File Coverage

CDB_File.xs
Criterion Covered Total %
statement 316 329 96.0
branch 183 272 67.2
condition n/a
subroutine n/a
pod n/a
total 499 601 83.0


line stmt bran cond sub pod time code
1             /*
2              
3             Most of this is reasonably straightforward. The complications arise
4             when we are "iterating" over the CDB file, that is to say, using `keys'
5             or `values' or `each' to retrieve all the data in the file in order.
6             This interface stores extra data to allow us to track iterations: end
7             is a pointer to the end of data in the CDB file, and also a flag which
8             indicates whether we are iterating or not (note that the end of data
9             occurs at a position >= 2048); curkey is a copy of the current key;
10             curpos is the file offset of curkey; and fetch_advance is 0 for
11              
12             FIRSTKEY, fetch, NEXTKEY, fetch, NEXTKEY, fetch, ...
13              
14             but 1 for
15              
16             FIRSTKEY, NEXTKEY, NEXTKEY, ..., fetch, fetch, fetch, ...
17              
18             Don't tell the OO Police, but there are actually two different objects
19             called CDB_File. One is created by TIEHASH, and accessed by the usual
20             tied hash methods (FETCH, FIRSTKEY, etc.). The other is created by new,
21             and accessed by insert and finish.
22              
23             In both cases, the object is a blessed reference to a scalar. The
24             scalar contains either a struct cdbobj or a struct cdbmakeobj.
25              
26             It gets a little messy in DESTROY: since this method will automatically
27             be called for both sorts of object, it distinguishes them by their
28             different sizes.
29              
30             */
31              
32             #ifdef __cplusplus
33             extern "C" {
34             #endif
35              
36             #include "EXTERN.h"
37             #include "perl.h"
38             #include "XSUB.h"
39             #include "ppport.h"
40              
41             #include
42             #include
43             #include
44             #include
45             #include
46             #include
47              
48             #ifdef WIN32
49             #define fsync _commit
50             #endif
51              
52             #ifdef HASMMAP
53             #include
54             #endif
55              
56             /* We need to whistle up an error number for a file that is not a CDB
57             file. The BSDish EFTYPE probably gives the most useful error message;
58             failing that we'll settle for the Single Unix Specification v2 EPROTO;
59             and finally the rather inappropriate, but universally(?) implemented,
60             EINVAL. */
61             #ifdef EFTYPE
62             #else
63             #ifdef EPROTO
64             #define EFTYPE EPROTO
65             #else
66             #define EFTYPE EINVAL
67             #endif
68             #endif
69              
70             #ifdef __cplusplus
71             }
72             #endif
73              
74             #if defined(SV_COW_REFCNT_MAX)
75             # define CDB_CAN_COW 1
76             #else
77             # define CDB_CAN_COW 0
78             #endif
79              
80             #if CDB_CAN_COW
81             # define CDB_DO_COW(sv) STMT_START { SvIsCOW_on(sv); CowREFCNT(sv) = 1; } STMT_END
82             #else
83             # define CDB_DO_COW(sv)
84             #endif
85              
86             #define CDB_SET_PV(sv, len) STMT_START { \
87             (void) SvPOK_only(sv); \
88             SvGROW(sv, len + 2); \
89             SvCUR_set(sv, len); \
90             CDB_DO_COW(sv); \
91             SvPV(sv, PL_na)[len] = '\0'; \
92             } STMT_END
93              
94             struct t_cdb {
95             PerlIO *fh; /* */
96              
97             #ifdef HASMMAP
98             char *map;
99             #endif
100              
101             U32 end; /* If non zero, the file offset of the first byte of hash tables. */
102             SV *curkey; /* While iterating: a copy of the current key; */
103             U32 curpos; /* the file offset of the current record. */
104             int fetch_advance; /* the kludge */
105             U32 size; /* initialized if map is nonzero */
106             U32 loop; /* number of hash slots searched under this key */
107             U32 khash; /* initialized if loop is nonzero */
108             U32 kpos; /* initialized if loop is nonzero */
109             U32 hpos; /* initialized if loop is nonzero */
110             U32 hslots; /* initialized if loop is nonzero */
111             U32 dpos; /* initialized if cdb_findnext() returns 1 */
112             U32 dlen; /* initialized if cdb_findnext() returns 1 */
113             } ;
114              
115             typedef struct t_cdb cdb;
116              
117             #define CDB_HPLIST 1000
118              
119             struct cdb_hp { U32 h; U32 p; } ;
120              
121             struct cdb_hplist {
122             struct cdb_hp hp[CDB_HPLIST];
123             struct cdb_hplist *next;
124             int num;
125             } ;
126              
127             struct t_cdb_make {
128             PerlIO *f; /* Handle of file being created. */
129             char *fn; /* Final name of file. */
130             char *fntemp; /* Temporary name of file. */
131             char final[2048];
132             char bspace[1024];
133             U32 count[256];
134             U32 start[256];
135             struct cdb_hplist *head;
136             struct cdb_hp *split; /* includes space for hash */
137             struct cdb_hp *hash;
138             U32 numentries;
139             U32 pos;
140             int fd;
141             } ;
142              
143             typedef struct t_cdb_make cdb_make;
144              
145 0           static void writeerror() { croak("Write to CDB_File failed: %s", Strerror(errno)); }
146              
147 2           static void readerror() { croak("Read of CDB_File failed: %s", Strerror(errno)); }
148              
149 0           static void seekerror() { croak("Seek in CDB_File failed: %s", Strerror(errno)); }
150              
151 0           static void nomem() { croak("Out of memory!"); }
152              
153 10           static int cdb_make_start(cdb_make *c) {
154 10           c->head = 0;
155 10           c->split = 0;
156 10           c->hash = 0;
157 10           c->numentries = 0;
158 10           c->pos = sizeof c->final;
159 10           return PerlIO_seek(c->f, c->pos, SEEK_SET);
160             }
161              
162 215           static int posplus(cdb_make *c, U32 len) {
163 215           U32 newpos = c->pos + len;
164 215 50         if (newpos < len) { errno = ENOMEM; return -1; }
165 215           c->pos = newpos;
166 215           return 0;
167             }
168              
169 43           static int cdb_make_addend(cdb_make *c, unsigned int keylen, unsigned int datalen, U32 h) {
170             struct cdb_hplist *head;
171              
172 43           head = c->head;
173 43 100         if (!head || (head->num >= CDB_HPLIST)) {
    50          
174 9           New(0xCDB, head, 1, struct cdb_hplist);
175 9           head->num = 0;
176 9           head->next = c->head;
177 9           c->head = head;
178             }
179 43           head->hp[head->num].h = h;
180 43           head->hp[head->num].p = c->pos;
181 43           ++head->num;
182 43           ++c->numentries;
183 43 50         if (posplus(c, 8) == -1) return -1;
184 43 50         if (posplus(c, keylen) == -1) return -1;
185 43 50         if (posplus(c, datalen) == -1) return -1;
186 43           return 0;
187             }
188              
189             #define CDB_HASHSTART 5381
190              
191             #define cdb_hashadd(hh, cc) ((hh + (hh << 5)) ^ (unsigned char) cc)
192              
193 183           static U32 cdb_hash(char *buf, unsigned int len) {
194             U32 h;
195              
196 183           h = CDB_HASHSTART;
197 855 100         while (len) {
198 672           h = cdb_hashadd(h,*buf++);
199 672           --len;
200             }
201 183           return h;
202             }
203              
204 5378           static void uint32_pack(char s[4], U32 u) {
205 5378           s[0] = u & 255;
206 5378           u >>= 8;
207 5378           s[1] = u & 255;
208 5378           u >>= 8;
209 5378           s[2] = u & 255;
210 5378           s[3] = u >> 8;
211 5378           }
212              
213 2258           static void uint32_unpack(char s[4], U32 *u) {
214             U32 result;
215              
216 2258           result = (unsigned char) s[3];
217 2258           result <<= 8;
218 2258           result += (unsigned char) s[2];
219 2258           result <<= 8;
220 2258           result += (unsigned char) s[1];
221 2258           result <<= 8;
222 2258           result += (unsigned char) s[0];
223              
224 2258           *u = result;
225 2258           }
226              
227 140           static void cdb_findstart(cdb *c) {
228 140           c->loop = 0;
229 140           }
230              
231 2285           static int cdb_read(cdb *c, char *buf, unsigned int len, U32 pos) {
232              
233             #ifdef HASMMAP
234 2285 100         if (c->map) {
235 2284 50         if ((pos > c->size) || (c->size - pos < len)) {
    50          
236 0           errno = EFTYPE;
237 0           return -1;
238             }
239 2284           memcpy(buf, c->map + pos, len);
240 2284           return 0;
241             }
242             #endif
243              
244 1 50         if (PerlIO_seek(c->fh, pos, SEEK_SET) == -1) return -1;
245 1 50         while (len > 0) {
246             int r;
247             do
248 1           r = PerlIO_read(c->fh, buf, len);
249 1 50         while ((r == -1) && (errno == EINTR));
    0          
250 1 50         if (r == -1) return -1;
251 1 50         if (r == 0) {
252 1           errno = EFTYPE;
253 1           return -1;
254             }
255 0           buf += r;
256 0           len -= r;
257             }
258 0           return 0;
259             }
260              
261 140           static int match(cdb *c,char *key,unsigned int len, U32 pos) {
262             char buf[32];
263             int n;
264              
265 280 100         while (len > 0) {
266 140           n = sizeof buf;
267 140 50         if (n > len) n = len;
268 140 50         if (cdb_read(c, buf, n, pos) == -1) return -1;
269 140 50         if (memcmp(buf, key, n)) return 0;
270 140           pos += n;
271 140           key += n;
272 140           len -= n;
273             }
274 140           return 1;
275             }
276              
277 158           static int cdb_findnext(cdb *c,char *key,unsigned int len) {
278             char buf[8];
279             U32 pos;
280             U32 u;
281              
282             /* Matt: reset these so if a search fails they are zero'd */
283 158           c->dpos = 0;
284 158           c->dlen = 0;
285 158 100         if (!c->loop) {
286 140           u = cdb_hash(key,len);
287 140 100         if (cdb_read(c,buf,8,(u << 3) & 2047) == -1) return -1;
288 139           uint32_unpack(buf + 4,&c->hslots);
289 139 100         if (!c->hslots) return 0;
290 133           uint32_unpack(buf,&c->hpos);
291 133           c->khash = u;
292 133           u >>= 8;
293 133           u %= c->hslots;
294 133           u <<= 3;
295 133           c->kpos = c->hpos + u;
296             }
297              
298 151 50         while (c->loop < c->hslots) {
299 151 50         if (cdb_read(c,buf,8,c->kpos) == -1) return -1;
300 151           uint32_unpack(buf + 4,&pos);
301 151 100         if (!pos) return 0;
302 140           c->loop += 1;
303 140           c->kpos += 8;
304 140 100         if (c->kpos == c->hpos + (c->hslots << 3)) c->kpos = c->hpos;
305 140           uint32_unpack(buf,&u);
306 140 50         if (u == c->khash) {
307 140 50         if (cdb_read(c,buf,8,pos) == -1) return -1;
308 140           uint32_unpack(buf,&u);
309 140 50         if (u == len)
310 140           switch(match(c,key,len,pos + 8)) {
311             case -1:
312 0           return -1;
313             case 1:
314 140           uint32_unpack(buf + 4,&c->dlen);
315 140           c->dpos = pos + 8 + len;
316 140           return 1;
317             }
318             }
319             }
320              
321 158           return 0;
322             }
323              
324 8           static int cdb_find(cdb *c, char *key, unsigned int len) {
325 8           cdb_findstart(c);
326 8           return cdb_findnext(c,key,len);
327             }
328              
329 52           static void iter_start(cdb *c) {
330             char buf[4];
331              
332 52           c->curpos = 2048;
333 52 50         if (cdb_read(c, buf, 4, 0) == -1) readerror();
334 52           uint32_unpack(buf, &c->end);
335 52           c->curkey = NEWSV(0xcdb, 1);
336 52           c->fetch_advance = 0;
337 52           }
338              
339 451           static int iter_key(cdb *c) {
340             char buf[8];
341             U32 klen;
342              
343 451 100         if (c->curpos < c->end) {
344 407 50         if (cdb_read(c, buf, 8, c->curpos) == -1) readerror();
345 407           uint32_unpack(buf, &klen);
346              
347 407 100         CDB_SET_PV(c->curkey, klen);
    50          
    50          
348              
349 407 50         if (cdb_read(c, SvPVX(c->curkey), klen, c->curpos + 8) == -1) readerror();
350 407           return 1;
351             }
352 451           return 0;
353             }
354              
355 400           static void iter_advance(cdb *c) {
356             char buf[8];
357             U32 klen, dlen;
358              
359 400 50         if (cdb_read(c, buf, 8, c->curpos) == -1) readerror();
360 400           uint32_unpack(buf, &klen);
361 400           uint32_unpack(buf + 4, &dlen);
362 400           c->curpos += 8 + klen + dlen;
363 400           }
364              
365 36           static void iter_end(cdb *c) {
366 36 100         if (c->end != 0) {
367 30           c->end = 0;
368 30           SvREFCNT_dec(c->curkey);
369             }
370 36           }
371              
372             #define cdb_datapos(c) ((c)->dpos)
373             #define cdb_datalen(c) ((c)->dlen)
374              
375             typedef PerlIO * InputStream;
376              
377             MODULE = CDB_File PACKAGE = CDB_File PREFIX = cdb_
378              
379             PROTOTYPES: DISABLED
380              
381             # Some accessor methods.
382              
383             # WARNING: I don't really understand enough about Perl's guts (file
384             # handles / globs, etc.) to write this code. I think this is right, and
385             # it seems to work, but input from anybody with a deeper
386             # understanding would be most welcome.
387              
388             # Additional: fixed by someone with a deeper understanding ;-) (Matt Sergeant)
389              
390             InputStream
391             cdb_handle(this)
392             cdb * this
393              
394             PREINIT:
395             GV *gv;
396             char *packname;
397              
398             CODE:
399             /* here we dup the filehandle, because perl space will try and close
400             it when it goes out of scope */
401 1           RETVAL = PerlIO_fdopen(PerlIO_fileno(this->fh), "r");
402             OUTPUT:
403             RETVAL
404              
405             U32
406             cdb_datalen(db)
407             cdb * db
408              
409             CODE:
410 6           RETVAL = cdb_datalen(db);
411              
412             OUTPUT:
413             RETVAL
414              
415             U32
416             cdb_datapos(db)
417             cdb * db
418              
419             CODE:
420 6           RETVAL = cdb_datapos(db);
421              
422             OUTPUT:
423             RETVAL
424              
425             cdb *
426             cdb_TIEHASH(CLASS, filename)
427             char * CLASS
428             char * filename
429              
430             PREINIT:
431             PerlIO *f;
432             IO *io;
433             SV *cdbp;
434              
435             CODE:
436 13           New(0, RETVAL, 1, cdb);
437 13           RETVAL->fh = f = PerlIO_open(filename, "rb");
438 13 100         if (!f) XSRETURN_NO;
439 12           RETVAL->end = 0;
440             #ifdef HASMMAP
441             {
442             struct stat st;
443 12           int fd = PerlIO_fileno(f);
444              
445 12           RETVAL->map = 0;
446 12 50         if (fstat(fd, &st) == 0) {
447 12 50         if (st.st_size <= 0xffffffff) {
448             char *x;
449              
450 12           x = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
451 12 100         if (x != (char *)-1) {
452 11           RETVAL->size = st.st_size;
453 11           RETVAL->map = x;
454             }
455             }
456             }
457             }
458             #endif
459             OUTPUT:
460             RETVAL
461              
462             SV *
463             cdb_FETCH(this, k)
464             cdb * this
465             SV * k
466              
467             PREINIT:
468             PerlIO *f;
469             char buf[8];
470             int found;
471             off_t pos;
472             STRLEN klen, x;
473             U32 klen0;
474             char *kp;
475              
476             CODE:
477 167 100         if (!SvOK(k)) {
    50          
    50          
478 1           XSRETURN_UNDEF;
479             }
480 166 50         kp = SvPV(k, klen);
481 166 100         if (this->end && sv_eq(this->curkey, k)) {
    100          
482 156 50         if (cdb_read(this, buf, 8, this->curpos) == -1) readerror();
483 156           uint32_unpack(buf + 4, &this->dlen);
484 156           this->dpos = this->curpos + 8 + klen;
485 156 100         if (this->fetch_advance) {
486 126           iter_advance(this);
487 126 100         if (!iter_key(this)) iter_end(this);
488             }
489 156           found = 1;
490             } else {
491 10           cdb_findstart(this);
492 10           found = cdb_findnext(this, kp, klen);
493 10 100         if ((found != 0) && (found != 1)) readerror();
    100          
494             }
495 165           ST(0) = sv_newmortal();
496 165 100         if (found) {
497             U32 dlen;
498              
499 164 50         SvUPGRADE(ST(0), SVt_PV);
500 164           dlen = cdb_datalen(this);
501              
502 164 50         CDB_SET_PV(ST(0), dlen);
    50          
    50          
503              
504 164 50         if (cdb_read(this, SvPVX(ST(0)), dlen, cdb_datapos(this)) == -1) readerror();
505             }
506              
507              
508             HV *
509             cdb_fetch_all(this)
510             cdb * this
511              
512             PREINIT:
513             U32 dlen;
514             SV *keyvalue;
515             int found;
516             STRLEN klen;
517             char *kp;
518              
519             CODE:
520 11           RETVAL = newHV();
521 11           sv_2mortal((SV *)RETVAL);
522 11           iter_start(this);
523 121 100         while(iter_key(this)) {
524 110           cdb_findstart(this);
525 110 50         kp = SvPV(this->curkey, klen);
526 110           found = cdb_findnext(this, kp, klen);
527 110 50         if ((found != 0) && (found != 1)) readerror();
    50          
528              
529 110           dlen = cdb_datalen(this);
530              
531 110           keyvalue = newSVpvn("", 0);
532              
533 110 50         CDB_SET_PV(keyvalue, dlen);
    50          
    50          
534              
535 110 50         if (cdb_read(this, SvPVX(keyvalue), dlen, cdb_datapos(this)) == -1) readerror();
536              
537 110 50         if (! hv_store_ent(RETVAL, this->curkey, keyvalue, 0)) {
538 0           SvREFCNT_dec(keyvalue);
539             };
540 110           iter_advance(this);
541             }
542 11           iter_end(this);
543              
544             OUTPUT:
545             RETVAL
546              
547              
548             AV *
549             cdb_multi_get(this, k)
550             cdb * this
551             SV * k
552              
553             PREINIT:
554             PerlIO *f;
555             char buf[8];
556             int found;
557             off_t pos;
558             STRLEN klen;
559             U32 dlen, klen0;
560             char *kp;
561             SV *x;
562              
563             CODE:
564 12 50         if (!SvOK(k)) {
    0          
    0          
565 0           XSRETURN_UNDEF;
566             }
567 12           cdb_findstart(this);
568 12           RETVAL = newAV();
569 12           sv_2mortal((SV *)RETVAL);
570 12 100         kp = SvPV(k, klen);
571             for (;;) {
572 30           found = cdb_findnext(this, kp, klen);
573 30 100         if ((found != 0) && (found != 1)) readerror();
    50          
574 30 100         if (!found) break;
575              
576 18           dlen = cdb_datalen(this);
577 18           x = newSVpvn("", 0);
578              
579 18 50         CDB_SET_PV(x, dlen);
    50          
    50          
580              
581 18 50         if (cdb_read(this, SvPVX(x), dlen, cdb_datapos(this)) == -1) readerror();
582 18           av_push(RETVAL, x);
583 18           }
584              
585             OUTPUT:
586             RETVAL
587              
588             int
589             cdb_EXISTS(this, k)
590             cdb * this
591             SV * k
592              
593             PREINIT:
594             STRLEN klen;
595             char *kp;
596              
597             CODE:
598 9 100         if (!SvOK(k)) {
    50          
    50          
599 1           XSRETURN_NO;
600             }
601 8 50         kp = SvPV(k, klen);
602 8           RETVAL = cdb_find(this, kp, klen);
603 8 100         if (RETVAL != 0 && RETVAL != 1) readerror();
    50          
