"Fossies" - the Fresh Open Source Software Archive

Member "links-1.03/cache.c" (19 Nov 2011, 9130 Bytes) of archive /linux/www/links-1.03.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "cache.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.8_vs_1.03.

    1 #include "links.h"
    2 
    3 struct list_head cache = {&cache, &cache};
    4 
    5 long cache_size;
    6 
    7 int cache_count = 0;
    8 
    9 long cache_info(int type)
   10 {
   11     int i = 0;
   12     struct cache_entry *ce;
   13     switch (type) {
   14         case CI_BYTES:
   15             return cache_size;
   16         case CI_FILES:
   17             foreach(ce, cache) i++;
   18             return i;
   19         case CI_LOCKED:
   20             foreach(ce, cache) i += !!ce->refcount;
   21             return i;
   22         case CI_LOADING:
   23             foreach(ce, cache) i += is_entry_used(ce);
   24             return i;
   25         case CI_LIST:
   26             return (long) &cache;
   27         default:
   28             internal("cache_info: bad request");
   29     }
   30     return 0;
   31 }
   32 
   33 unsigned char *extract_proxy(unsigned char *url)
   34 {
   35     char *a;
   36     if (strlen(url) < 8 || casecmp(url, "proxy://", 8)) return url;
   37     if (!(a = strchr(url + 8, '/'))) return url;
   38     return a + 1;
   39 }
   40 
   41 int find_in_cache(unsigned char *url, struct cache_entry **f)
   42 {
   43     struct cache_entry *e;
   44     url = extract_proxy(url);
   45     foreach(e, cache) if (!strcmp(e->url, url)) {
   46         e->refcount++;
   47         del_from_list(e);
   48         add_to_list(cache, e);
   49         *f = e;
   50         return 0;
   51     }
   52     return -1;
   53 }
   54 
   55 int get_cache_entry(unsigned char *url, struct cache_entry **f)
   56 {
   57     struct cache_entry *e;
   58     if (!find_in_cache(url, f)) return 0;
   59     shrink_memory(0);
   60     url = extract_proxy(url);
   61     e = mem_alloc(sizeof(struct cache_entry));
   62     memset(e, 0, sizeof(struct cache_entry));
   63     e->url = mem_alloc(strlen(url) + 1);
   64     strcpy(e->url, url);
   65     e->length = 0;
   66     e->incomplete = 1;
   67     e->data_size = 0;
   68     init_list(e->frag);
   69     e->count = cache_count++;
   70     e->refcount = 1;
   71     add_to_list(cache, e);
   72     *f = e;
   73     return 0;
   74 }
   75 
   76 #define sf(x) e->data_size += (x), cache_size += (x)
   77 
   78 int page_size = 4096;
   79 
   80 #define C_ALIGN(x) ((((x) + sizeof(struct fragment) + 64) | (page_size - 1)) - sizeof(struct fragment) - 64)
   81 
   82 int add_fragment(struct cache_entry *e, off_t offset, unsigned char *data, off_t length)
   83 {
   84     struct fragment *f;
   85     struct fragment *nf;
   86     int a = 0;
   87     int trunc = 0;
   88     volatile off_t ca;
   89     if (!length) return 0;
   90     e->incomplete = 1;
   91     if (offset + length < 0 || offset + length < offset) overalloc();
   92     if (offset + (off_t)C_ALIGN(length) < 0 || offset + (off_t)C_ALIGN(length) < offset) overalloc();
   93     if (e->length < offset + length) e->length = offset + length;
   94     e->count = cache_count++;
   95     foreach(f, e->frag) {
   96         if (f->offset > offset) break;
   97         if (f->offset <= offset && f->offset+f->length >= offset) {
   98             if (offset+length > f->offset+f->length) {
   99                 if (memcmp(f->data+offset-f->offset, data, f->offset+f->length-offset)) trunc = 1;
  100                 a = 1; /* !!! FIXME */
  101                 if (offset-f->offset+length <= f->real_length) {
  102                     sf((offset+length) - (f->offset+f->length));
  103                     f->length = offset-f->offset+length;
  104                 }
  105                 else {
  106                     sf(-(f->offset+f->length-offset));
  107                     f->length = offset-f->offset;
  108                     f = f->next;
  109                     break;
  110                 }
  111             } else {
  112                 if (memcmp(f->data+offset-f->offset, data, length)) trunc = 1;
  113             }
  114             memcpy(f->data+offset-f->offset, data, length);
  115             goto ch_o;
  116         }
  117     }
  118 /* Intel C 9 has a bug and miscompiles this statement (< 0 test is true) */
  119     /*if (C_ALIGN(length) > MAXINT - sizeof(struct fragment) || C_ALIGN(length) < 0) overalloc();*/
  120     ca = C_ALIGN(length);
  121     if (ca > MAXINT - (int)sizeof(struct fragment) || ca < 0) overalloc();
  122     nf = mem_alloc(sizeof(struct fragment) + ca);
  123     a = 1;
  124     sf(length);
  125     nf->offset = offset;
  126     nf->length = length;
  127     nf->real_length = C_ALIGN(length);
  128     memcpy(nf->data, data, length);
  129     add_at_pos(f->prev, nf);
  130     f = nf;
  131     ch_o:
  132     while ((void *)f->next != &e->frag && f->offset+f->length > f->next->offset) {
  133         if (f->offset+f->length < f->next->offset+f->next->length) {
  134             nf = mem_realloc(f, sizeof(struct fragment)+f->next->offset-f->offset+f->next->length);
  135             nf->prev->next = nf;
  136             nf->next->prev = nf;
  137             f = nf;
  138             if (memcmp(f->data+f->next->offset-f->offset, f->next->data, f->offset+f->length-f->next->offset)) trunc = 1;
  139             memcpy(f->data+f->length, f->next->data+f->offset+f->length-f->next->offset, f->next->offset+f->next->length-f->offset-f->length);
  140             sf(f->next->offset+f->next->length-f->offset-f->length);
  141             f->length = f->real_length = f->next->offset+f->next->length-f->offset;
  142         } else {
  143             if (memcmp(f->data+f->next->offset-f->offset, f->next->data, f->next->length)) trunc = 1;
  144         }
  145         nf = f->next;
  146         del_from_list(nf);
  147         sf(-nf->length);
  148         mem_free(nf);
  149     }
  150     if (trunc) truncate_entry(e, offset + length, 0);
  151     /*{
  152         foreach(f, e->frag) fprintf(stderr, "%d, %d, %d\n", f->offset, f->length, f->real_length);
  153         debug("a-");
  154     }*/
  155     return a;
  156 }
  157 
  158 void defrag_entry(struct cache_entry *e)
  159 {
  160     struct fragment *f, *g, *h, *n, *x;
  161     off_t l;
  162     if (list_empty(e->frag)) return;
  163     f = e->frag.next;
  164     if (f->offset) return;
  165     for (g = f->next; g != (void *)&e->frag && g->offset <= g->prev->offset+g->prev->length; g = g->next) if (g->offset < g->prev->offset+g->prev->length) {
  166         internal("fragments overlay");
  167         return;
  168     }
  169     if (g == f->next && f->length == f->real_length) return;
  170     for (l = 0, h = f; h != g; h = h->next) l += h->length;
  171     if (l > MAXINT - (int)sizeof(struct fragment) || l < 0) overalloc();
  172     n = mem_alloc(sizeof(struct fragment) + l);
  173     n->offset = 0;
  174     n->length = l;
  175     n->real_length = l;
  176     /*{
  177         struct fragment *f;
  178         foreach(f, e->frag) fprintf(stderr, "%d, %d, %d\n", f->offset, f->length, f->real_length);
  179         debug("d1-");
  180     }*/
  181     for (l = 0, h = f; h != g; h = h->next) {
  182         memcpy(n->data + l, h->data, h->length);
  183         l += h->length;
  184         x = h;
  185         h = h->prev;
  186         del_from_list(x);
  187         mem_free(x);
  188     }
  189     add_to_list(e->frag, n);
  190     /*{
  191         foreach(f, e->frag) fprintf(stderr, "%d, %d, %d\n", f->offset, f->length, f->real_length);
  192         debug("d-");
  193     }*/
  194 }
  195 
  196 void truncate_entry(struct cache_entry *e, off_t off, int final)
  197 {
  198     int modified = 0;
  199     struct fragment *f, *g;
  200     if (e->length > off) e->length = off, e->incomplete = 1;
  201     foreach(f, e->frag) {
  202         if (f->offset >= off) {
  203             del:
  204             while ((void *)f != &e->frag) {
  205                 modified = 1;
  206                 sf(-f->length);
  207                 g = f->next;
  208                 del_from_list(f);
  209                 mem_free(f);
  210                 f = g;
  211             }
  212             goto ret;
  213         }
  214         if (f->offset + f->length > off) {
  215             modified = 1;
  216             sf(-(f->offset + f->length - off));
  217             f->length = off - f->offset;
  218             if (final) {
  219                 g = mem_realloc(f, sizeof(struct fragment) + f->length);
  220                 g->next->prev = g;
  221                 g->prev->next = g;
  222                 f = g;
  223                 f->real_length = f->length;
  224             }
  225             f = f->next;
  226             goto del;
  227         }
  228     }
  229     ret:
  230     if (modified) {
  231         e->count = cache_count++;
  232     }
  233 }
  234 
  235 void free_entry_to(struct cache_entry *e, off_t off)
  236 {
  237     struct fragment *f, *g;
  238     e->incomplete = 1;
  239     foreach(f, e->frag) {
  240         if (f->offset + f->length <= off) {
  241             sf(-f->length);
  242             g = f;
  243             f = f->prev;
  244             del_from_list(g);
  245             mem_free(g);
  246         } else if (f->offset < off) {
  247             sf(f->offset - off);
  248             memmove(f->data, f->data + (off - f->offset), f->length -= off - f->offset);
  249             f->offset = off;
  250         } else break;
  251     }
  252 }
  253 
  254 void delete_entry_content(struct cache_entry *e)
  255 {
  256     e->count = cache_count++;
  257     free_list(e->frag);
  258     e->length = 0;
  259     e->incomplete = 1;
  260     if ((cache_size -= e->data_size) < 0) {
  261         internal("cache_size underflow: %ld", cache_size);
  262         cache_size = 0;
  263     }
  264     e->data_size = 0;
  265     if (e->last_modified) {
  266         mem_free(e->last_modified);
  267         e->last_modified = NULL;
  268     }
  269 }
  270 
  271 void delete_cache_entry(struct cache_entry *e)
  272 {
  273     if (e->refcount) internal("deleteing locked cache entry");
  274 #ifdef DEBUG
  275     if (is_entry_used(e)) internal("deleting loading cache entry");
  276 #endif
  277     delete_entry_content(e);
  278     del_from_list(e);
  279     mem_free(e->url);
  280     if (e->head) mem_free(e->head);
  281     if (e->last_modified) mem_free(e->last_modified);
  282     if (e->redirect) mem_free(e->redirect);
  283 #ifdef HAVE_SSL
  284     if (e->ssl_info) mem_free(e->ssl_info);
  285 #endif
  286     mem_free(e);
  287 }
  288 
  289 void garbage_collection(int u)
  290 {
  291     struct cache_entry *e, *f;
  292     long ncs = cache_size;
  293     long ccs = 0;
  294     if (!u && cache_size <= memory_cache_size) return;
  295     foreach(e, cache) {
  296         if (e->refcount || is_entry_used(e)) if ((ncs -= e->data_size) < 0) {
  297             internal("cache_size underflow: %ld", ncs);
  298             ncs = 0;
  299         }
  300         ccs += e->data_size;
  301     }
  302     if (ccs != cache_size) internal("cache size badly computed: %ld != %ld", cache_size, ccs), cache_size = ccs;
  303     if (!u && ncs <= memory_cache_size) return;
  304     for (e = cache.prev; (void *)e != &cache; e = e->prev) {
  305         if (!u && ncs <= (longlong)memory_cache_size * MEMORY_CACHE_GC_PERCENT) goto g;
  306         if (e->refcount || is_entry_used(e)) {
  307             e->tgc = 0;
  308             continue;
  309         }
  310         e->tgc = 1;
  311         if ((ncs -= e->data_size) < 0) {
  312             internal("cache_size underflow: %ld", ncs);
  313             ncs = 0;
  314         }
  315     }
  316     if (/*!no &&*/ ncs) internal("cache_size(%ld) is larger than size of all objects(%ld)", cache_size, cache_size - ncs);
  317     g:
  318     if ((void *)(e = e->next) == &cache) return;
  319     if (!u) for (f = e; (void *)f != &cache; f = f->next) {
  320         if (ncs + f->data_size <= (longlong)memory_cache_size * MEMORY_CACHE_GC_PERCENT) {
  321             ncs += f->data_size;
  322             f->tgc = 0;
  323         }
  324     }
  325     for (f = e; (void *)f != &cache;) {
  326         f = f->next;
  327         if (f->prev->tgc) delete_cache_entry(f->prev);
  328     }
  329     /*if (!no && cache_size > (longlong)memory_cache_size * MEMORY_CACHE_GC_PERCENT) {
  330         internal("garbage collection doesn't work, cache size %ld", cache_size);
  331     }*/
  332 }
  333 
  334 void init_cache(void)
  335 {
  336 #ifdef HAVE_GETPAGESIZE
  337     int getpg = getpagesize();
  338     if (getpg > 0 && getpg < 0x10000 && !(getpg & (getpg - 1))) page_size = getpg;
  339 #endif
  340 }
  341