ruby_odeum 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. data/COPYING +504 -0
  2. data/LICENSE +504 -0
  3. data/README +50 -0
  4. data/bin/odeum_mgr +106 -0
  5. data/doc/rdoc/classes/Odeum.html +235 -0
  6. data/doc/rdoc/classes/Odeum.src/M000010.html +25 -0
  7. data/doc/rdoc/classes/Odeum.src/M000011.html +22 -0
  8. data/doc/rdoc/classes/Odeum.src/M000012.html +27 -0
  9. data/doc/rdoc/classes/Odeum.src/M000013.html +27 -0
  10. data/doc/rdoc/classes/Odeum.src/M000014.html +28 -0
  11. data/doc/rdoc/classes/Odeum/Document.html +382 -0
  12. data/doc/rdoc/classes/Odeum/Document.src/M000040.html +25 -0
  13. data/doc/rdoc/classes/Odeum/Document.src/M000041.html +22 -0
  14. data/doc/rdoc/classes/Odeum/Document.src/M000042.html +23 -0
  15. data/doc/rdoc/classes/Odeum/Document.src/M000043.html +23 -0
  16. data/doc/rdoc/classes/Odeum/Document.src/M000044.html +24 -0
  17. data/doc/rdoc/classes/Odeum/Document.src/M000045.html +32 -0
  18. data/doc/rdoc/classes/Odeum/Document.src/M000046.html +22 -0
  19. data/doc/rdoc/classes/Odeum/Document.src/M000047.html +22 -0
  20. data/doc/rdoc/classes/Odeum/Document.src/M000048.html +22 -0
  21. data/doc/rdoc/classes/Odeum/Document.src/M000049.html +22 -0
  22. data/doc/rdoc/classes/Odeum/Document.src/M000050.html +24 -0
  23. data/doc/rdoc/classes/Odeum/Document.src/M000051.html +27 -0
  24. data/doc/rdoc/classes/Odeum/Index.html +662 -0
  25. data/doc/rdoc/classes/Odeum/Index.src/M000015.html +46 -0
  26. data/doc/rdoc/classes/Odeum/Index.src/M000016.html +33 -0
  27. data/doc/rdoc/classes/Odeum/Index.src/M000017.html +35 -0
  28. data/doc/rdoc/classes/Odeum/Index.src/M000018.html +23 -0
  29. data/doc/rdoc/classes/Odeum/Index.src/M000019.html +22 -0
  30. data/doc/rdoc/classes/Odeum/Index.src/M000020.html +22 -0
  31. data/doc/rdoc/classes/Odeum/Index.src/M000021.html +22 -0
  32. data/doc/rdoc/classes/Odeum/Index.src/M000022.html +22 -0
  33. data/doc/rdoc/classes/Odeum/Index.src/M000023.html +22 -0
  34. data/doc/rdoc/classes/Odeum/Index.src/M000024.html +29 -0
  35. data/doc/rdoc/classes/Odeum/Index.src/M000025.html +23 -0
  36. data/doc/rdoc/classes/Odeum/Index.src/M000026.html +24 -0
  37. data/doc/rdoc/classes/Odeum/Index.src/M000027.html +23 -0
  38. data/doc/rdoc/classes/Odeum/Index.src/M000028.html +26 -0
  39. data/doc/rdoc/classes/Odeum/Index.src/M000029.html +24 -0
  40. data/doc/rdoc/classes/Odeum/Index.src/M000030.html +20 -0
  41. data/doc/rdoc/classes/Odeum/Index.src/M000031.html +22 -0
  42. data/doc/rdoc/classes/Odeum/Index.src/M000032.html +22 -0
  43. data/doc/rdoc/classes/Odeum/Index.src/M000033.html +22 -0
  44. data/doc/rdoc/classes/Odeum/Index.src/M000034.html +22 -0
  45. data/doc/rdoc/classes/Odeum/Index.src/M000035.html +20 -0
  46. data/doc/rdoc/classes/Odeum/Index.src/M000036.html +20 -0
  47. data/doc/rdoc/classes/Odeum/Index.src/M000037.html +22 -0
  48. data/doc/rdoc/classes/Odeum/Index.src/M000038.html +22 -0
  49. data/doc/rdoc/classes/Odeum/Index.src/M000039.html +22 -0
  50. data/doc/rdoc/classes/OdeumTest.html +257 -0
  51. data/doc/rdoc/classes/OdeumTest.src/M000001.html +18 -0
  52. data/doc/rdoc/classes/OdeumTest.src/M000002.html +19 -0
  53. data/doc/rdoc/classes/OdeumTest.src/M000003.html +27 -0
  54. data/doc/rdoc/classes/OdeumTest.src/M000004.html +25 -0
  55. data/doc/rdoc/classes/OdeumTest.src/M000005.html +44 -0
  56. data/doc/rdoc/classes/OdeumTest.src/M000006.html +20 -0
  57. data/doc/rdoc/classes/OdeumTest.src/M000007.html +39 -0
  58. data/doc/rdoc/classes/OdeumTest.src/M000008.html +59 -0
  59. data/doc/rdoc/classes/OdeumTest.src/M000009.html +41 -0
  60. data/doc/rdoc/created.rid +1 -0
  61. data/doc/rdoc/files/COPYING.html +756 -0
  62. data/doc/rdoc/files/LICENSE.html +756 -0
  63. data/doc/rdoc/files/README.html +175 -0
  64. data/doc/rdoc/files/ext/odeum_index/odeum_index_c.html +101 -0
  65. data/doc/rdoc/files/test/test_odeum_rb.html +109 -0
  66. data/doc/rdoc/fr_class_index.html +30 -0
  67. data/doc/rdoc/fr_file_index.html +31 -0
  68. data/doc/rdoc/fr_method_index.html +77 -0
  69. data/doc/rdoc/index.html +24 -0
  70. data/doc/rdoc/rdoc-style.css +208 -0
  71. data/ext/odeum_index/cabin.c +2735 -0
  72. data/ext/odeum_index/cabin.h +1040 -0
  73. data/ext/odeum_index/curia.c +1114 -0
  74. data/ext/odeum_index/curia.h +430 -0
  75. data/ext/odeum_index/depot.c +1910 -0
  76. data/ext/odeum_index/depot.h +439 -0
  77. data/ext/odeum_index/extconf.rb +10 -0
  78. data/ext/odeum_index/myconf.c +668 -0
  79. data/ext/odeum_index/myconf.h +523 -0
  80. data/ext/odeum_index/odeum.c +1743 -0
  81. data/ext/odeum_index/odeum.h +541 -0
  82. data/ext/odeum_index/odeum_index.c +991 -0
  83. data/ext/odeum_index/villa.c +1923 -0
  84. data/ext/odeum_index/villa.h +470 -0
  85. data/ext/odeum_index/vista.c +159 -0
  86. data/ext/odeum_index/vista.h +111 -0
  87. data/test/test_odeum.rb +174 -0
  88. metadata +138 -0
