sdbm_pair.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. /* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
  2. * applicable.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * 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. * sdbm - ndbm work-alike hashed database library
  18. * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
  19. * author: oz@nexus.yorku.ca
  20. * status: ex-public domain.
  21. *
  22. * page-level routines
  23. */
  24. #include "apr_sdbm.h"
  25. #include "sdbm_tune.h"
  26. #include "sdbm_pair.h"
  27. #include "sdbm_private.h"
  28. #include <string.h> /* for memset() */
  29. #define exhash(item) sdbm_hash((item).dptr, (item).dsize)
  30. /*
  31. * forward
  32. */
  33. static int seepair(char *, int, char *, int);
  34. /*
  35. * page format:
  36. * +------------------------------+
  37. * ino | n | keyoff | datoff | keyoff |
  38. * +------------+--------+--------+
  39. * | datoff | - - - ----> |
  40. * +--------+---------------------+
  41. * | F R E E A R E A |
  42. * +--------------+---------------+
  43. * | <---- - - - | data |
  44. * +--------+-----+----+----------+
  45. * | key | data | key |
  46. * +--------+----------+----------+
  47. *
  48. * calculating the offsets for free area: if the number
  49. * of entries (ino[0]) is zero, the offset to the END of
  50. * the free area is the block size. Otherwise, it is the
  51. * nth (ino[ino[0]]) entry's offset.
  52. */
  53. int
  54. fitpair(pag, need)
  55. char *pag;
  56. int need;
  57. {
  58. register int n;
  59. register int off;
  60. register int avail;
  61. register short *ino = (short *) pag;
  62. off = ((n = ino[0]) > 0) ? ino[n] : PBLKSIZ;
  63. avail = off - (n + 1) * sizeof(short);
  64. need += 2 * sizeof(short);
  65. debug(("avail %d need %d\n", avail, need));
  66. return need <= avail;
  67. }
  68. void
  69. putpair(pag, key, val)
  70. char *pag;
  71. apr_sdbm_datum_t key;
  72. apr_sdbm_datum_t val;
  73. {
  74. register int n;
  75. register int off;
  76. register short *ino = (short *) pag;
  77. off = ((n = ino[0]) > 0) ? ino[n] : PBLKSIZ;
  78. /*
  79. * enter the key first
  80. */
  81. off -= key.dsize;
  82. (void) memcpy(pag + off, key.dptr, key.dsize);
  83. ino[n + 1] = off;
  84. /*
  85. * now the data
  86. */
  87. off -= val.dsize;
  88. (void) memcpy(pag + off, val.dptr, val.dsize);
  89. ino[n + 2] = off;
  90. /*
  91. * adjust item count
  92. */
  93. ino[0] += 2;
  94. }
  95. apr_sdbm_datum_t
  96. getpair(pag, key)
  97. char *pag;
  98. apr_sdbm_datum_t key;
  99. {
  100. register int i;
  101. register int n;
  102. apr_sdbm_datum_t val;
  103. register short *ino = (short *) pag;
  104. if ((n = ino[0]) == 0)
  105. return sdbm_nullitem;
  106. if ((i = seepair(pag, n, key.dptr, key.dsize)) == 0)
  107. return sdbm_nullitem;
  108. val.dptr = pag + ino[i + 1];
  109. val.dsize = ino[i] - ino[i + 1];
  110. return val;
  111. }
  112. int
  113. duppair(pag, key)
  114. char *pag;
  115. apr_sdbm_datum_t key;
  116. {
  117. register short *ino = (short *) pag;
  118. return ino[0] > 0 && seepair(pag, ino[0], key.dptr, key.dsize) > 0;
  119. }
  120. apr_sdbm_datum_t
  121. getnkey(pag, num)
  122. char *pag;
  123. int num;
  124. {
  125. apr_sdbm_datum_t key;
  126. register int off;
  127. register short *ino = (short *) pag;
  128. num = num * 2 - 1;
  129. if (ino[0] == 0 || num > ino[0])
  130. return sdbm_nullitem;
  131. off = (num > 1) ? ino[num - 1] : PBLKSIZ;
  132. key.dptr = pag + ino[num];
  133. key.dsize = off - ino[num];
  134. return key;
  135. }
  136. int
  137. delpair(pag, key)
  138. char *pag;
  139. apr_sdbm_datum_t key;
  140. {
  141. register int n;
  142. register int i;
  143. register short *ino = (short *) pag;
  144. if ((n = ino[0]) == 0)
  145. return 0;
  146. if ((i = seepair(pag, n, key.dptr, key.dsize)) == 0)
  147. return 0;
  148. /*
  149. * found the key. if it is the last entry
  150. * [i.e. i == n - 1] we just adjust the entry count.
  151. * hard case: move all data down onto the deleted pair,
  152. * shift offsets onto deleted offsets, and adjust them.
  153. * [note: 0 < i < n]
  154. */
  155. if (i < n - 1) {
  156. register int m;
  157. register char *dst = pag + (i == 1 ? PBLKSIZ : ino[i - 1]);
  158. register char *src = pag + ino[i + 1];
  159. register int zoo = dst - src;
  160. debug(("free-up %d ", zoo));
  161. /*
  162. * shift data/keys down
  163. */
  164. m = ino[i + 1] - ino[n];
  165. #undef DUFF /* just use memmove. it should be plenty fast. */
  166. #ifdef DUFF
  167. #define MOVB *--dst = *--src
  168. if (m > 0) {
  169. register int loop = (m + 8 - 1) >> 3;
  170. switch (m & (8 - 1)) {
  171. case 0: do {
  172. MOVB; case 7: MOVB;
  173. case 6: MOVB; case 5: MOVB;
  174. case 4: MOVB; case 3: MOVB;
  175. case 2: MOVB; case 1: MOVB;
  176. } while (--loop);
  177. }
  178. }
  179. #else
  180. dst -= m;
  181. src -= m;
  182. memmove(dst, src, m);
  183. #endif
  184. /*
  185. * adjust offset index up
  186. */
  187. while (i < n - 1) {
  188. ino[i] = ino[i + 2] + zoo;
  189. i++;
  190. }
  191. }
  192. ino[0] -= 2;
  193. return 1;
  194. }
  195. /*
  196. * search for the key in the page.
  197. * return offset index in the range 0 < i < n.
  198. * return 0 if not found.
  199. */
  200. static int
  201. seepair(pag, n, key, siz)
  202. char *pag;
  203. register int n;
  204. register char *key;
  205. register int siz;
  206. {
  207. register int i;
  208. register int off = PBLKSIZ;
  209. register short *ino = (short *) pag;
  210. for (i = 1; i < n; i += 2) {
  211. if (siz == off - ino[i] &&
  212. memcmp(key, pag + ino[i], siz) == 0)
  213. return i;
  214. off = ino[i + 1];
  215. }
  216. return 0;
  217. }
  218. void
  219. splpage(pag, new, sbit)
  220. char *pag;
  221. char *new;
  222. long sbit;
  223. {
  224. apr_sdbm_datum_t key;
  225. apr_sdbm_datum_t val;
  226. register int n;
  227. register int off = PBLKSIZ;
  228. char cur[PBLKSIZ];
  229. register short *ino = (short *) cur;
  230. (void) memcpy(cur, pag, PBLKSIZ);
  231. (void) memset(pag, 0, PBLKSIZ);
  232. (void) memset(new, 0, PBLKSIZ);
  233. n = ino[0];
  234. for (ino++; n > 0; ino += 2) {
  235. key.dptr = cur + ino[0];
  236. key.dsize = off - ino[0];
  237. val.dptr = cur + ino[1];
  238. val.dsize = ino[0] - ino[1];
  239. /*
  240. * select the page pointer (by looking at sbit) and insert
  241. */
  242. (void) putpair((exhash(key) & sbit) ? new : pag, key, val);
  243. off = ino[1];
  244. n -= 2;
  245. }
  246. debug(("%d split %d/%d\n", ((short *) cur)[0] / 2,
  247. ((short *) new)[0] / 2,
  248. ((short *) pag)[0] / 2));
  249. }
  250. /*
  251. * check page sanity:
  252. * number of entries should be something
  253. * reasonable, and all offsets in the index should be in order.
  254. * this could be made more rigorous.
  255. */
  256. int
  257. chkpage(pag)
  258. char *pag;
  259. {
  260. register int n;
  261. register int off;
  262. register short *ino = (short *) pag;
  263. if ((n = ino[0]) < 0 || n > PBLKSIZ / sizeof(short))
  264. return 0;
  265. if (n > 0) {
  266. off = PBLKSIZ;
  267. for (ino++; n > 0; ino += 2) {
  268. if (ino[0] > off || ino[1] > off ||
  269. ino[1] > ino[0])
  270. return 0;
  271. off = ino[1];
  272. n -= 2;
  273. }
  274. }
  275. return 1;
  276. }