8 uint64 cache_motion
= 0;
18 100 <= size <= 1000000000.
19 4 <= hsize <= size/16.
20 hsize is a power of 2.
22 hsize <= writer <= oldest <= unused <= size.
23 If oldest == unused then unused == size.
25 x is a hash table with the following structure:
26 x[0...hsize-1]: hsize/4 head links.
27 x[hsize...writer-1]: consecutive entries, newest entry on the right.
28 x[writer...oldest-1]: free space for new entries.
29 x[oldest...unused-1]: consecutive entries, oldest entry on the left.
30 x[unused...size-1]: unused.
32 Each hash bucket is a linked list containing the following items:
33 the head link, the newest entry, the second-newest entry, etc.
34 Each link is a 4-byte number giving the xor of
35 the positions of the adjacent items in the list.
37 Entries are always inserted immediately after the head and removed at the tail.
39 Each entry contains the following information:
40 4-byte link; 4-byte keylen; 4-byte datalen; 8-byte expire time; key; data.
43 #define MAXKEYLEN 1000
44 #define MAXDATALEN 1000000
46 static void cache_impossible(void)
51 static void set4(uint32 pos
,uint32 u
)
53 if (pos
> size
- 4) cache_impossible();
54 uint32_pack(x
+ pos
,u
);
57 static uint32
get4(uint32 pos
)
60 if (pos
> size
- 4) cache_impossible();
61 uint32_unpack(x
+ pos
,&result
);
65 static unsigned int hash(const char *key
,unsigned int keylen
)
67 unsigned int result
= 5381;
70 result
= (result
<< 5) + result
;
71 result
^= (unsigned char) *key
;
80 char *cache_get(const char *key
,unsigned int keylen
,unsigned int *datalen
,uint32
*ttl
)
92 if (keylen
> MAXKEYLEN
) return 0;
94 prevpos
= hash(key
,keylen
);
99 if (get4(pos
+ 4) == keylen
) {
100 if (pos
+ 20 + keylen
> size
) cache_impossible();
101 if (byte_equal(key
,keylen
,x
+ pos
+ 20)) {
102 tai_unpack(x
+ pos
+ 12,&expire
);
104 if (tai_less(&expire
,&now
)) return 0;
106 tai_sub(&expire
,&expire
,&now
);
107 d
= tai_approx(&expire
);
108 if (d
> 604800) d
= 604800;
112 if (u
> size
- pos
- 20 - keylen
) cache_impossible();
115 return x
+ pos
+ 20 + keylen
;
118 nextpos
= prevpos
^ get4(pos
);
121 if (++loop
> 100) return 0; /* to protect against hash flooding */
127 void cache_set(const char *key
,unsigned int keylen
,const char *data
,unsigned int datalen
,uint32 ttl
)
131 unsigned int entrylen
;
132 unsigned int keyhash
;
136 if (keylen
> MAXKEYLEN
) return;
137 if (datalen
> MAXDATALEN
) return;
140 if (ttl
> 604800) ttl
= 604800;
142 entrylen
= keylen
+ datalen
+ 20;
144 while (writer
+ entrylen
> oldest
) {
145 if (oldest
== unused
) {
146 if (writer
<= hsize
) return;
153 set4(pos
,get4(pos
) ^ oldest
);
155 oldest
+= get4(oldest
+ 4) + get4(oldest
+ 8) + 20;
156 if (oldest
> unused
) cache_impossible();
157 if (oldest
== unused
) {
163 keyhash
= hash(key
,keylen
);
166 tai_uint(&expire
,ttl
);
167 tai_add(&expire
,&expire
,&now
);
171 set4(pos
,get4(pos
) ^ keyhash
^ writer
);
172 set4(writer
,pos
^ keyhash
);
173 set4(writer
+ 4,keylen
);
174 set4(writer
+ 8,datalen
);
175 tai_pack(x
+ writer
+ 12,&expire
);
176 byte_copy(x
+ writer
+ 20,keylen
,key
);
177 byte_copy(x
+ writer
+ 20 + keylen
,datalen
,data
);
179 set4(keyhash
,writer
);
181 cache_motion
+= entrylen
;
184 int cache_init(unsigned int cachesize
)
191 if (cachesize
> 1000000000) cachesize
= 1000000000;
192 if (cachesize
< 100) cachesize
= 100;
196 while (hsize
<= (size
>> 5)) hsize
<<= 1;