@@ -0,0 +1,1923 @@
1
+ /*************************************************************************************************
2
+ * Implementation of Villa
3
+ * Copyright (C) 2000-2005 Mikio Hirabayashi
4
+ * This file is part of QDBM, Quick Database Manager.
5
+ * QDBM is free software; you can redistribute it and/or modify it under the terms of the GNU
6
+ * Lesser General Public License as published by the Free Software Foundation; either version
7
+ * 2.1 of the License or any later version. QDBM is distributed in the hope that it will be
8
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
10
+ * details.
11
+ * You should have received a copy of the GNU Lesser General Public License along with QDBM; if
12
+ * not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
13
+ * 02111-1307 USA.
14
+ *************************************************************************************************/
15
+
16
+
17
+ #include "villa.h"
18
+ #include "myconf.h"
19
+
20
+ #define VL_LEAFIDMIN 1 /* minimum number of leaf ID */
21
+ #define VL_NODEIDMIN 100000000 /* minimum number of node ID */
22
+ #define VL_VNUMBUFSIZ 8 /* size of a buffer for variable length number */
23
+ #define VL_NUMBUFSIZ 32 /* size of a buffer for a number */
24
+ #define VL_LEVELMAX 64 /* max level of B+ tree */
25
+ #define VL_DEFLRECMAX 49 /* default number of records in each leaf */
26
+ #define VL_DEFNIDXMAX 192 /* default number of indexes in each node */
27
+ #define VL_DEFLCNUM 1024 /* default number of leaf cache */
28
+ #define VL_DEFNCNUM 512 /* default number of node cache */
29
+ #define VL_ALIGNRATIO 1.4 /* ratio between alignment and page size */
30
+ #define VL_CACHEOUT 8 /* number of pages in a process of cacheout */
31
+ #define VL_INITBNUM 32749 /* initial bucket number */
32
+ #define VL_INITALIGN 448 /* initial size of alignment */
33
+ #define VL_OPTALIGN -3 /* alignment setting when optimization */
34
+ #define VL_PATHBUFSIZ 1024 /* size of a path buffer */
35
+ #define VL_TMPFSUF MYEXTSTR "vltmp" /* suffix of a temporary file */
36
+ #define VL_ROOTKEY -1 /* key of the root key */
37
+ #define VL_LASTKEY -2 /* key of the last key */
38
+ #define VL_LNUMKEY -3 /* key of the number of leaves */
39
+ #define VL_NNUMKEY -4 /* key of the number of nodes */
40
+ #define VL_RNUMKEY -5 /* key of the number of records */
41
+
42
+ enum { /* enumeration for flags */
43
+ VL_FLISVILLA = 1 << 0, /* whether for Villa or not */
44
+ VL_FLISZLIB = 1 << 1 /* whether with ZLIB or not */
45
+ };
46
+
47
+
48
+ /* private function prototypes */
49
+ static int vllexcompare(const char *aptr, int asiz, const char *bptr, int bsiz);
50
+ static int vlintcompare(const char *aptr, int asiz, const char *bptr, int bsiz);
51
+ static int vlnumcompare(const char *aptr, int asiz, const char *bptr, int bsiz);
52
+ static int vldeccompare(const char *aptr, int asiz, const char *bptr, int bsiz);
53
+ static int vldpputnum(DEPOT *depot, int knum, int vnum);
54
+ static int vldpgetnum(DEPOT *depot, int knum, int *vnp);
55
+ static int vlsetvnumbuf(char *buf, int num);
56
+ static int vlreadvnumbuf(const char *buf, int size, int *sp);
57
+ static VLLEAF *vlleafnew(VILLA *villa, int prev, int next);
58
+ static int vlleafcacheout(VILLA *villa, int id);
59
+ static int vlleafsave(VILLA *villa, VLLEAF *leaf);
60
+ static VLLEAF *vlleafload(VILLA *villa, int id);
61
+ static int vlleafaddrec(VILLA *villa, VLLEAF *leaf, int dmode,
62
+ const char *kbuf, int ksiz, const char *vbuf, int vsiz);
63
+ static VLLEAF *vlleafdivide(VILLA *villa, VLLEAF *leaf);
64
+ static VLNODE *vlnodenew(VILLA *villa, int heir);
65
+ static int vlnodecacheout(VILLA *villa, int id);
66
+ static int vlnodesave(VILLA *villa, VLNODE *node);
67
+ static VLNODE *vlnodeload(VILLA *villa, int id);
68
+ static void vlnodeaddidx(VILLA *villa, VLNODE *node, int order,
69
+ int pid, const char *kbuf, int ksiz);
70
+ static int vlsearchleaf(VILLA *villa, const char *kbuf, int ksiz, int *hist, int *hnp);
71
+ static int vlcacheadjust(VILLA *villa);
72
+ static VLREC *vlrecsearch(VILLA *villa, VLLEAF *leaf, const char *kbuf, int ksiz, int *ip);
73
+
74
+
75
+
76
+ /*************************************************************************************************
77
+ * public objects
78
+ *************************************************************************************************/
79
+
80
+
81
+ /* Comparing functions. */
82
+ VLCFUNC VL_CMPLEX = vllexcompare;
83
+ VLCFUNC VL_CMPINT = vlintcompare;
84
+ VLCFUNC VL_CMPNUM = vlnumcompare;
85
+ VLCFUNC VL_CMPDEC = vldeccompare;
86
+
87
+
88
+ /* Get a database handle. */
89
+ VILLA *vlopen(const char *name, int omode, VLCFUNC cmp){
90
+ DEPOT *depot;
91
+ int dpomode, flags, zmode, root, last, lnum, nnum, rnum;
92
+ VILLA *villa;
93
+ VLLEAF *leaf;
94
+ assert(name && cmp);
95
+ dpomode = DP_OREADER;
96
+ if(omode & VL_OWRITER){
97
+ dpomode = DP_OWRITER;
98
+ if(omode & VL_OCREAT) dpomode |= DP_OCREAT;
99
+ if(omode & VL_OTRUNC) dpomode |= DP_OTRUNC;
100
+ }
101
+ if(omode & VL_ONOLCK) dpomode |= DP_ONOLCK;
102
+ if(!(depot = dpopen(name, dpomode, VL_INITBNUM))) return NULL;
103
+ flags = dpgetflags(depot);
104
+ zmode = 0;
105
+ root = -1;
106
+ last = -1;
107
+ lnum = 0;
108
+ nnum = 0;
109
+ rnum = 0;
110
+ if(dprnum(depot) > 0){
111
+ if(!(flags & VL_FLISVILLA) ||
112
+ !vldpgetnum(depot, VL_ROOTKEY, &root) || !vldpgetnum(depot, VL_LASTKEY, &last) ||
113
+ !vldpgetnum(depot, VL_LNUMKEY, &lnum) || !vldpgetnum(depot, VL_NNUMKEY, &nnum) ||
114
+ !vldpgetnum(depot, VL_RNUMKEY, &rnum) || root < VL_LEAFIDMIN || last < VL_LEAFIDMIN ||
115
+ lnum < 0 || nnum < 0 || rnum < 0){
116
+ dpclose(depot);
117
+ dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
118
+ return NULL;
119
+ }
120
+ zmode = flags & VL_FLISZLIB;
121
+ } else if(omode & VL_OWRITER){
122
+ zmode = omode & VL_OZCOMP;
123
+ }
124
+ if(omode & VL_OWRITER){
125
+ flags |= VL_FLISVILLA;
126
+ if(_qdbm_deflate && zmode) flags |= VL_FLISZLIB;
127
+ if(!dpsetflags(depot, flags)){
128
+ dpclose(depot);
129
+ return NULL;
130
+ }
131
+ }
132
+ villa = cbmalloc(sizeof(VILLA));
133
+ villa->depot = depot;
134
+ villa->cmp = cmp;
135
+ villa->wmode = (omode & VL_OWRITER);
136
+ villa->zmode = zmode;
137
+ villa->root = root;
138
+ villa->last = last;
139
+ villa->lnum = lnum;
140
+ villa->nnum = nnum;
141
+ villa->rnum = rnum;
142
+ villa->leafc = cbmapopen();
143
+ villa->nodec = cbmapopen();
144
+ villa->curleaf = -1;
145
+ villa->curknum = -1;
146
+ villa->curvnum = -1;
147
+ villa->leafrecmax = VL_DEFLRECMAX;
148
+ villa->nodeidxmax = VL_DEFNIDXMAX;
149
+ villa->leafcnum = VL_DEFLCNUM;
150
+ villa->nodecnum = VL_DEFNCNUM;
151
+ villa->avglsiz = VL_INITALIGN;
152
+ villa->avgnsiz = VL_INITALIGN;
153
+ villa->tran = FALSE;
154
+ villa->rbroot = -1;
155
+ villa->rblast = -1;
156
+ villa->rblnum = -1;
157
+ villa->rbnnum = -1;
158
+ villa->rbrnum = -1;
159
+ if(root == -1){
160
+ leaf = vlleafnew(villa, -1, -1);
161
+ villa->root = leaf->id;
162
+ villa->last = leaf->id;
163
+ if(!vltranbegin(villa) || !vltranabort(villa)){
164
+ vlclose(villa);
165
+ return NULL;
166
+ }
167
+ }
168
+ return villa;
169
+ }
170
+
171
+
172
+ /* Close a database handle. */
173
+ int vlclose(VILLA *villa){
174
+ int err, pid;
175
+ const char *tmp;
176
+ assert(villa);
177
+ err = FALSE;
178
+ if(villa->tran){
179
+ if(!vltranabort(villa)) err = TRUE;
180
+ }
181
+ cbmapiterinit(villa->leafc);
182
+ while((tmp = cbmapiternext(villa->leafc, NULL)) != NULL){
183
+ pid = *(int *)tmp;
184
+ if(!vlleafcacheout(villa, pid)) err = TRUE;
185
+ }
186
+ cbmapiterinit(villa->nodec);
187
+ while((tmp = cbmapiternext(villa->nodec, NULL)) != NULL){
188
+ pid = *(int *)tmp;
189
+ if(!vlnodecacheout(villa, pid)) err = TRUE;
190
+ }
191
+ if(villa->wmode){
192
+ if(!dpsetalign(villa->depot, 0)) err = TRUE;
193
+ if(!vldpputnum(villa->depot, VL_ROOTKEY, villa->root)) err = TRUE;
194
+ if(!vldpputnum(villa->depot, VL_LASTKEY, villa->last)) err = TRUE;
195
+ if(!vldpputnum(villa->depot, VL_LNUMKEY, villa->lnum)) err = TRUE;
196
+ if(!vldpputnum(villa->depot, VL_NNUMKEY, villa->nnum)) err = TRUE;
197
+ if(!vldpputnum(villa->depot, VL_RNUMKEY, villa->rnum)) err = TRUE;
198
+ }
199
+ cbmapclose(villa->leafc);
200
+ cbmapclose(villa->nodec);
201
+ if(!dpclose(villa->depot)) err = TRUE;
202
+ free(villa);
203
+ return err ? FALSE : TRUE;
204
+ }
205
+
206
+
207
+ /* Store a record. */
208
+ int vlput(VILLA *villa, const char *kbuf, int ksiz, const char *vbuf, int vsiz, int dmode){
209
+ VLLEAF *leaf, *newleaf;
210
+ VLNODE *node, *newnode;
211
+ VLIDX *idxp;
212
+ CBDATUM *key;
213
+ int hist[VL_LEVELMAX];
214
+ int i, hnum, pid, heir, parent, mid;
215
+ assert(villa && kbuf && vbuf);
216
+ villa->curleaf = -1;
217
+ villa->curknum = -1;
218
+ villa->curvnum = -1;
219
+ if(!villa->wmode){
220
+ dpecodeset(DP_EMODE, __FILE__, __LINE__);
221
+ return FALSE;
222
+ }
223
+ if(ksiz < 0) ksiz = strlen(kbuf);
224
+ if(vsiz < 0) vsiz = strlen(vbuf);
225
+ if((pid = vlsearchleaf(villa, kbuf, ksiz, hist, &hnum)) == -1) return FALSE;
226
+ if(!(leaf = vlleafload(villa, pid))) return FALSE;
227
+ if(!vlleafaddrec(villa, leaf, dmode, kbuf, ksiz, vbuf, vsiz)){
228
+ dpecodeset(DP_EKEEP, __FILE__, __LINE__);
229
+ return FALSE;
230
+ }
231
+ if(CB_LISTNUM(leaf->recs) > villa->leafrecmax && CB_LISTNUM(leaf->recs) % 2 == 0){
232
+ if(!(newleaf = vlleafdivide(villa, leaf))) return FALSE;
233
+ if(leaf->id == villa->last) villa->last = newleaf->id;
234
+ heir = leaf->id;
235
+ pid = newleaf->id;
236
+ key = ((VLREC *)CB_LISTVAL(newleaf->recs, 0, NULL))->key;
237
+ key = cbdatumopen(CB_DATUMPTR(key), CB_DATUMSIZE(key));
238
+ while(TRUE){
239
+ if(hnum < 1){
240
+ node = vlnodenew(villa, heir);
241
+ vlnodeaddidx(villa, node, TRUE, pid, CB_DATUMPTR(key), CB_DATUMSIZE(key));
242
+ villa->root = node->id;
243
+ cbdatumclose(key);
244
+ break;
245
+ }
246
+ parent = hist[--hnum];
247
+ if(!(node = vlnodeload(villa, parent))){
248
+ cbdatumclose(key);
249
+ return FALSE;
250
+ }
251
+ vlnodeaddidx(villa, node, FALSE, pid, CB_DATUMPTR(key), CB_DATUMSIZE(key));
252
+ cbdatumclose(key);
253
+ if(CB_LISTNUM(node->idxs) <= villa->nodeidxmax || CB_LISTNUM(node->idxs) % 2 == 0) break;
254
+ mid = CB_LISTNUM(node->idxs) / 2;
255
+ idxp = (VLIDX *)CB_LISTVAL(node->idxs, mid, NULL);
256
+ newnode = vlnodenew(villa, idxp->pid);
257
+ heir = node->id;
258
+ pid = newnode->id;
259
+ key = cbdatumopen(CB_DATUMPTR(idxp->key), CB_DATUMSIZE(idxp->key));
260
+ for(i = mid + 1; i < CB_LISTNUM(node->idxs); i++){
261
+ idxp = (VLIDX *)CB_LISTVAL(node->idxs, i, NULL);
262
+ vlnodeaddidx(villa, newnode, TRUE, idxp->pid,
263
+ CB_DATUMPTR(idxp->key), CB_DATUMSIZE(idxp->key));
264
+ }
265
+ for(i = 0; i <= mid; i++){
266
+ idxp = (VLIDX *)cblistpop(node->idxs, NULL);
267
+ cbdatumclose(idxp->key);
268
+ free(idxp);
269
+ }
270
+ node->dirty = TRUE;
271
+ }
272
+ }
273
+ if(!villa->tran && !vlcacheadjust(villa)) return FALSE;
274
+ return TRUE;
275
+ }
276
+
277
+
278
+ /* Delete a record. */
279
+ int vlout(VILLA *villa, const char *kbuf, int ksiz){
280
+ VLLEAF *leaf;
281
+ VLREC *recp;
282
+ int pid, ri, vsiz;
283
+ char *vbuf;
284
+ assert(villa && kbuf);
285
+ villa->curleaf = -1;
286
+ villa->curknum = -1;
287
+ villa->curvnum = -1;
288
+ if(!villa->wmode){
289
+ dpecodeset(DP_EMODE, __FILE__, __LINE__);
290
+ return FALSE;
291
+ }
292
+ if(ksiz < 0) ksiz = strlen(kbuf);
293
+ if((pid = vlsearchleaf(villa, kbuf, ksiz, NULL, NULL)) == -1) return FALSE;
294
+ if(!(leaf = vlleafload(villa, pid))) return FALSE;
295
+ if(!(recp = vlrecsearch(villa, leaf, kbuf, ksiz, &ri))){
296
+ dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
297
+ return FALSE;
298
+ }
299
+ if(recp->rest){
300
+ cbdatumclose(recp->first);
301
+ vbuf = cblistshift(recp->rest, &vsiz);
302
+ recp->first = cbdatumopen(vbuf, vsiz);
303
+ free(vbuf);
304
+ if(CB_LISTNUM(recp->rest) < 1){
305
+ cblistclose(recp->rest);
306
+ recp->rest = NULL;
307
+ }
308
+ } else {
309
+ cbdatumclose(recp->key);
310
+ cbdatumclose(recp->first);
311
+ free(cblistremove(leaf->recs, ri, NULL));
312
+ }
313
+ leaf->dirty = TRUE;
314
+ villa->rnum--;
315
+ if(!villa->tran && !vlcacheadjust(villa)) return FALSE;
316
+ return TRUE;
317
+ }
318
+
319
+
320
+ /* Retrieve a record. */
321
+ char *vlget(VILLA *villa, const char *kbuf, int ksiz, int *sp){
322
+ VLLEAF *leaf;
323
+ VLREC *recp;
324
+ int pid;
325
+ assert(villa && kbuf);
326
+ if(ksiz < 0) ksiz = strlen(kbuf);
327
+ if((pid = vlsearchleaf(villa, kbuf, ksiz, NULL, NULL)) == -1) return NULL;
328
+ if(!(leaf = vlleafload(villa, pid))) return NULL;
329
+ if(!(recp = vlrecsearch(villa, leaf, kbuf, ksiz, NULL))){
330
+ dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
331
+ return NULL;
332
+ }
333
+ if(!villa->tran && !vlcacheadjust(villa)) return NULL;
334
+ if(sp) *sp = CB_DATUMSIZE(recp->first);
335
+ return cbmemdup(CB_DATUMPTR(recp->first), CB_DATUMSIZE(recp->first));
336
+ }
337
+
338
+
339
+ /* Get the number of records corresponding a key. */
340
+ int vlvnum(VILLA *villa, const char *kbuf, int ksiz){
341
+ VLLEAF *leaf;
342
+ VLREC *recp;
343
+ int pid;
344
+ assert(villa && kbuf);
345
+ if(ksiz < 0) ksiz = strlen(kbuf);
346
+ if((pid = vlsearchleaf(villa, kbuf, ksiz, NULL, NULL)) == -1) return 0;
347
+ if(!(leaf = vlleafload(villa, pid))) return 0;
348
+ if(!(recp = vlrecsearch(villa, leaf, kbuf, ksiz, NULL))){
349
+ dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
350
+ return 0;
351
+ }
352
+ if(!villa->tran && !vlcacheadjust(villa)) return 0;
353
+ return 1 + (recp->rest ? CB_LISTNUM(recp->rest) : 0);
354
+ }
355
+
356
+
357
+ /* Store plural records corresponding a key. */
358
+ int vlputlist(VILLA *villa, const char *kbuf, int ksiz, const CBLIST *vals){
359
+ int i, vsiz;
360
+ const char *vbuf;
361
+ assert(villa && kbuf && vals);
362
+ if(!villa->wmode){
363
+ dpecodeset(DP_EMODE, __FILE__, __LINE__);
364
+ return FALSE;
365
+ }
366
+ if(CB_LISTNUM(vals) < 1){
367
+ dpecodeset(DP_EMISC, __FILE__, __LINE__);
368
+ return FALSE;
369
+ }
370
+ if(ksiz < 0) ksiz = strlen(kbuf);
371
+ for(i = 0; i < CB_LISTNUM(vals); i++){
372
+ vbuf = cblistval(vals, i, &vsiz);
373
+ if(!vlput(villa, kbuf, ksiz, vbuf, vsiz, VL_DDUP)) return FALSE;
374
+ }
375
+ return TRUE;
376
+ }
377
+
378
+
379
+ /* Delete all records corresponding a key. */
380
+ int vloutlist(VILLA *villa, const char *kbuf, int ksiz){
381
+ int i, vnum;
382
+ assert(villa && kbuf);
383
+ if(!villa->wmode){
384
+ dpecodeset(DP_EMISC, __FILE__, __LINE__);
385
+ return FALSE;
386
+ }
387
+ if(ksiz < 0) ksiz = strlen(kbuf);
388
+ if((vnum = vlvnum(villa, kbuf, ksiz)) < 1) return FALSE;
389
+ for(i = 0; i < vnum; i++){
390
+ if(!vlout(villa, kbuf, ksiz)) return FALSE;
391
+ }
392
+ return TRUE;
393
+ }
394
+
395
+
396
+ /* Retrieve values of all records corresponding a key. */
397
+ CBLIST *vlgetlist(VILLA *villa, const char *kbuf, int ksiz){
398
+ VLLEAF *leaf;
399
+ VLREC *recp;
400
+ int pid, i, vsiz;
401
+ CBLIST *vals;
402
+ const char *vbuf;
403
+ assert(villa && kbuf);
404
+ if(ksiz < 0) ksiz = strlen(kbuf);
405
+ if((pid = vlsearchleaf(villa, kbuf, ksiz, NULL, NULL)) == -1) return NULL;
406
+ if(!(leaf = vlleafload(villa, pid))) return NULL;
407
+ if(!(recp = vlrecsearch(villa, leaf, kbuf, ksiz, NULL))){
408
+ dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
409
+ return NULL;
410
+ }
411
+ vals = cblistopen();
412
+ cblistpush(vals, CB_DATUMPTR(recp->first), CB_DATUMSIZE(recp->first));
413
+ if(recp->rest){
414
+ for(i = 0; i < CB_LISTNUM(recp->rest); i++){
415
+ vbuf = cblistval(recp->rest, i, &vsiz);
416
+ cblistpush(vals, vbuf, vsiz);
417
+ }
418
+ }
419
+ if(!villa->tran && !vlcacheadjust(villa)){
420
+ cblistclose(vals);
421
+ return NULL;
422
+ }
423
+ return vals;
424
+ }
425
+
426
+
427
+ /* Move the cursor to the first record. */
428
+ int vlcurfirst(VILLA *villa){
429
+ VLLEAF *leaf;
430
+ assert(villa);
431
+ villa->curleaf = VL_LEAFIDMIN;
432
+ villa->curknum = 0;
433
+ villa->curvnum = 0;
434
+ if(!(leaf = vlleafload(villa, villa->curleaf))){
435
+ villa->curleaf = -1;
436
+ return FALSE;
437
+ }
438
+ while(CB_LISTNUM(leaf->recs) < 1){
439
+ villa->curleaf = leaf->next;
440
+ villa->curknum = 0;
441
+ villa->curvnum = 0;
442
+ if(villa->curleaf == -1){
443
+ dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
444
+ return FALSE;
445
+ }
446
+ if(!(leaf = vlleafload(villa, villa->curleaf))){
447
+ villa->curleaf = -1;
448
+ return FALSE;
449
+ }
450
+ }
451
+ return TRUE;
452
+ }
453
+
454
+
455
+ /* Move the cursor to the last record. */
456
+ int vlcurlast(VILLA *villa){
457
+ VLLEAF *leaf;
458
+ VLREC *recp;
459
+ assert(villa);
460
+ villa->curleaf = villa->last;
461
+ if(!(leaf = vlleafload(villa, villa->curleaf))){
462
+ villa->curleaf = -1;
463
+ return FALSE;
464
+ }
465
+ while(CB_LISTNUM(leaf->recs) < 1){
466
+ villa->curleaf = leaf->prev;
467
+ if(villa->curleaf == -1){
468
+ villa->curleaf = -1;
469
+ dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
470
+ return FALSE;
471
+ }
472
+ if(!(leaf = vlleafload(villa, villa->curleaf))){
473
+ villa->curleaf = -1;
474
+ return FALSE;
475
+ }
476
+ }
477
+ villa->curknum = CB_LISTNUM(leaf->recs) - 1;
478
+ recp = (VLREC *)CB_LISTVAL(leaf->recs, villa->curknum, NULL);
479
+ villa->curvnum = recp->rest ? CB_LISTNUM(recp->rest) : 0;
480
+ return TRUE;
481
+ }
482
+
483
+
484
+ /* Move the cursor to the previous record. */
485
+ int vlcurprev(VILLA *villa){
486
+ VLLEAF *leaf;
487
+ VLREC *recp;
488
+ assert(villa);
489
+ if(villa->curleaf == -1){
490
+ dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
491
+ return FALSE;
492
+ }
493
+ if(!(leaf = vlleafload(villa, villa->curleaf)) || CB_LISTNUM(leaf->recs) < 1){
494
+ villa->curleaf = -1;
495
+ return FALSE;
496
+ }
497
+ recp = (VLREC *)CB_LISTVAL(leaf->recs, villa->curknum, NULL);
498
+ villa->curvnum--;
499
+ if(villa->curvnum < 0){
500
+ villa->curknum--;
501
+ if(villa->curknum < 0){
502
+ villa->curleaf = leaf->prev;
503
+ if(villa->curleaf == -1){
504
+ villa->curleaf = -1;
505
+ dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
506
+ return FALSE;
507
+ }
508
+ if(!(leaf = vlleafload(villa, villa->curleaf))){
509
+ villa->curleaf = -1;
510
+ return FALSE;
511
+ }
512
+ while(CB_LISTNUM(leaf->recs) < 1){
513
+ villa->curleaf = leaf->prev;
514
+ if(villa->curleaf == -1){
515
+ dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
516
+ return FALSE;
517
+ }
518
+ if(!(leaf = vlleafload(villa, villa->curleaf))){
519
+ villa->curleaf = -1;
520
+ return FALSE;
521
+ }
522
+ }
523
+ villa->curknum = CB_LISTNUM(leaf->recs) - 1;
524
+ recp = (VLREC *)CB_LISTVAL(leaf->recs, villa->curknum, NULL);
525
+ villa->curvnum = recp->rest ? CB_LISTNUM(recp->rest) : 0;
526
+ }
527
+ recp = (VLREC *)CB_LISTVAL(leaf->recs, villa->curknum, NULL);
528
+ villa->curvnum = recp->rest ? CB_LISTNUM(recp->rest) : 0;
529
+ }
530
+ if(!villa->tran && !vlcacheadjust(villa)) return FALSE;
531
+ return TRUE;
532
+ }
533
+
534
+
535
+ /* Move the cursor to the next record. */
536
+ int vlcurnext(VILLA *villa){
537
+ VLLEAF *leaf;
538
+ VLREC *recp;
539
+ assert(villa);
540
+ if(villa->curleaf == -1){
541
+ dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
542
+ return FALSE;
543
+ }
544
+ if(!(leaf = vlleafload(villa, villa->curleaf)) || CB_LISTNUM(leaf->recs) < 1){
545
+ villa->curleaf = -1;
546
+ return FALSE;
547
+ }
548
+ recp = (VLREC *)CB_LISTVAL(leaf->recs, villa->curknum, NULL);
549
+ villa->curvnum++;
550
+ if(villa->curvnum > (recp->rest ? CB_LISTNUM(recp->rest) : 0)){
551
+ villa->curknum++;
552
+ villa->curvnum = 0;
553
+ }
554
+ if(villa->curknum >= CB_LISTNUM(leaf->recs)){
555
+ villa->curleaf = leaf->next;
556
+ villa->curknum = 0;
557
+ villa->curvnum = 0;
558
+ if(villa->curleaf == -1){
559
+ dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
560
+ return FALSE;
561
+ }
562
+ if(!(leaf = vlleafload(villa, villa->curleaf))){
563
+ villa->curleaf = -1;
564
+ return FALSE;
565
+ }
566
+ while(CB_LISTNUM(leaf->recs) < 1){
567
+ villa->curleaf = leaf->next;
568
+ villa->curknum = 0;
569
+ villa->curvnum = 0;
570
+ if(villa->curleaf == -1){
571
+ dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
572
+ return FALSE;
573
+ }
574
+ if(!(leaf = vlleafload(villa, villa->curleaf))){
575
+ villa->curleaf = -1;
576
+ return FALSE;
577
+ }
578
+ }
579
+ }
580
+ if(!villa->tran && !vlcacheadjust(villa)) return FALSE;
581
+ return TRUE;
582
+ }
583
+
584
+
585
+ /* Move the cursor to position around a record. */
586
+ int vlcurjump(VILLA *villa, const char *kbuf, int ksiz, int jmode){
587
+ VLLEAF *leaf;
588
+ VLREC *recp;
589
+ int pid, index;
590
+ assert(villa && kbuf);
591
+ if(ksiz < 0) ksiz = strlen(kbuf);
592
+ if((pid = vlsearchleaf(villa, kbuf, ksiz, NULL, NULL)) == -1){
593
+ villa->curleaf = -1;
594
+ return FALSE;
595
+ }
596
+ if(!(leaf = vlleafload(villa, pid))){
597
+ villa->curleaf = -1;
598
+ return FALSE;
599
+ }
600
+ while(CB_LISTNUM(leaf->recs) < 1){
601
+ villa->curleaf = (jmode == VL_JFORWARD) ? leaf->next : leaf->prev;
602
+ if(villa->curleaf == -1){
603
+ dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
604
+ return FALSE;
605
+ }
606
+ if(!(leaf = vlleafload(villa, villa->curleaf))){
607
+ villa->curleaf = -1;
608
+ return FALSE;
609
+ }
610
+ }
611
+ if(!(recp = vlrecsearch(villa, leaf, kbuf, ksiz, &index))){
612
+ if(jmode == VL_JFORWARD){
613
+ villa->curleaf = leaf->id;
614
+ if(index >= CB_LISTNUM(leaf->recs)) index--;
615
+ villa->curknum = index;
616
+ villa->curvnum = 0;
617
+ recp = (VLREC *)CB_LISTVAL(leaf->recs, index, NULL);
618
+ if(villa->cmp(kbuf, ksiz, CB_DATUMPTR(recp->key), CB_DATUMSIZE(recp->key)) < 0) return TRUE;
619
+ villa->curvnum = (recp->rest ? CB_LISTNUM(recp->rest) : 0);
620
+ return vlcurnext(villa);
621
+ } else {
622
+ villa->curleaf = leaf->id;
623
+ if(index >= CB_LISTNUM(leaf->recs)) index--;
624
+ villa->curknum = index;
625
+ recp = (VLREC *)CB_LISTVAL(leaf->recs, index, NULL);
626
+ villa->curvnum = (recp->rest ? CB_LISTNUM(recp->rest) : 0);
627
+ if(villa->cmp(kbuf, ksiz, CB_DATUMPTR(recp->key), CB_DATUMSIZE(recp->key)) > 0) return TRUE;
628
+ villa->curvnum = 0;
629
+ return vlcurprev(villa);
630
+ }
631
+ }
632
+ if(jmode == VL_JFORWARD){
633
+ villa->curleaf = pid;
634
+ villa->curknum = index;
635
+ villa->curvnum = 0;
636
+ } else {
637
+ villa->curleaf = pid;
638
+ villa->curknum = index;
639
+ villa->curvnum = (recp->rest ? CB_LISTNUM(recp->rest) : 0);
640
+ }
641
+ return TRUE;
642
+ }
643
+
644
+
645
+ /* Get the key of the record where the cursor is. */
646
+ char *vlcurkey(VILLA *villa, int *sp){
647
+ VLLEAF *leaf;
648
+ VLREC *recp;
649
+ const char *kbuf;
650
+ int ksiz;
651
+ assert(villa);
652
+ if(villa->curleaf == -1){
653
+ dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
654
+ return FALSE;
655
+ }
656
+ if(!(leaf = vlleafload(villa, villa->curleaf))){
657
+ villa->curleaf = -1;
658
+ return FALSE;
659
+ }
660
+ recp = (VLREC *)CB_LISTVAL(leaf->recs, villa->curknum, NULL);
661
+ kbuf = CB_DATUMPTR(recp->key);
662
+ ksiz = CB_DATUMSIZE(recp->key);
663
+ if(sp) *sp = ksiz;
664
+ return cbmemdup(kbuf, ksiz);
665
+ }
666
+
667
+
668
+ /* Get the value of the record where the cursor is. */
669
+ char *vlcurval(VILLA *villa, int *sp){
670
+ VLLEAF *leaf;
671
+ VLREC *recp;
672
+ const char *kbuf;
673
+ int ksiz;
674
+ assert(villa);
675
+ if(villa->curleaf == -1){
676
+ dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
677
+ return FALSE;
678
+ }
679
+ if(!(leaf = vlleafload(villa, villa->curleaf))){
680
+ villa->curleaf = -1;
681
+ return FALSE;
682
+ }
683
+ recp = (VLREC *)CB_LISTVAL(leaf->recs, villa->curknum, NULL);
684
+ if(villa->curvnum < 1){
685
+ kbuf = CB_DATUMPTR(recp->first);
686
+ ksiz = CB_DATUMSIZE(recp->first);
687
+ } else {
688
+ kbuf = cblistval(recp->rest, villa->curvnum - 1, &ksiz);
689
+ }
690
+ if(sp) *sp = ksiz;
691
+ return cbmemdup(kbuf, ksiz);
692
+ }
693
+
694
+
695
+ /* Set the tuning parameters for performance. */
696
+ void vlsettuning(VILLA *villa, int lrecmax, int nidxmax, int lcnum, int ncnum){
697
+ assert(villa);
698
+ if(lrecmax < 1) lrecmax = VL_DEFLRECMAX;
699
+ if(lrecmax < 3) lrecmax = 3;
700
+ if(nidxmax < 1) nidxmax = VL_DEFNIDXMAX;
701
+ if(nidxmax < 4) nidxmax = 4;
702
+ if(lcnum < 1) lcnum = VL_DEFLCNUM;
703
+ if(lcnum < VL_CACHEOUT * 2) lcnum = VL_CACHEOUT * 2;
704
+ if(ncnum < 1) ncnum = VL_DEFNCNUM;
705
+ if(ncnum < VL_CACHEOUT * 2) ncnum = VL_CACHEOUT * 2;
706
+ villa->leafrecmax = lrecmax;
707
+ villa->nodeidxmax = nidxmax;
708
+ villa->leafcnum = lcnum;
709
+ villa->nodecnum = ncnum;
710
+ }
711
+
712
+
713
+ /* Synchronize updating contents with the file and the device. */
714
+ int vlsync(VILLA *villa){
715
+ int err, pid;
716
+ const char *tmp;
717
+ assert(villa);
718
+ if(!villa->wmode){
719
+ dpecodeset(DP_EMODE, __FILE__, __LINE__);
720
+ return FALSE;
721
+ }
722
+ if(villa->tran){
723
+ dpecodeset(DP_EMISC, __FILE__, __LINE__);
724
+ return FALSE;
725
+ }
726
+ err = FALSE;
727
+ cbmapiterinit(villa->leafc);
728
+ while((tmp = cbmapiternext(villa->leafc, NULL)) != NULL){
729
+ pid = *(int *)tmp;
730
+ if(!vlleafcacheout(villa, pid)) err = TRUE;
731
+ }
732
+ cbmapiterinit(villa->nodec);
733
+ while((tmp = cbmapiternext(villa->nodec, NULL)) != NULL){
734
+ pid = *(int *)tmp;
735
+ if(!vlnodecacheout(villa, pid)) err = TRUE;
736
+ }
737
+ if(!dpsetalign(villa->depot, 0)) err = TRUE;
738
+ if(!vldpputnum(villa->depot, VL_ROOTKEY, villa->root)) err = TRUE;
739
+ if(!vldpputnum(villa->depot, VL_LASTKEY, villa->last)) err = TRUE;
740
+ if(!vldpputnum(villa->depot, VL_LNUMKEY, villa->lnum)) err = TRUE;
741
+ if(!vldpputnum(villa->depot, VL_NNUMKEY, villa->nnum)) err = TRUE;
742
+ if(!vldpputnum(villa->depot, VL_RNUMKEY, villa->rnum)) err = TRUE;
743
+ if(!dpsync(villa->depot)) err = TRUE;
744
+ return err ? FALSE : TRUE;
745
+ }
746
+
747
+
748
+ /* Optimize a database. */
749
+ int vloptimize(VILLA *villa){
750
+ int err;
751
+ assert(villa);
752
+ if(!villa->wmode){
753
+ dpecodeset(DP_EMODE, __FILE__, __LINE__);
754
+ return FALSE;
755
+ }
756
+ if(villa->tran){
757
+ dpecodeset(DP_EMISC, __FILE__, __LINE__);
758
+ return FALSE;
759
+ }
760
+ err = FALSE;
761
+ if(!vlsync(villa)) return FALSE;
762
+ if(!dpsetalign(villa->depot, VL_OPTALIGN)) err = TRUE;
763
+ if(!dpoptimize(villa->depot, -1)) err = TRUE;
764
+ return err ? FALSE : TRUE;
765
+ }
766
+
767
+
768
+ /* Get the name of a database. */
769
+ char *vlname(VILLA *villa){
770
+ assert(villa);
771
+ return dpname(villa->depot);
772
+ }
773
+
774
+
775
+ /* Get the size of a database file. */
776
+ int vlfsiz(VILLA *villa){
777
+ return dpfsiz(villa->depot);
778
+ }
779
+
780
+
781
+ /* Get the number of the leaf nodes of B+ tree. */
782
+ int vllnum(VILLA *villa){
783
+ assert(villa);
784
+ return villa->lnum;
785
+ }
786
+
787
+
788
+ /* Get the number of the non-leaf nodes of B+ tree. */
789
+ int vlnnum(VILLA *villa){
790
+ assert(villa);
791
+ return villa->nnum;
792
+ }
793
+
794
+
795
+ /* Get the number of the records stored in a database. */
796
+ int vlrnum(VILLA *villa){
797
+ assert(villa);
798
+ return villa->rnum;
799
+ }
800
+
801
+
802
+ /* Check whether a database handle is a writer or not. */
803
+ int vlwritable(VILLA *villa){
804
+ assert(villa);
805
+ return villa->wmode;
806
+ }
807
+
808
+
809
+ /* Check whether a database has a fatal error or not. */
810
+ int vlfatalerror(VILLA *villa){
811
+ assert(villa);
812
+ return dpfatalerror(villa->depot);
813
+ }
814
+
815
+
816
+ /* Get the inode number of a database file. */
817
+ int vlinode(VILLA *villa){
818
+ assert(villa);
819
+ return dpinode(villa->depot);
820
+ }
821
+
822
+
823
+ /* Get the last modified time of a database. */
824
+ int vlmtime(VILLA *villa){
825
+ assert(villa);
826
+ return dpmtime(villa->depot);
827
+ }
828
+
829
+
830
+ /* Begin the transaction. */
831
+ int vltranbegin(VILLA *villa){
832
+ int err, pid;
833
+ const char *tmp;
834
+ VLLEAF *leaf;
835
+ VLNODE *node;
836
+ assert(villa);
837
+ if(!villa->wmode){
838
+ dpecodeset(DP_EMODE, __FILE__, __LINE__);
839
+ return FALSE;
840
+ }
841
+ if(villa->tran){
842
+ dpecodeset(DP_EMISC, __FILE__, __LINE__);
843
+ return FALSE;
844
+ }
845
+ err = FALSE;
846
+ cbmapiterinit(villa->leafc);
847
+ while((tmp = cbmapiternext(villa->leafc, NULL)) != NULL){
848
+ pid = *(int *)tmp;
849
+ leaf = (VLLEAF *)cbmapget(villa->leafc, (char *)&pid, sizeof(int), NULL);
850
+ if(leaf->dirty){
851
+ if(!vlleafsave(villa, leaf)) err = TRUE;
852
+ }
853
+ }
854
+ cbmapiterinit(villa->nodec);
855
+ while((tmp = cbmapiternext(villa->nodec, NULL)) != NULL){
856
+ pid = *(int *)tmp;
857
+ node = (VLNODE *)cbmapget(villa->nodec, (char *)&pid, sizeof(int), NULL);
858
+ if(node->dirty){
859
+ if(!vlnodesave(villa, node)) err = TRUE;
860
+ }
861
+ }
862
+ if(!dpsetalign(villa->depot, 0)) err = TRUE;
863
+ if(!vldpputnum(villa->depot, VL_ROOTKEY, villa->root)) err = TRUE;
864
+ if(!vldpputnum(villa->depot, VL_LASTKEY, villa->last)) err = TRUE;
865
+ if(!vldpputnum(villa->depot, VL_LNUMKEY, villa->lnum)) err = TRUE;
866
+ if(!vldpputnum(villa->depot, VL_NNUMKEY, villa->nnum)) err = TRUE;
867
+ if(!vldpputnum(villa->depot, VL_RNUMKEY, villa->rnum)) err = TRUE;
868
+ if(!dpmemsync(villa->depot)) err = TRUE;
869
+ villa->tran = TRUE;
870
+ villa->rbroot = villa->root;
871
+ villa->rblast = villa->last;
872
+ villa->rblnum = villa->lnum;
873
+ villa->rbnnum = villa->nnum;
874
+ villa->rbrnum = villa->rnum;
875
+ return err ? FALSE : TRUE;
876
+ }
877
+
878
+
879
+ /* Commit the transaction. */
880
+ int vltrancommit(VILLA *villa){
881
+ int err, pid;
882
+ const char *tmp;
883
+ VLLEAF *leaf;
884
+ VLNODE *node;
885
+ assert(villa);
886
+ if(!villa->wmode){
887
+ dpecodeset(DP_EMODE, __FILE__, __LINE__);
888
+ return FALSE;
889
+ }
890
+ if(!villa->tran){
891
+ dpecodeset(DP_EMISC, __FILE__, __LINE__);
892
+ return FALSE;
893
+ }
894
+ err = FALSE;
895
+ cbmapiterinit(villa->leafc);
896
+ while((tmp = cbmapiternext(villa->leafc, NULL)) != NULL){
897
+ pid = *(int *)tmp;
898
+ leaf = (VLLEAF *)cbmapget(villa->leafc, (char *)&pid, sizeof(int), NULL);
899
+ if(leaf->dirty){
900
+ if(!vlleafsave(villa, leaf)) err = TRUE;
901
+ }
902
+ }
903
+ cbmapiterinit(villa->nodec);
904
+ while((tmp = cbmapiternext(villa->nodec, NULL)) != NULL){
905
+ pid = *(int *)tmp;
906
+ node = (VLNODE *)cbmapget(villa->nodec, (char *)&pid, sizeof(int), NULL);
907
+ if(node->dirty){
908
+ if(!vlnodesave(villa, node)) err = TRUE;
909
+ }
910
+ }
911
+ if(!dpsetalign(villa->depot, 0)) err = TRUE;
912
+ if(!vldpputnum(villa->depot, VL_ROOTKEY, villa->root)) err = TRUE;
913
+ if(!vldpputnum(villa->depot, VL_LASTKEY, villa->last)) err = TRUE;
914
+ if(!vldpputnum(villa->depot, VL_LNUMKEY, villa->lnum)) err = TRUE;
915
+ if(!vldpputnum(villa->depot, VL_NNUMKEY, villa->nnum)) err = TRUE;
916
+ if(!vldpputnum(villa->depot, VL_RNUMKEY, villa->rnum)) err = TRUE;
917
+ if(!dpmemsync(villa->depot)) err = TRUE;
918
+ villa->tran = FALSE;
919
+ villa->rbroot = -1;
920
+ villa->rblast = -1;
921
+ villa->rblnum = -1;
922
+ villa->rbnnum = -1;
923
+ villa->rbrnum = -1;
924
+ while(cbmaprnum(villa->leafc) > villa->leafcnum || cbmaprnum(villa->nodec) > villa->nodecnum){
925
+ if(!vlcacheadjust(villa)){
926
+ err = TRUE;
927
+ break;
928
+ }
929
+ }
930
+ return err ? FALSE : TRUE;
931
+ }
932
+
933
+
934
+ /* Abort the transaction. */
935
+ int vltranabort(VILLA *villa){
936
+ int err, pid;
937
+ const char *tmp;
938
+ VLLEAF *leaf;
939
+ VLNODE *node;
940
+ assert(villa);
941
+ if(!villa->wmode){
942
+ dpecodeset(DP_EMODE, __FILE__, __LINE__);
943
+ return FALSE;
944
+ }
945
+ if(!villa->tran){
946
+ dpecodeset(DP_EMISC, __FILE__, __LINE__);
947
+ return FALSE;
948
+ }
949
+ err = FALSE;
950
+ cbmapiterinit(villa->leafc);
951
+ while((tmp = cbmapiternext(villa->leafc, NULL)) != NULL){
952
+ pid = *(int *)tmp;
953
+ if(!(leaf = (VLLEAF *)cbmapget(villa->leafc, (char *)&pid, sizeof(int), NULL))){
954
+ err = TRUE;
955
+ continue;
956
+ }
957
+ if(leaf->dirty){
958
+ leaf->dirty = FALSE;
959
+ if(!vlleafcacheout(villa, pid)) err = TRUE;
960
+ }
961
+ }
962
+ cbmapiterinit(villa->nodec);
963
+ while((tmp = cbmapiternext(villa->nodec, NULL)) != NULL){
964
+ pid = *(int *)tmp;
965
+ if(!(node = (VLNODE *)cbmapget(villa->nodec, (char *)&pid, sizeof(int), NULL))){
966
+ err = TRUE;
967
+ continue;
968
+ }
969
+ if(node->dirty){
970
+ node->dirty = FALSE;
971
+ if(!vlnodecacheout(villa, pid)) err = TRUE;
972
+ }
973
+ }
974
+ villa->tran = FALSE;
975
+ villa->root = villa->rbroot;
976
+ villa->last = villa->rblast;
977
+ villa->lnum = villa->rblnum;
978
+ villa->nnum = villa->rbnnum;
979
+ villa->rnum = villa->rbrnum;
980
+ while(cbmaprnum(villa->leafc) > villa->leafcnum || cbmaprnum(villa->nodec) > villa->nodecnum){
981
+ if(!vlcacheadjust(villa)){
982
+ err = TRUE;
983
+ break;
984
+ }
985
+ }
986
+ return err ? FALSE : TRUE;
987
+ }
988
+
989
+
990
+ /* Remove a database file. */
991
+ int vlremove(const char *name){
992
+ assert(name);
993
+ return dpremove(name);
994
+ }
995
+
996
+
997
+ /* Repair a broken database file. */
998
+ int vlrepair(const char *name, VLCFUNC cmp){
999
+ DEPOT *depot;
1000
+ VILLA *tvilla;
1001
+ char path[VL_PATHBUFSIZ], *kbuf, *vbuf, *zbuf, *rp, *tkbuf, *tvbuf;
1002
+ int i, err, flags, omode, ksiz, vsiz, zsiz, size, step, tksiz, tvsiz, vnum;
1003
+ assert(name && cmp);
1004
+ err = FALSE;
1005
+ if(!dprepair(name)) err = TRUE;
1006
+ if(!(depot = dpopen(name, DP_OREADER, -1))) return FALSE;
1007
+ flags = dpgetflags(depot);
1008
+ if(!(flags & VL_FLISVILLA)){
1009
+ dpclose(depot);
1010
+ dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
1011
+ return FALSE;
1012
+ }
1013
+ sprintf(path, "%s%s", name, VL_TMPFSUF);
1014
+ omode = VL_OWRITER | VL_OCREAT | VL_OTRUNC;
1015
+ if(flags & VL_FLISZLIB) omode |= VL_OZCOMP;
1016
+ if(!(tvilla = vlopen(path, omode, cmp))){
1017
+ dpclose(depot);
1018
+ return FALSE;
1019
+ }
1020
+ if(!dpiterinit(depot)) err = TRUE;
1021
+ while((kbuf = dpiternext(depot, &ksiz)) != NULL){
1022
+ if(ksiz == sizeof(int) && *(int *)kbuf < VL_NODEIDMIN && *(int *)kbuf > 0){
1023
+ if((vbuf = dpget(depot, (char *)kbuf, sizeof(int), 0, -1, &vsiz)) != NULL){
1024
+ if(_qdbm_inflate && (flags & VL_FLISZLIB) &&
1025
+ (zbuf = _qdbm_inflate(vbuf, vsiz, &zsiz)) != NULL){
1026
+ free(vbuf);
1027
+ vbuf = zbuf;
1028
+ vsiz = zsiz;
1029
+ }
1030
+ rp = vbuf;
1031
+ size = vsiz;
1032
+ if(size >= 1){
1033
+ vlreadvnumbuf(rp, size, &step);
1034
+ rp += step;
1035
+ size -= step;
1036
+ }
1037
+ if(size >= 1){
1038
+ vlreadvnumbuf(rp, size, &step);
1039
+ rp += step;
1040
+ size -= step;
1041
+ }
1042
+ while(size >= 1){
1043
+ tksiz = vlreadvnumbuf(rp, size, &step);
1044
+ rp += step;
1045
+ size -= step;
1046
+ if(size < tksiz) break;
1047
+ tkbuf = rp;
1048
+ rp += tksiz;
1049
+ size -= tksiz;
1050
+ if(size < 1) break;
1051
+ vnum = vlreadvnumbuf(rp, size, &step);
1052
+ rp += step;
1053
+ size -= step;
1054
+ if(vnum < 1 || size < 1) break;
1055
+ for(i = 0; i < vnum && size >= 1; i++){
1056
+ tvsiz = vlreadvnumbuf(rp, size, &step);
1057
+ rp += step;
1058
+ size -= step;
1059
+ if(size < tvsiz) break;
1060
+ tvbuf = rp;
1061
+ rp += tvsiz;
1062
+ size -= tvsiz;
1063
+ if(!vlput(tvilla, tkbuf, tksiz, tvbuf, tvsiz, VL_DDUP)) err = TRUE;
1064
+ }
1065
+ }
1066
+ free(vbuf);
1067
+ }
1068
+ }
1069
+ free(kbuf);
1070
+ }
1071
+ if(!vlclose(tvilla)) err = TRUE;
1072
+ if(!dpclose(depot)) err = TRUE;
1073
+ if(rename(path, name) == -1){
1074
+ if(!err) dpecodeset(DP_EMISC, __FILE__, __LINE__);
1075
+ err = TRUE;
1076
+ }
1077
+ return err ? FALSE : TRUE;
1078
+ }
1079
+
1080
+
1081
+ /* Dump all records as endian independent data. */
1082
+ int vlexportdb(VILLA *villa, const char *name){
1083
+ DEPOT *depot;
1084
+ char path[VL_PATHBUFSIZ], *kbuf, *vbuf, *nkey;
1085
+ int i, err, ksiz, vsiz, ki;
1086
+ assert(villa && name);
1087
+ sprintf(path, "%s%s", name, VL_TMPFSUF);
1088
+ if(!(depot = dpopen(path, DP_OWRITER | DP_OCREAT | DP_OTRUNC, -1))) return FALSE;
1089
+ err = FALSE;
1090
+ vlcurfirst(villa);
1091
+ for(i = 0; !err && (kbuf = vlcurkey(villa, &ksiz)) != NULL; i++){
1092
+ if((vbuf = vlcurval(villa, &vsiz)) != NULL){
1093
+ nkey = cbmalloc(ksiz + VL_NUMBUFSIZ);
1094
+ ki = sprintf(nkey, "%X\t", i);
1095
+ memcpy(nkey + ki, kbuf, ksiz);
1096
+ if(!dpput(depot, nkey, ki + ksiz, vbuf, vsiz, DP_DKEEP)) err = TRUE;
1097
+ free(nkey);
1098
+ free(vbuf);
1099
+ } else {
1100
+ err = TRUE;
1101
+ }
1102
+ free(kbuf);
1103
+ vlcurnext(villa);
1104
+ }
1105
+ if(!dpexportdb(depot, name)) err = TRUE;
1106
+ if(!dpclose(depot)) err = TRUE;
1107
+ if(!dpremove(path)) err = TRUE;
1108
+ return !err && !vlfatalerror(villa);
1109
+ }
1110
+
1111
+
1112
+ /* Load all records from endian independent data. */
1113
+ int vlimportdb(VILLA *villa, const char *name){
1114
+ DEPOT *depot;
1115
+ char path[VL_PATHBUFSIZ], *kbuf, *vbuf, *rp;
1116
+ int err, ksiz, vsiz;
1117
+ assert(villa && name);
1118
+ if(!villa->wmode){
1119
+ dpecodeset(DP_EMODE, __FILE__, __LINE__);
1120
+ return FALSE;
1121
+ }
1122
+ if(vlrnum(villa) > 0){
1123
+ dpecodeset(DP_EMISC, __FILE__, __LINE__);
1124
+ return FALSE;
1125
+ }
1126
+ kbuf = dpname(villa->depot);
1127
+ sprintf(path, "%s%s", kbuf, VL_TMPFSUF);
1128
+ free(kbuf);
1129
+ if(!(depot = dpopen(path, DP_OWRITER | DP_OCREAT | DP_OTRUNC, -1))) return FALSE;
1130
+ err = FALSE;
1131
+ if(!dpimportdb(depot, name)) err = TRUE;
1132
+ dpiterinit(depot);
1133
+ while(!err && (kbuf = dpiternext(depot, &ksiz)) != NULL){
1134
+ if((vbuf = dpget(depot, kbuf, ksiz, 0, -1, &vsiz)) != NULL){
1135
+ if((rp = strchr(kbuf, '\t')) != NULL){
1136
+ rp++;
1137
+ if(!vlput(villa, rp, ksiz - (rp - kbuf), vbuf, vsiz, VL_DDUP)) err = TRUE;
1138
+ } else {
1139
+ dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
1140
+ err = TRUE;
1141
+ }
1142
+ free(vbuf);
1143
+ } else {
1144
+ err = TRUE;
1145
+ }
1146
+ free(kbuf);
1147
+ }
1148
+ if(!dpclose(depot)) err = TRUE;
1149
+ if(!dpremove(path)) err = TRUE;
1150
+ return !err && !vlfatalerror(villa);
1151
+ }
1152
+
1153
+
1154
+
1155
+ /*************************************************************************************************
1156
+ * private objects
1157
+ *************************************************************************************************/
1158
+
1159
+
1160
+ /* Compare keys of two records by lexical order.
1161
+ `aptr' specifies the pointer to the region of one key.
1162
+ `asiz' specifies the size of the region of one key.
1163
+ `bptr' specifies the pointer to the region of the other key.
1164
+ `bsiz' specifies the size of the region of the other key.
1165
+ The return value is positive if the former is big, negative if the latter is big, 0 if both
1166
+ are equivalent. */
1167
+ static int vllexcompare(const char *aptr, int asiz, const char *bptr, int bsiz){
1168
+ int i, min;
1169
+ assert(aptr && asiz >= 0 && bptr && bsiz >= 0);
1170
+ min = asiz < bsiz ? asiz : bsiz;
1171
+ for(i = 0; i < min; i++){
1172
+ if(((unsigned char *)aptr)[i] != ((unsigned char *)bptr)[i])
1173
+ return ((unsigned char *)aptr)[i] - ((unsigned char *)bptr)[i];
1174
+ }
1175
+ if(asiz == bsiz) return 0;
1176
+ return asiz - bsiz;
1177
+ }
1178
+
1179
+
1180
+ /* Compare keys of two records as native integers.
1181
+ `aptr' specifies the pointer to the region of one key.
1182
+ `asiz' specifies the size of the region of one key.
1183
+ `bptr' specifies the pointer to the region of the other key.
1184
+ `bsiz' specifies the size of the region of the other key.
1185
+ The return value is positive if the former is big, negative if the latter is big, 0 if both
1186
+ are equivalent. */
1187
+ static int vlintcompare(const char *aptr, int asiz, const char *bptr, int bsiz){
1188
+ int anum, bnum;
1189
+ assert(aptr && asiz >= 0 && bptr && bsiz >= 0);
1190
+ if(asiz != bsiz) return asiz - bsiz;
1191
+ anum = (asiz == sizeof(int) ? *(int *)aptr : INT_MIN);
1192
+ bnum = (bsiz == sizeof(int) ? *(int *)bptr : INT_MIN);
1193
+ return anum - bnum;
1194
+ }
1195
+
1196
+
1197
+ /* Compare keys of two records as numbers of big endian.
1198
+ `aptr' specifies the pointer to the region of one key.
1199
+ `asiz' specifies the size of the region of one key.
1200
+ `bptr' specifies the pointer to the region of the other key.
1201
+ `bsiz' specifies the size of the region of the other key.
1202
+ The return value is positive if the former is big, negative if the latter is big, 0 if both
1203
+ are equivalent. */
1204
+ static int vlnumcompare(const char *aptr, int asiz, const char *bptr, int bsiz){
1205
+ int i;
1206
+ assert(aptr && asiz >= 0 && bptr && bsiz >= 0);
1207
+ if(asiz != bsiz) return asiz - bsiz;
1208
+ for(i = 0; i < asiz; i++){
1209
+ if(aptr[i] != bptr[i]) return aptr[i] - bptr[i];
1210
+ }
1211
+ return 0;
1212
+ }
1213
+
1214
+
1215
+ /* Compare keys of two records as numeric strings of octal, decimal or hexadecimal.
1216
+ `aptr' specifies the pointer to the region of one key.
1217
+ `asiz' specifies the size of the region of one key.
1218
+ `bptr' specifies the pointer to the region of the other key.
1219
+ `bsiz' specifies the size of the region of the other key.
1220
+ The return value is positive if the former is big, negative if the latter is big, 0 if both
1221
+ are equivalent. */
1222
+ static int vldeccompare(const char *aptr, int asiz, const char *bptr, int bsiz){
1223
+ assert(aptr && asiz >= 0 && bptr && bsiz >= 0);
1224
+ return (int)(strtod(aptr, NULL) - strtod(bptr, NULL));
1225
+ }
1226
+
1227
+
1228
+ /* Store a record composed of a pair of integers.
1229
+ `depot' specifies an internal database handle.
1230
+ `knum' specifies an integer of the key.
1231
+ `vnum' specifies an integer of the value.
1232
+ The return value is true if successful, else, it is false. */
1233
+ static int vldpputnum(DEPOT *depot, int knum, int vnum){
1234
+ assert(depot);
1235
+ return dpput(depot, (char *)&knum, sizeof(int), (char *)&vnum, sizeof(int), DP_DOVER);
1236
+ }
1237
+
1238
+
1239
+ /* Retrieve a record composed of a pair of integers.
1240
+ `depot' specifies an internal database handle.
1241
+ `knum' specifies an integer of the key.
1242
+ `vip' specifies the pointer to a variable to assign the result to.
1243
+ The return value is true if successful, else, it is false. */
1244
+ static int vldpgetnum(DEPOT *depot, int knum, int *vnp){
1245
+ char *vbuf;
1246
+ int vsiz;
1247
+ assert(depot && vnp);
1248
+ vbuf = dpget(depot, (char *)&knum, sizeof(int), 0, -1, &vsiz);
1249
+ if(!vbuf || vsiz != sizeof(int)){
1250
+ free(vbuf);
1251
+ return FALSE;
1252
+ }
1253
+ *vnp = *(int *)vbuf;
1254
+ free(vbuf);
1255
+ return TRUE;
1256
+ }
1257
+
1258
+
1259
+ /* Set a buffer for a variable length number.
1260
+ `buf' specifies the pointer to the buffer.
1261
+ `num' specifies the number.
1262
+ The return value is the size of valid region. */
1263
+ static int vlsetvnumbuf(char *buf, int num){
1264
+ div_t d;
1265
+ int len;
1266
+ assert(buf && num >= 0);
1267
+ if(num == 0){
1268
+ ((signed char *)buf)[0] = 0;
1269
+ return 1;
1270
+ }
1271
+ len = 0;
1272
+ while(num > 0){
1273
+ d = div(num, 128);
1274
+ num = d.quot;
1275
+ ((signed char *)buf)[len] = d.rem;
1276
+ if(num > 0) ((signed char *)buf)[len] = -(((signed char *)buf)[len]) - 1;
1277
+ len++;
1278
+ }
1279
+ return len;
1280
+ }
1281
+
1282
+
1283
+ /* Read a variable length buffer.
1284
+ `buf' specifies the pointer to the buffer.
1285
+ `size' specifies the limit size to read.
1286
+ `sp' specifies the pointer to a variable to which the size of the read region assigned.
1287
+ The return value is the value of the buffer. */
1288
+ static int vlreadvnumbuf(const char *buf, int size, int *sp){
1289
+ int i, num, base;
1290
+ assert(buf && size > 0 && sp);
1291
+ num = 0;
1292
+ base = 1;
1293
+ if(size < 2){
1294
+ *sp = 1;
1295
+ return ((signed char *)buf)[0];
1296
+ }
1297
+ for(i = 0; i < size; i++){
1298
+ if(((signed char *)buf)[i] >= 0){
1299
+ num += ((signed char *)buf)[i] * base;
1300
+ break;
1301
+ }
1302
+ num += base * (((signed char *)buf)[i] + 1) * -1;
1303
+ base *= 128;
1304
+ }
1305
+ *sp = i + 1;
1306
+ return num;
1307
+ }
1308
+
1309
+
1310
+ /* Create a new leaf.
1311
+ `villa' specifies a database handle.
1312
+ `prev' specifies the ID number of the previous leaf.
1313
+ `next' specifies the ID number of the previous leaf.
1314
+ The return value is a handle of the leaf. */
1315
+ static VLLEAF *vlleafnew(VILLA *villa, int prev, int next){
1316
+ VLLEAF lent;
1317
+ assert(villa);
1318
+ lent.id = villa->lnum + VL_LEAFIDMIN;
1319
+ lent.dirty = TRUE;
1320
+ lent.recs = cblistopen();
1321
+ lent.prev = prev;
1322
+ lent.next = next;
1323
+ villa->lnum++;
1324
+ cbmapput(villa->leafc, (char *)&(lent.id), sizeof(int), (char *)&lent, sizeof(VLLEAF), TRUE);
1325
+ return (VLLEAF *)cbmapget(villa->leafc, (char *)&(lent.id), sizeof(int), NULL);
1326
+ }
1327
+
1328
+
1329
+ /* Remove a leaf from the cache.
1330
+ `villa' specifies a database handle.
1331
+ `id' specifies the ID number of the leaf.
1332
+ The return value is true if successful, else, it is false. */
1333
+ static int vlleafcacheout(VILLA *villa, int id){
1334
+ VLLEAF *leaf;
1335
+ VLREC *recp;
1336
+ int i, j, err, ln;
1337
+ assert(villa && id >= VL_LEAFIDMIN);
1338
+ if(!(leaf = (VLLEAF *)cbmapget(villa->leafc, (char *)&id, sizeof(int), NULL))) return FALSE;
1339
+ err = FALSE;
1340
+ if(leaf->dirty){
1341
+ if(!vlleafsave(villa, leaf)) err = TRUE;
1342
+ }
1343
+ ln = CB_LISTNUM(leaf->recs);
1344
+ for(i = 0; i < ln; i++){
1345
+ recp = (VLREC *)CB_LISTVAL(leaf->recs, i, NULL);
1346
+ cbdatumclose(recp->key);
1347
+ cbdatumclose(recp->first);
1348
+ if(recp->rest){
1349
+ for(j = 0; j < CB_LISTNUM(recp->rest); j++){
1350
+ free(cblistpop(recp->rest, NULL));
1351
+ }
1352
+ cblistclose(recp->rest);
1353
+ }
1354
+ }
1355
+ cblistclose(leaf->recs);
1356
+ cbmapout(villa->leafc, (char *)&id, sizeof(int));
1357
+ return err ? FALSE : TRUE;
1358
+ }
1359
+
1360
+
1361
+ /* Save a leaf into the database.
1362
+ `villa' specifies a database handle.
1363
+ `leaf' specifies a leaf handle.
1364
+ The return value is true if successful, else, it is false. */
1365
+ static int vlleafsave(VILLA *villa, VLLEAF *leaf){
1366
+ CBDATUM *buf;
1367
+ char vnumbuf[VL_VNUMBUFSIZ], *zbuf;
1368
+ const char *vbuf;
1369
+ VLREC *recp;
1370
+ int i, j, ksiz, vnum, vsiz, prev, next, vnumsiz, ln, zsiz;
1371
+ assert(villa && leaf);
1372
+ buf = cbdatumopen(NULL, 0);
1373
+ prev = leaf->prev;
1374
+ if(prev == -1) prev = VL_NODEIDMIN - 1;
1375
+ vnumsiz = vlsetvnumbuf(vnumbuf, prev);
1376
+ cbdatumcat(buf, vnumbuf, vnumsiz);
1377
+ next = leaf->next;
1378
+ if(next == -1) next = VL_NODEIDMIN - 1;
1379
+ vnumsiz = vlsetvnumbuf(vnumbuf, next);
1380
+ cbdatumcat(buf, vnumbuf, vnumsiz);
1381
+ ln = CB_LISTNUM(leaf->recs);
1382
+ for(i = 0; i < ln; i++){
1383
+ recp = (VLREC *)CB_LISTVAL(leaf->recs, i, NULL);
1384
+ ksiz = CB_DATUMSIZE(recp->key);
1385
+ vnumsiz = vlsetvnumbuf(vnumbuf, ksiz);
1386
+ cbdatumcat(buf, vnumbuf, vnumsiz);
1387
+ cbdatumcat(buf, CB_DATUMPTR(recp->key), ksiz);
1388
+ vnum = 1 + (recp->rest ? CB_LISTNUM(recp->rest) : 0);
1389
+ vnumsiz = vlsetvnumbuf(vnumbuf, vnum);
1390
+ cbdatumcat(buf, vnumbuf, vnumsiz);
1391
+ vsiz = CB_DATUMSIZE(recp->first);
1392
+ vnumsiz = vlsetvnumbuf(vnumbuf, vsiz);
1393
+ cbdatumcat(buf, vnumbuf, vnumsiz);
1394
+ cbdatumcat(buf, CB_DATUMPTR(recp->first), vsiz);
1395
+ if(recp->rest){
1396
+ for(j = 0; j < CB_LISTNUM(recp->rest); j++){
1397
+ vbuf = cblistval(recp->rest, j, &vsiz);
1398
+ vnumsiz = vlsetvnumbuf(vnumbuf, vsiz);
1399
+ cbdatumcat(buf, vnumbuf, vnumsiz);
1400
+ cbdatumcat(buf, vbuf, vsiz);
1401
+ }
1402
+ }
1403
+ }
1404
+ if(_qdbm_deflate && villa->zmode){
1405
+ if(!(zbuf = _qdbm_deflate(CB_DATUMPTR(buf), CB_DATUMSIZE(buf), &zsiz))){
1406
+ cbdatumclose(buf);
1407
+ if(dpecode == DP_EMODE) dpecodeset(DP_EMISC, __FILE__, __LINE__);
1408
+ return FALSE;
1409
+ }
1410
+ villa->avglsiz = (villa->avglsiz * 9 + zsiz) / 10;
1411
+ if(!dpsetalign(villa->depot, (int)(villa->avglsiz * VL_ALIGNRATIO)) ||
1412
+ !dpput(villa->depot, (char *)&(leaf->id), sizeof(int), zbuf, zsiz, DP_DOVER)){
1413
+ cbdatumclose(buf);
1414
+ if(dpecode == DP_EMODE) dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
1415
+ return FALSE;
1416
+ }
1417
+ free(zbuf);
1418
+ } else {
1419
+ villa->avglsiz = (villa->avglsiz * 9 + CB_DATUMSIZE(buf)) / 10;
1420
+ if(!dpsetalign(villa->depot, (int)(villa->avglsiz * VL_ALIGNRATIO)) ||
1421
+ !dpput(villa->depot, (char *)&(leaf->id), sizeof(int),
1422
+ CB_DATUMPTR(buf), CB_DATUMSIZE(buf), DP_DOVER)){
1423
+ cbdatumclose(buf);
1424
+ if(dpecode == DP_EMODE) dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
1425
+ return FALSE;
1426
+ }
1427
+ }
1428
+ cbdatumclose(buf);
1429
+ leaf->dirty = FALSE;
1430
+ return TRUE;
1431
+ }
1432
+
1433
+
1434
+ /* Load a leaf from the database.
1435
+ `villa' specifies a database handle.
1436
+ `id' specifies the ID number of the leaf.
1437
+ If successful, the return value is the pointer to the leaf, else, it is `NULL'. */
1438
+ static VLLEAF *vlleafload(VILLA *villa, int id){
1439
+ char *buf, *rp, *kbuf, *vbuf, *zbuf;
1440
+ int i, size, step, ksiz, vnum, vsiz, prev, next, zsiz;
1441
+ VLLEAF *leaf, lent;
1442
+ VLREC rec;
1443
+ assert(villa && id >= VL_LEAFIDMIN);
1444
+ if((leaf = (VLLEAF *)cbmapget(villa->leafc, (char *)&id, sizeof(int), NULL)) != NULL){
1445
+ cbmapmove(villa->leafc, (char *)&id, sizeof(int), FALSE);
1446
+ return leaf;
1447
+ }
1448
+ ksiz = -1;
1449
+ prev = -1;
1450
+ next = -1;
1451
+ if(!(buf = dpget(villa->depot, (char *)&id, sizeof(int), 0, -1, &size))){
1452
+ dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
1453
+ return NULL;
1454
+ }
1455
+ if(_qdbm_inflate && villa->zmode){
1456
+ if(!(zbuf = _qdbm_inflate(buf, size, &zsiz))){
1457
+ dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
1458
+ free(buf);
1459
+ return NULL;
1460
+ }
1461
+ free(buf);
1462
+ buf = zbuf;
1463
+ size = zsiz;
1464
+ }
1465
+ rp = buf;
1466
+ if(size >= 1){
1467
+ prev = vlreadvnumbuf(rp, size, &step);
1468
+ rp += step;
1469
+ size -= step;
1470
+ if(prev >= VL_NODEIDMIN - 1) prev = -1;
1471
+ }
1472
+ if(size >= 1){
1473
+ next = vlreadvnumbuf(rp, size, &step);
1474
+ rp += step;
1475
+ size -= step;
1476
+ if(next >= VL_NODEIDMIN - 1) next = -1;
1477
+ }
1478
+ lent.id = id;
1479
+ lent.dirty = FALSE;
1480
+ lent.recs = cblistopen();
1481
+ lent.prev = prev;
1482
+ lent.next = next;
1483
+ while(size >= 1){
1484
+ ksiz = vlreadvnumbuf(rp, size, &step);
1485
+ rp += step;
1486
+ size -= step;
1487
+ if(size < ksiz) break;
1488
+ kbuf = rp;
1489
+ rp += ksiz;
1490
+ size -= ksiz;
1491
+ vnum = vlreadvnumbuf(rp, size, &step);
1492
+ rp += step;
1493
+ size -= step;
1494
+ if(vnum < 1 || size < 1) break;
1495
+ for(i = 0; i < vnum && size >= 1; i++){
1496
+ vsiz = vlreadvnumbuf(rp, size, &step);
1497
+ rp += step;
1498
+ size -= step;
1499
+ if(size < vsiz) break;
1500
+ vbuf = rp;
1501
+ rp += vsiz;
1502
+ size -= vsiz;
1503
+ if(i < 1){
1504
+ rec.key = cbdatumopen(kbuf, ksiz);
1505
+ rec.first = cbdatumopen(vbuf, vsiz);
1506
+ rec.rest = NULL;
1507
+ } else {
1508
+ if(!rec.rest) rec.rest = cblistopen();
1509
+ cblistpush(rec.rest, vbuf, vsiz);
1510
+ }
1511
+ }
1512
+ if(i > 0) cblistpush(lent.recs, (char *)&rec, sizeof(VLREC));
1513
+ }
1514
+ free(buf);
1515
+ cbmapput(villa->leafc, (char *)&(lent.id), sizeof(int), (char *)&lent, sizeof(VLLEAF), TRUE);
1516
+ return (VLLEAF *)cbmapget(villa->leafc, (char *)&(lent.id), sizeof(int), NULL);
1517
+ }
1518
+
1519
+
1520
+ /* Add a record to a leaf.
1521
+ `villa' specifies a database handle.
1522
+ `leaf' specifies a leaf handle.
1523
+ `dmode' specifies behavior when the key overlaps.
1524
+ `kbuf' specifies the pointer to the region of a key.
1525
+ `ksiz' specifies the size of the region of the key.
1526
+ `vbuf' specifies the pointer to the region of a value.
1527
+ `vsiz' specifies the size of the region of the value.
1528
+ The return value is true if successful, else, it is false. */
1529
+ static int vlleafaddrec(VILLA *villa, VLLEAF *leaf, int dmode,
1530
+ const char *kbuf, int ksiz, const char *vbuf, int vsiz){
1531
+ VLREC *recp, rec;
1532
+ int i, rv, left, right, ln;
1533
+ assert(villa && leaf && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
1534
+ left = 0;
1535
+ ln = CB_LISTNUM(leaf->recs);
1536
+ right = ln;
1537
+ i = (left + right) / 2;
1538
+ while(right >= left && i < ln){
1539
+ recp = (VLREC *)CB_LISTVAL(leaf->recs, i, NULL);
1540
+ rv = villa->cmp(kbuf, ksiz, CB_DATUMPTR(recp->key), CB_DATUMSIZE(recp->key));
1541
+ if(rv == 0){
1542
+ break;
1543
+ } else if(rv <= 0){
1544
+ right = i - 1;
1545
+ } else {
1546
+ left = i + 1;
1547
+ }
1548
+ i = (left + right) / 2;
1549
+ }
1550
+ while(i < ln){
1551
+ recp = (VLREC *)CB_LISTVAL(leaf->recs, i, NULL);
1552
+ rv = villa->cmp(kbuf, ksiz, CB_DATUMPTR(recp->key), CB_DATUMSIZE(recp->key));
1553
+ if(rv == 0){
1554
+ switch(dmode){
1555
+ case VL_DOVER:
1556
+ cbdatumclose(recp->first);
1557
+ recp->first = cbdatumopen(vbuf, vsiz);
1558
+ break;
1559
+ case VL_DKEEP:
1560
+ return FALSE;
1561
+ default:
1562
+ if(!recp->rest) recp->rest = cblistopen();
1563
+ cblistpush(recp->rest, vbuf, vsiz);
1564
+ villa->rnum++;
1565
+ break;
1566
+ }
1567
+ break;
1568
+ } else if(rv < 0){
1569
+ rec.key = cbdatumopen(kbuf, ksiz);
1570
+ rec.first = cbdatumopen(vbuf, vsiz);
1571
+ rec.rest = NULL;
1572
+ cblistinsert(leaf->recs, i, (char *)&rec, sizeof(VLREC));
1573
+ villa->rnum++;
1574
+ break;
1575
+ }
1576
+ i++;
1577
+ }
1578
+ if(i >= ln){
1579
+ rec.key = cbdatumopen(kbuf, ksiz);
1580
+ rec.first = cbdatumopen(vbuf, vsiz);
1581
+ rec.rest = NULL;
1582
+ cblistpush(leaf->recs, (char *)&rec, sizeof(VLREC));
1583
+ villa->rnum++;
1584
+ }
1585
+ leaf->dirty = TRUE;
1586
+ return TRUE;
1587
+ }
1588
+
1589
+
1590
+ /* Divide a leaf into two.
1591
+ `villa' specifies a database handle.
1592
+ `leaf' specifies a leaf handle.
1593
+ The return value is the handle of a new leaf, or `NULL' on failure. */
1594
+ static VLLEAF *vlleafdivide(VILLA *villa, VLLEAF *leaf){
1595
+ VLLEAF *newleaf, *nextleaf;
1596
+ VLREC *recp;
1597
+ int i, mid, ln;
1598
+ assert(villa && leaf);
1599
+ mid = CB_LISTNUM(leaf->recs) / 2;
1600
+ recp = (VLREC *)CB_LISTVAL(leaf->recs, mid, NULL);
1601
+ newleaf = vlleafnew(villa, leaf->id, leaf->next);
1602
+ if(newleaf->next != -1){
1603
+ if(!(nextleaf = vlleafload(villa, newleaf->next))) return NULL;
1604
+ nextleaf->prev = newleaf->id;
1605
+ nextleaf->dirty = TRUE;
1606
+ }
1607
+ leaf->next = newleaf->id;
1608
+ leaf->dirty = TRUE;
1609
+ ln = CB_LISTNUM(leaf->recs);
1610
+ for(i = mid; i < ln; i++){
1611
+ recp = (VLREC *)CB_LISTVAL(leaf->recs, i, NULL);
1612
+ cblistpush(newleaf->recs, (char *)recp, sizeof(VLREC));
1613
+ }
1614
+ ln = CB_LISTNUM(newleaf->recs);
1615
+ for(i = 0; i < ln; i++){
1616
+ free(cblistpop(leaf->recs, NULL));
1617
+ }
1618
+ return newleaf;
1619
+ }
1620
+
1621
+
1622
+ /* Create a new node.
1623
+ `villa' specifies a database handle.
1624
+ `id' specifies the ID number of the node.
1625
+ The return value is a handle of the node. */
1626
+ static VLNODE *vlnodenew(VILLA *villa, int heir){
1627
+ VLNODE nent;
1628
+ assert(villa && heir >= VL_LEAFIDMIN);
1629
+ nent.id = villa->nnum + VL_NODEIDMIN;
1630
+ nent.dirty = TRUE;
1631
+ nent.heir = heir;
1632
+ nent.idxs = cblistopen();
1633
+ villa->nnum++;
1634
+ cbmapput(villa->nodec, (char *)&(nent.id), sizeof(int), (char *)&nent, sizeof(VLNODE), TRUE);
1635
+ return (VLNODE *)cbmapget(villa->nodec, (char *)&(nent.id), sizeof(int), NULL);
1636
+ }
1637
+
1638
+
1639
+ /* Remove a node from the cache.
1640
+ `villa' specifies a database handle.
1641
+ `id' specifies the ID number of the node.
1642
+ The return value is true if successful, else, it is false. */
1643
+ static int vlnodecacheout(VILLA *villa, int id){
1644
+ VLNODE *node;
1645
+ VLIDX *idxp;
1646
+ int i, err, ln;
1647
+ assert(villa && id >= VL_NODEIDMIN);
1648
+ if(!(node = (VLNODE *)cbmapget(villa->nodec, (char *)&id, sizeof(int), NULL))) return FALSE;
1649
+ err = FALSE;
1650
+ if(node->dirty){
1651
+ if(!vlnodesave(villa, node)) err = TRUE;
1652
+ }
1653
+ ln = CB_LISTNUM(node->idxs);
1654
+ for(i = 0; i < ln; i++){
1655
+ idxp = (VLIDX *)CB_LISTVAL(node->idxs, i, NULL);
1656
+ cbdatumclose(idxp->key);
1657
+ }
1658
+ cblistclose(node->idxs);
1659
+ cbmapout(villa->nodec, (char *)&id, sizeof(int));
1660
+ return err ? FALSE : TRUE;
1661
+ }
1662
+
1663
+
1664
+ /* Save a node into the database.
1665
+ `villa' specifies a database handle.
1666
+ `node' specifies a node handle.
1667
+ The return value is true if successful, else, it is false. */
1668
+ static int vlnodesave(VILLA *villa, VLNODE *node){
1669
+ CBDATUM *buf;
1670
+ char vnumbuf[VL_VNUMBUFSIZ];
1671
+ VLIDX *idxp;
1672
+ int i, heir, pid, ksiz, vnumsiz, ln;
1673
+ assert(villa && node);
1674
+ buf = cbdatumopen(NULL, 0);
1675
+ heir = node->heir;
1676
+ vnumsiz = vlsetvnumbuf(vnumbuf, heir);
1677
+ cbdatumcat(buf, vnumbuf, vnumsiz);
1678
+ ln = CB_LISTNUM(node->idxs);
1679
+ for(i = 0; i < ln; i++){
1680
+ idxp = (VLIDX *)CB_LISTVAL(node->idxs, i, NULL);
1681
+ pid = idxp->pid;
1682
+ vnumsiz = vlsetvnumbuf(vnumbuf, pid);
1683
+ cbdatumcat(buf, vnumbuf, vnumsiz);
1684
+ ksiz = CB_DATUMSIZE(idxp->key);
1685
+ vnumsiz = vlsetvnumbuf(vnumbuf, ksiz);
1686
+ cbdatumcat(buf, vnumbuf, vnumsiz);
1687
+ cbdatumcat(buf, CB_DATUMPTR(idxp->key), ksiz);
1688
+ }
1689
+ villa->avgnsiz = (villa->avgnsiz * 9 + CB_DATUMSIZE(buf)) / 10;
1690
+ if(!dpsetalign(villa->depot, (int)(villa->avgnsiz * VL_ALIGNRATIO)) ||
1691
+ !dpput(villa->depot, (char *)&(node->id), sizeof(int),
1692
+ CB_DATUMPTR(buf), CB_DATUMSIZE(buf), DP_DOVER)){
1693
+ cbdatumclose(buf);
1694
+ if(dpecode == DP_EMODE) dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
1695
+ return FALSE;
1696
+ }
1697
+ cbdatumclose(buf);
1698
+ node->dirty = FALSE;
1699
+ return TRUE;
1700
+ }
1701
+
1702
+
1703
+ /* Load a node from the database.
1704
+ `villa' specifies a database handle.
1705
+ `id' specifies the ID number of the node.
1706
+ If successful, the return value is the pointer to the node, else, it is `NULL'. */
1707
+ static VLNODE *vlnodeload(VILLA *villa, int id){
1708
+ char *buf, *rp, *kbuf;
1709
+ int size, step, heir, pid, ksiz;
1710
+ VLNODE *node, nent;
1711
+ VLIDX idx;
1712
+ assert(villa && id >= VL_NODEIDMIN);
1713
+ if((node = (VLNODE *)cbmapget(villa->nodec, (char *)&id, sizeof(int), NULL)) != NULL){
1714
+ cbmapmove(villa->nodec, (char *)&id, sizeof(int), FALSE);
1715
+ return node;
1716
+ }
1717
+ heir = -1;
1718
+ if(!(buf = dpget(villa->depot, (char *)&id, sizeof(int), 0, -1, &size))) return NULL;
1719
+ rp = buf;
1720
+ if(size >= 1){
1721
+ heir = vlreadvnumbuf(rp, size, &step);
1722
+ rp += step;
1723
+ size -= step;
1724
+ }
1725
+ if(heir < 0){
1726
+ free(buf);
1727
+ return NULL;
1728
+ }
1729
+ nent.id = id;
1730
+ nent.dirty = FALSE;
1731
+ nent.heir = heir;
1732
+ nent.idxs = cblistopen();
1733
+ while(size >= 1){
1734
+ pid = vlreadvnumbuf(rp, size, &step);
1735
+ rp += step;
1736
+ size -= step;
1737
+ if(size < 1) break;
1738
+ ksiz = vlreadvnumbuf(rp, size, &step);
1739
+ rp += step;
1740
+ size -= step;
1741
+ if(size < ksiz) break;
1742
+ kbuf = rp;
1743
+ rp += ksiz;
1744
+ size -= ksiz;
1745
+ idx.pid = pid;
1746
+ idx.key = cbdatumopen(kbuf, ksiz);
1747
+ cblistpush(nent.idxs, (char *)&idx, sizeof(VLIDX));
1748
+ }
1749
+ free(buf);
1750
+ cbmapput(villa->nodec, (char *)&(nent.id), sizeof(int), (char *)&nent, sizeof(VLNODE), TRUE);
1751
+ return (VLNODE *)cbmapget(villa->nodec, (char *)&(nent.id), sizeof(int), NULL);
1752
+ }
1753
+
1754
+
1755
+ /* Add an index to a node.
1756
+ `villa' specifies a database handle.
1757
+ `node' specifies a node handle.
1758
+ `order' specifies whether the calling sequence is orderd or not.
1759
+ `pid' specifies the ID number of referred page.
1760
+ `kbuf' specifies the pointer to the region of a key.
1761
+ `ksiz' specifies the size of the region of the key. */
1762
+ static void vlnodeaddidx(VILLA *villa, VLNODE *node, int order,
1763
+ int pid, const char *kbuf, int ksiz){
1764
+ VLIDX idx, *idxp;
1765
+ int i, rv, left, right, ln;
1766
+ assert(villa && node && pid >= VL_LEAFIDMIN && kbuf && ksiz >= 0);
1767
+ idx.pid = pid;
1768
+ idx.key = cbdatumopen(kbuf, ksiz);
1769
+ if(order){
1770
+ cblistpush(node->idxs, (char *)&idx, sizeof(VLIDX));
1771
+ } else {
1772
+ left = 0;
1773
+ right = CB_LISTNUM(node->idxs);
1774
+ i = (left + right) / 2;
1775
+ ln = CB_LISTNUM(node->idxs);
1776
+ while(right >= left && i < ln){
1777
+ idxp = (VLIDX *)CB_LISTVAL(node->idxs, i, NULL);
1778
+ rv = villa->cmp(kbuf, ksiz, CB_DATUMPTR(idxp->key), CB_DATUMSIZE(idxp->key));
1779
+ if(rv == 0){
1780
+ break;
1781
+ } else if(rv <= 0){
1782
+ right = i - 1;
1783
+ } else {
1784
+ left = i + 1;
1785
+ }
1786
+ i = (left + right) / 2;
1787
+ }
1788
+ ln = CB_LISTNUM(node->idxs);
1789
+ while(i < ln){
1790
+ idxp = (VLIDX *)CB_LISTVAL(node->idxs, i, NULL);
1791
+ if(villa->cmp(kbuf, ksiz, CB_DATUMPTR(idxp->key), CB_DATUMSIZE(idxp->key)) < 0){
1792
+ cblistinsert(node->idxs, i, (char *)&idx, sizeof(VLIDX));
1793
+ break;
1794
+ }
1795
+ i++;
1796
+ }
1797
+ if(i >= CB_LISTNUM(node->idxs)) cblistpush(node->idxs, (char *)&idx, sizeof(VLIDX));
1798
+ }
1799
+ node->dirty = TRUE;
1800
+ }
1801
+
1802
+
1803
+ /* Search the leaf corresponding to a key.
1804
+ `villa' specifies a database handle.
1805
+ `kbuf' specifies the pointer to the region of a key.
1806
+ `ksiz' specifies the size of the region of the key.
1807
+ `hist' specifies an array history of visited nodes. If `NULL', it is not used.
1808
+ `hnp' specifies the pointer to a variable to which the number of elements of the history
1809
+ assigned. If `NULL', it is not used.
1810
+ The return value is the ID number of the leaf, or -1 on failure. */
1811
+ static int vlsearchleaf(VILLA *villa, const char *kbuf, int ksiz, int *hist, int *hnp){
1812
+ VLNODE *node;
1813
+ VLIDX *idxp;
1814
+ int i, pid, level, rv, left, right, ln;
1815
+ assert(villa && kbuf && ksiz >= 0);
1816
+ pid = villa->root;
1817
+ idxp = NULL;
1818
+ level = 0;
1819
+ while(pid >= VL_NODEIDMIN){
1820
+ if(!(node = vlnodeload(villa, pid)) || (ln = CB_LISTNUM(node->idxs)) < 1){
1821
+ dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
1822
+ if(hnp) *hnp = level;
1823
+ return -1;
1824
+ }
1825
+ if(hist) hist[level++] = node->id;
1826
+ left = 1;
1827
+ right = ln;
1828
+ i = (left + right) / 2;
1829
+ while(right >= left && i < ln){
1830
+ idxp = (VLIDX *)CB_LISTVAL(node->idxs, i, NULL);
1831
+ rv = villa->cmp(kbuf, ksiz, CB_DATUMPTR(idxp->key), CB_DATUMSIZE(idxp->key));
1832
+ if(rv == 0){
1833
+ break;
1834
+ } else if(rv <= 0){
1835
+ right = i - 1;
1836
+ } else {
1837
+ left = i + 1;
1838
+ }
1839
+ i = (left + right) / 2;
1840
+ }
1841
+ if(i > 0) i--;
1842
+ while(i < ln){
1843
+ idxp = (VLIDX *)CB_LISTVAL(node->idxs, i, NULL);
1844
+ if(villa->cmp(kbuf, ksiz, CB_DATUMPTR(idxp->key), CB_DATUMSIZE(idxp->key)) < 0){
1845
+ if(i == 0){
1846
+ pid = node->heir;
1847
+ break;
1848
+ }
1849
+ idxp = (VLIDX *)CB_LISTVAL(node->idxs, i - 1, NULL);
1850
+ pid = idxp->pid;
1851
+ break;
1852
+ }
1853
+ i++;
1854
+ }
1855
+ if(i >= ln) pid = idxp->pid;
1856
+ }
1857
+ if(hnp) *hnp = level;
1858
+ return pid;
1859
+ }
1860
+
1861
+
1862
+ /* Adjust the caches for leaves and nodes.
1863
+ `villa' specifies a database handle.
1864
+ The return value is true if successful, else, it is false. */
1865
+ static int vlcacheadjust(VILLA *villa){
1866
+ const char *tmp;
1867
+ int i, pid, err;
1868
+ err = FALSE;
1869
+ if(cbmaprnum(villa->leafc) > villa->leafcnum){
1870
+ cbmapiterinit(villa->leafc);
1871
+ for(i = 0; i < VL_CACHEOUT; i++){
1872
+ tmp = cbmapiternext(villa->leafc, NULL);
1873
+ pid = *(int *)tmp;
1874
+ if(!vlleafcacheout(villa, pid)) err = TRUE;
1875
+ }
1876
+ }
1877
+ if(cbmaprnum(villa->nodec) > villa->nodecnum){
1878
+ cbmapiterinit(villa->nodec);
1879
+ for(i = 0; i < VL_CACHEOUT; i++){
1880
+ tmp = cbmapiternext(villa->nodec, NULL);
1881
+ pid = *(int *)tmp;
1882
+ if(!vlnodecacheout(villa, pid)) err = TRUE;
1883
+ }
1884
+ }
1885
+ return err ? FALSE : TRUE;
1886
+ }
1887
+
1888
+
1889
+ /* Search a record of a leaf.
1890
+ `villa' specifies a database handle.
1891
+ `leaf' specifies a leaf handle.
1892
+ `kbuf' specifies the pointer to the region of a key.
1893
+ `ksiz' specifies the size of the region of the key.
1894
+ `ip' specifies the pointer to a variable to fetch the index of the correspnding record.
1895
+ The return value is the pointer to a corresponding record, or `NULL' on failure. */
1896
+ static VLREC *vlrecsearch(VILLA *villa, VLLEAF *leaf, const char *kbuf, int ksiz, int *ip){
1897
+ int i, rv, left, right, ln;
1898
+ VLREC *recp;
1899
+ assert(villa && leaf && kbuf && ksiz >= 0);
1900
+ ln = CB_LISTNUM(leaf->recs);
1901
+ left = 0;
1902
+ right = ln;
1903
+ i = (left + right) / 2;
1904
+ while(right >= left && i < ln){
1905
+ recp = (VLREC *)CB_LISTVAL(leaf->recs, i, NULL);
1906
+ rv = villa->cmp(kbuf, ksiz, CB_DATUMPTR(recp->key), CB_DATUMSIZE(recp->key));
1907
+ if(rv == 0){
1908
+ if(ip) *ip = i;
1909
+ return recp;
1910
+ } else if(rv <= 0){
1911
+ right = i - 1;
1912
+ } else {
1913
+ left = i + 1;
1914
+ }
1915
+ i = (left + right) / 2;
1916
+ }
1917
+ if(ip) *ip = i;
1918
+ return NULL;
1919
+ }
1920
+
1921
+
1922
+
1923
+ /* END OF FILE */