604              
605             OUTPUT:
606             RETVAL
607              
608             void
609             cdb_DESTROY(db)
610             SV * db
611              
612             PREINIT:
613             cdb * this;
614             IO *io;
615              
616             CODE:
617 13 50         if (sv_isobject(db) && (SvTYPE(SvRV(db)) == SVt_PVMG) ) {
    100          
618 12 50         this = (cdb*)SvIV(SvRV(db));
619              
620 12           iter_end(this);
621             #ifdef HASMMAP
622 12 100         if (this->map) {
623 11           munmap(this->map, this->size);
624 11           this->map = 0;
625             }
626             #endif
627 12           PerlIO_close(this->fh); /* close() on O_RDONLY cannot fail */
628 12           Safefree(this);
629             }
630              
631             SV *
632             cdb_FIRSTKEY(this)
633             cdb * this
634              
635             PREINIT:
636             char buf[8];
637             U32 klen;
638              
639             CODE:
640 21           iter_start(this);
641 21 100         if (iter_key(this)) {
642 20           ST(0) = sv_mortalcopy(this->curkey);
643 20           CDB_DO_COW(ST(0));
644             } else
645 1           XSRETURN_UNDEF; /* empty database */
646              
647             SV *
648             cdb_NEXTKEY(this, k)
649             cdb * this
650             SV * k
651              
652             PREINIT:
653             char buf[8], *kp;
654             int found;
655             off_t pos;
656             U32 dlen, klen0;
657             STRLEN klen1;
658              
659             CODE:
660 164 50         if (!SvOK(k)) {
    0          
    0          
661 0           XSRETURN_UNDEF;
662             }
663             /* Sometimes NEXTKEY gets called before FIRSTKEY if the hash
664             * gets re-tied so we call iter_start() anyway here */
665 164 100         if (this->end == 0 || !sv_eq(this->curkey, k))
    50          
