upload http
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / modules / experimental / cache_cache.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "apr_general.h"
18
19 #include "mod_cache.h"
20 #include "cache_hash.h"
21 #include "cache_pqueue.h"
22 #include "cache_cache.h"
23
24 #if APR_HAVE_STDLIB_H
25 #include <stdlib.h>
26 #endif
27 #if APR_HAVE_STRING_H
28 #include <string.h>
29 #endif
30
31 struct cache_cache_t  {
32     int             max_entries;
33     apr_size_t      max_size;
34     apr_size_t      current_size;
35     int             total_purges;
36     long            queue_clock;
37     cache_hash_t   *ht;
38     cache_pqueue_t *pq;
39     cache_pqueue_set_priority set_pri;
40     cache_pqueue_get_priority get_pri;
41     cache_cache_inc_frequency *inc_entry;
42     cache_cache_get_size *size_entry;
43     cache_cache_get_key *key_entry;
44     cache_cache_free *free_entry;
45 };
46
47 CACHE_DECLARE(cache_cache_t *)cache_init(int max_entries,
48                                          apr_size_t max_size,
49                                          cache_pqueue_get_priority get_pri,
50                                          cache_pqueue_set_priority set_pri,
51                                          cache_pqueue_getpos get_pos,
52                                          cache_pqueue_setpos set_pos,
53                                          cache_cache_inc_frequency *inc_entry,
54                                          cache_cache_get_size *size_entry,
55                                          cache_cache_get_key* key_entry,
56                                          cache_cache_free *free_entry)
57 {
58     cache_cache_t *tmp;
59     tmp = malloc(sizeof(cache_cache_t));
60     tmp->max_entries = max_entries;
61     tmp->max_size = max_size;
62     tmp->current_size = 0;
63     tmp->total_purges = 0;
64     tmp->queue_clock = 0;
65     tmp->get_pri = get_pri;
66     tmp->set_pri = set_pri;
67     tmp->inc_entry = inc_entry;
68     tmp->size_entry = size_entry;
69     tmp->key_entry = key_entry;
70     tmp->free_entry = free_entry;
71
72     tmp->ht = cache_hash_make(max_entries);
73     tmp->pq = cache_pq_init(max_entries, get_pri, get_pos, set_pos);
74
75     return tmp;
76 }
77
78 CACHE_DECLARE(void) cache_free(cache_cache_t *c)
79 {
80     cache_pq_free(c->pq);
81     cache_hash_free(c->ht);
82     free(c);
83 }
84
85
86 CACHE_DECLARE(void*) cache_find(cache_cache_t* c, const char *key)
87 {
88     void *e;
89
90     e = cache_hash_get(c->ht, key, CACHE_HASH_KEY_STRING);
91     if (!e)
92         return NULL;
93
94     return e;
95 }
96
97 CACHE_DECLARE(void) cache_update(cache_cache_t* c, void *entry)
98 {
99     long old_priority;
100     long new_priority;
101
102     old_priority = c->set_pri(c->queue_clock, entry);
103     c->inc_entry(entry);
104     new_priority = c->set_pri(c->queue_clock, entry);
105     cache_pq_change_priority(c->pq, old_priority, new_priority, entry);
106 }
107
108 CACHE_DECLARE(void) cache_insert(cache_cache_t* c, void *entry)
109 {
110     void *ejected = NULL;
111     long priority;
112
113     c->set_pri(c->queue_clock, entry);
114     /* FIX: check if priority of bottom item is greater than inserted one */
115     while ((cache_pq_size(c->pq) >= c->max_entries) ||
116             ((c->current_size + c->size_entry(entry)) > c->max_size)) {
117
118         ejected = cache_pq_pop(c->pq);
119         /* FIX: If ejected is NULL, we'll segfault here */
120         priority = c->get_pri(ejected);
121
122         if (c->queue_clock > priority)
123             c->queue_clock = priority;
124
125         cache_hash_set(c->ht,
126                        c->key_entry(ejected),
127                        CACHE_HASH_KEY_STRING,
128                        NULL);
129
130         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, "Cache Purge of %s",c->key_entry(ejected));
131         c->current_size -= c->size_entry(ejected);
132         c->free_entry(ejected);
133         c->total_purges++;
134     }
135     c->current_size += c->size_entry(entry);
136
137     cache_pq_insert(c->pq, entry);
138     cache_hash_set(c->ht, c->key_entry(entry), CACHE_HASH_KEY_STRING, entry);
139 }
140
141 CACHE_DECLARE(void *) cache_pop(cache_cache_t *c)
142 {
143     void *entry;
144
145     if (!c)
146         return NULL;
147
148     entry = cache_pq_pop(c->pq);
149
150     if (!entry)
151         return NULL;
152
153     c->current_size -= c->size_entry(entry);
154     cache_hash_set(c->ht, c->key_entry(entry), CACHE_HASH_KEY_STRING, NULL);
155
156     return entry;
157 }
158
159 CACHE_DECLARE(apr_status_t) cache_remove(cache_cache_t *c, void *entry)
160 {
161     apr_size_t entry_size = c->size_entry(entry);
162     apr_status_t rc;
163     rc = cache_pq_remove(c->pq, entry);
164     if (rc != APR_SUCCESS)
165         return rc;
166
167     cache_hash_set(c->ht, c->key_entry(entry), CACHE_HASH_KEY_STRING, NULL);
168     c->current_size -= entry_size;
169
170     return APR_SUCCESS;
171 }