/******************************************************************************/ /* XrdFfsDent.cc help functions to merge direntries */ /* */ /* (c) 2010 by the Board of Trustees of the Leland Stanford, Jr., University */ /* All Rights Reserved */ /* Author: Wei Yang (SLAC National Accelerator Laboratory, 2009) */ /* Contract DE-AC02-76-SFO0515 with the Department of Energy */ /* */ /* This file is part of the XRootD software suite. */ /* */ /* XRootD is free software: you can redistribute it and/or modify it under */ /* the terms of the GNU Lesser General Public License as published by the */ /* Free Software Foundation, either version 3 of the License, or (at your */ /* option) any later version. */ /* */ /* XRootD is distributed in the hope that it will be useful, but WITHOUT */ /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */ /* License for more details. */ /* */ /* You should have received a copy of the GNU Lesser General Public License */ /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */ /* COPYING (GPL license). If not, see . */ /* */ /* The copyright holder's institutional names and contributor's names may not */ /* be used to endorse or promote products derived from this software without */ /* specific prior written permission of the institution or contributor. */ /******************************************************************************/ #include "XrdFfs/XrdFfsDent.hh" #ifdef __cplusplus extern "C" { #endif /* to be used by quick sort */ int XrdFfsDent_cstr_cmp(const void *a, const void *b) { const char **aa = (const char **)a; const char **bb = (const char **)b; return strcmp(*aa, *bb); } /* _del() frees the head node of *p */ void XrdFfsDent_names_del(struct XrdFfsDentnames **p) { (*p)->name = NULL; (*p)->next = NULL; free(*p); } void XrdFfsDent_names_add(struct XrdFfsDentnames **p, char *name) { struct XrdFfsDentnames *n = (struct XrdFfsDentnames*)malloc(sizeof(struct XrdFfsDentnames)); n->name = strdup(name); n->next = *p; *p = n; return; } /* _join() joins *n to *p. Note *p or *n may equal to NULL. In that case, old *p is remove and *p will equal to *n in the end. Giving list A, B, C and one want to join in the order of A->B->C (so that A points to the joined final list), there are two ways to to this: 1. _join(&A, &B); _join(&A, &C) (not efficient) 2. _join(&B, &C); _join(&A, &B) (efficient) */ void XrdFfsDent_names_join(struct XrdFfsDentnames **p, struct XrdFfsDentnames **n) { struct XrdFfsDentnames *t, *l = 0; if ( *p != NULL ) { t = *p; while ( t != NULL ) { l = t; t = t->next; } l->next = *n; } else *p = *n; } /* _extract() returns (to dnarray) a char array with all (*p)->name sorted accroding to strcmp(), and destroy *p. */ int XrdFfsDent_names_extract(struct XrdFfsDentnames **p, char ***dnarray) { struct XrdFfsDentnames *x, *y; int i = 0; y = *p; while (y != NULL) { i++; y = y->next; } /* be careful, old dnarray is lost */ *dnarray = (char**) malloc(sizeof(char*) * i); x = *p; y = *p; i = 0; while (y != NULL) { (*dnarray)[i++] = y->name; y = y->next; XrdFfsDent_names_del(&x); x = y; } qsort((*dnarray), i, sizeof(char*), XrdFfsDent_cstr_cmp); *p = NULL; return i; } /* managing caches for dentnames */ struct XrdFfsDentcache { time_t t0; time_t life; unsigned int nents; char *dirname; char **dnarray; }; void XrdFfsDent_dentcache_fill(struct XrdFfsDentcache *cache, char *dname, char ***dnarray, int nents) { int i; cache->dirname = strdup(dname); cache->nents = nents; cache->t0 = time(NULL); cache->life = nents / 10 ; cache->dnarray = (char**) malloc(sizeof(char*) * nents); for (i = 0; i < nents; i++) cache->dnarray[i] = strdup((*dnarray)[i]); } void XrdFfsDent_dentcache_free(struct XrdFfsDentcache *cache) { int i; for (i = 0; i < (int)cache->nents; i++) { free(cache->dnarray[i]); } cache->nents = 0; free(cache->dnarray); free(cache->dirname); cache->dnarray = NULL; cache->dirname = NULL; } /* expired cache may still be useful. invalid cache should not be used */ int XrdFfsDent_dentcache_expired(struct XrdFfsDentcache *cache) { time_t t1; t1 = time(NULL); return (((t1 - cache->t0) < cache->life)? 0 : 1); } int XrdFfsDent_dentcache_invalid(struct XrdFfsDentcache *cache) { time_t t1; t1 = time(NULL); return (((t1 - cache->t0) < 28700)? 0 : 1); // after 8 hours (28800 sec), the redirector no longer remembers } int XrdFfsDent_dentcache_search(struct XrdFfsDentcache *cache, char *dname, char *dentname) { char path[1024]; strcpy(path, dname); if (dentname != NULL && path[strlen(path) -1] != '/') strcat(path,"/"); if (dentname != NULL) strcat(path, dentname); if (XrdFfsDent_dentcache_invalid(cache)) return 0; else if (strlen(cache->dirname) == strlen(path) && strcmp(cache->dirname, path) == 0) return 1; else if (strlen(cache->dirname) != strlen(dname) || strcmp(cache->dirname, dname) != 0) return 0; else if (bsearch(&dentname, cache->dnarray, cache->nents, sizeof(char*), XrdFfsDent_cstr_cmp) != NULL) return 1; else return 0; } #define XrdFfsDent_NDENTCACHES 20 struct XrdFfsDentcache XrdFfsDentCaches[XrdFfsDent_NDENTCACHES]; pthread_mutex_t XrdFfsDentCaches_mutex = PTHREAD_MUTEX_INITIALIZER; void XrdFfsDent_cache_init() { int i; for (i = 0; i < XrdFfsDent_NDENTCACHES; i++) { XrdFfsDentCaches[i].t0 = 0; XrdFfsDentCaches[i].nents = 0; XrdFfsDentCaches[i].dirname = strdup(""); XrdFfsDentCaches[i].dnarray = NULL; } } int XrdFfsDent_cache_fill(char *dname, char ***dnarray, int nents) { int i; pthread_mutex_lock(&XrdFfsDentCaches_mutex); for (i = 0; i < XrdFfsDent_NDENTCACHES; i++) { if (XrdFfsDent_dentcache_search(&XrdFfsDentCaches[i], dname, NULL) != 0) { XrdFfsDent_dentcache_free(&XrdFfsDentCaches[i]); XrdFfsDent_dentcache_fill(&XrdFfsDentCaches[i], dname, dnarray, nents); pthread_mutex_unlock(&XrdFfsDentCaches_mutex); return 1; } } for (i = 0; i < XrdFfsDent_NDENTCACHES; i++) { if (XrdFfsDent_dentcache_expired(&XrdFfsDentCaches[i]) || XrdFfsDent_dentcache_invalid(&XrdFfsDentCaches[i])) { XrdFfsDent_dentcache_free(&XrdFfsDentCaches[i]); XrdFfsDent_dentcache_fill(&XrdFfsDentCaches[i], dname, dnarray, nents); pthread_mutex_unlock(&XrdFfsDentCaches_mutex); return 1; } } pthread_mutex_unlock(&XrdFfsDentCaches_mutex); return 0; } int XrdFfsDent_cache_search(char *dname, char *dentname) { int i, rval = 0; pthread_mutex_lock(&XrdFfsDentCaches_mutex); for (i = 0; i < XrdFfsDent_NDENTCACHES; i++) if (XrdFfsDent_dentcache_search(&XrdFfsDentCaches[i], dname, dentname) == 1) { rval = 1; break; } pthread_mutex_unlock(&XrdFfsDentCaches_mutex); return rval; } void XrdFfsDent_cache_destroy() { int i; for (i = 0; i < XrdFfsDent_NDENTCACHES; i++) XrdFfsDent_dentcache_free(&XrdFfsDentCaches[i]); } /* #include main() { struct XrdFfsDentnames *x = NULL; struct XrdFfsDentnames *y = NULL; struct XrdFfsDentnames *z = NULL; int totdentnames; int i = 0; char **dnarray; XrdFfsDent_names_add(&x, "aaa"); XrdFfsDent_names_add(&x, "bbb"); XrdFfsDent_names_add(&x, "ccc"); XrdFfsDent_names_add(&y, "aaa"); XrdFfsDent_names_add(&y, "aa"); XrdFfsDent_names_add(&y, "bb"); XrdFfsDent_names_add(&z, "xxx"); XrdFfsDent_names_join(&z, &y); XrdFfsDent_names_join(&x, &z); totdentnames = XrdFfsDent_names_extract(&x, &dnarray); char *last, *name; for (i=0; i