666 1           iter_start(this);
667 164           iter_advance(this);
668 164 100         if (iter_key(this)) {
669 145           ST(0) = sv_mortalcopy(this->curkey);
670 145           CDB_DO_COW(ST(0));
671             } else {
672 19           iter_start(this);
673 19           (void)iter_key(this); /* prepare curkey for FETCH */
674 19           this->fetch_advance = 1;
675 19           XSRETURN_UNDEF;
676             }
677              
678             cdb_make *
679             cdb_new(CLASS, fn, fntemp)
680             char * CLASS
681             char * fn
682             char * fntemp
683              
684             PREINIT:
685             cdb_make *cdbmake;
686             int i;
687              
688             CODE:
689 11           New(0, cdbmake, 1, cdb_make);
690 11           cdbmake->f = PerlIO_open(fntemp, "wb");
691 11 100         if (!cdbmake->f) XSRETURN_UNDEF;
692              
693 10 50         if (cdb_make_start(cdbmake) < 0) XSRETURN_UNDEF;
694              
695             /* Oh, for referential transparency. */
696 10           New(0, cdbmake->fn, strlen(fn) + 1, char);
697 10           New(0, cdbmake->fntemp, strlen(fntemp) + 1, char);
698 10           strncpy(cdbmake->fn, fn, strlen(fn) + 1);
699 10           strncpy(cdbmake->fntemp, fntemp, strlen(fntemp) + 1);
700              
701 10           CLASS = "CDB_File::Maker"; /* OK, so this is a hack */
702              
703 10           RETVAL = cdbmake;
704              
705             OUTPUT:
706             RETVAL
707              
708             MODULE = CDB_File PACKAGE = CDB_File::Maker PREFIX = cdbmaker_
709              
710             void
711             cdbmaker_DESTROY(sv)
712             SV * sv
713              
714             PREINIT:
715             cdb_make * this;
716              
717             CODE:
718 10 50         if (sv_isobject(sv) && (SvTYPE(SvRV(sv)) == SVt_PVMG) ) {
    50          
719 10 50         this = (cdb_make*)SvIV(SvRV(sv));
720 10 50         if(this->f){PerlIO_close(this->f);}
721 10           Safefree(this);
722             }
723              
724             void
725             cdbmaker_insert(this, ...)
726             cdb_make * this
727              
728             PREINIT:
729             char *kp, *vp, packbuf[8];
730             int c, i, x;
731             STRLEN klen, vlen;
732             U32 h;
733             SV *k;
734             SV *v;
735              
736             PPCODE:
737 85 100         for (x = 1; x < items; x += 2) {
738 43           k = ST(x);
739 43           v = ST(x+1);
740 43 100         kp = SvPV(k, klen); vp = SvPV(v, vlen);
    100          
741 43           uint32_pack(packbuf, klen);
742 43           uint32_pack(packbuf + 4, vlen);
743              
744 43 50         if (PerlIO_write(this->f, packbuf, 8) < 8) writeerror();
745              
746 43           h = cdb_hash(kp, klen);
747 43 50         if (PerlIO_write(this->f, kp, klen) < klen) writeerror();
748 43 50         if (PerlIO_write(this->f, vp, vlen) < vlen) writeerror();
749              
750 43 50         if (cdb_make_addend(this, klen, vlen, h) == -1) nomem();
751             }
752              
753             int
754             cdbmaker_finish(this)
755             cdb_make * this
756              
757             PREINIT:
758             char buf[8];
759             int i;
760             U32 len, u;
761             U32 count, memsize, where;
762             struct cdb_hplist *x, *prev;
763             struct cdb_hp *hp;
764              
765             CODE:
766 2570 100         for (i = 0; i < 256; ++i)
767 2560           this->count[i] = 0;
768              
769 19 100         for (x = this->head; x; x = x->next) {
770 9           i = x->num;
771 52 100         while (i--)
772 43           ++this->count[255 & x->hp[i].h];
773             }
774              
775 10           memsize = 1;
776 2570 100         for (i = 0; i < 256; ++i) {
777 2560           u = this->count[i] * 2;
778 2560 100         if (u > memsize)
779 9           memsize = u;
780             }
781              
782 10           memsize += this->numentries; /* no overflow possible up to now */
783 10           u = (U32) 0 - (U32) 1;
784 10           u /= sizeof(struct cdb_hp);
785 10 50         if (memsize > u) { errno = ENOMEM; XSRETURN_UNDEF; }
786              
787 10 50         New(0xCDB, this->split, memsize, struct cdb_hp);
788              
789 10           this->hash = this->split + this->numentries;
790              
791 10           u = 0;
792 2570 100         for (i = 0; i < 256; ++i) {
793 2560           u += this->count[i]; /* bounded by numentries, so no overflow */
794 2560           this->start[i] = u;
795             }
796              
797 10           prev = 0;
798 19 100         for (x = this->head; x; x = x->next) {
799 9           i = x->num;
800 52 100         while (i--)
801 43           this->split[--this->start[255 & x->hp[i].h]] = x->hp[i];
802 9 50         if (prev) Safefree(prev);
803 9           prev = x;
804             }
805 10 100         if (prev) Safefree(prev);
806              
807 2570 100         for (i = 0; i < 256; ++i) {
808 2560           count = this->count[i];
809              
810 2560           len = count + count; /* no overflow possible */
811 2560           uint32_pack(this->final + 8 * i, this->pos);
812 2560           uint32_pack(this->final + 8 * i + 4, len);
813              
814 2646 100         for (u = 0; u < len; ++u)
815 86           this->hash[u].h = this->hash[u].p = 0;
816              
817 2560           hp = this->split + this->start[i];
818 2603 100         for (u = 0; u < count; ++u) {
819 43           where = (hp->h >> 8) % len;
820 46 100         while (this->hash[where].p)
821 3 100         if (++where == len)
822 2           where = 0;
823 43           this->hash[where] = *hp++;
824             }
825              
826 2646 100         for (u = 0; u < len; ++u) {
827 86           uint32_pack(buf, this->hash[u].h);
828 86           uint32_pack(buf + 4, this->hash[u].p);
829 86 50         if (PerlIO_write(this->f, buf, 8) == -1) XSRETURN_UNDEF;
830 86 50         if (posplus(this, 8) == -1) XSRETURN_UNDEF;
831             }
832             }
833              
834 10           Safefree(this->split);
835              
836 10 50         if (PerlIO_flush(this->f) == EOF) writeerror();
837 10           PerlIO_rewind(this->f);
838              
839 10 50         if (PerlIO_write(this->f, this->final, sizeof this->final) < sizeof this->final) writeerror();
840 10 50         if (PerlIO_flush(this->f) == EOF) writeerror();
841              
842 10 50         if (fsync(PerlIO_fileno(this->f)) == -1) XSRETURN_NO;
843 10 50         if (PerlIO_close(this->f) == EOF) XSRETURN_NO;
844 10           this->f=0;
845              
846 10 50         if (rename(this->fntemp, this->fn)) {
847 0           croak("Failed to rename %s to %s.", this->fntemp, this->fn);
848             }
849              
850 10           Safefree(this->fn);
851 10           Safefree(this->fntemp);
852              
853 10           RETVAL = 1;
854              
855             OUTPUT:
856             RETVAL