CDB-TinyCDB

 view release on metacpan or  search on metacpan

TinyCDB.xs  view on Meta::CPAN

                                ) < 0
                            ) {
                                fileerror(RETVAL, "update", RETVAL->fntemp);
                            }
                        };
                    } else {
                        fileerror(RETVAL, "read", RETVAL->fn);
                    }
                    PerlIO_rewind( RETVAL->fd );
                    if ( PerlIO_error( RETVAL->fd ) )
                        fileerror(RETVAL, "set position", RETVAL->fn);
                }
            }

        }
        memfree( RETVAL );
    }
    OUTPUT:
        RETVAL

CDB_TinyCDB *
create(CLASS, fn, fntemp)
    char * CLASS
    char * fn
    char * fntemp
    INIT:
        if ( sv_isobject( ST(0) ) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG )) {
            croak("%s is already blessed\n", SvPV(ST(0), PL_na));
        }
    CODE:
    {
        Newx(RETVAL, 1, CDB_TinyCDB);

        RETVAL->alias = DOCREATE;

        RETVAL->fn = savepv( fn );
        RETVAL->fntemp = savepv( fntemp );
        RETVAL->curpos = 0;
        RETVAL->opts = 0;
        RETVAL->mem.buf = 0;
        RETVAL->mem.key = 0;
        RETVAL->mem.val = 0;

        RETVAL->fdtemp = PerlIO_open(fntemp, "w+b");

        if ( ! RETVAL->fdtemp ) {
            fileerror(RETVAL, "create", fn);
        };
        cdb_make_start(&RETVAL->cdbm, PerlIO_fileno( RETVAL->fdtemp ));
    }
    OUTPUT:
        RETVAL


void
get(self, key)
    CDB_TinyCDB *self
    char *key
    INIT:
        assert_status( self, METHOD_GET );
    PPCODE:
    {
        unsigned int vlen = 0;
        STRLEN klen = strlen(key);

        if (self->alias & DOLOAD) { /* tinyfile whole in memory */
            if (cdb_find(&self->cdb, key, klen) > 0) {
                vlen = cdb_datalen( &self->cdb ); /* length of data */

                MAKESV( val, vlen );
                if ( cdb_read( &self->cdb, SvPVX(val), vlen, cdb_datapos( &self->cdb )) < 0 ) {
                    fileerror(self, "read", self->fn);
                };
                PUSHWITHNULL( val, vlen );
            };
        } else {
            if ( cdb_seek(PerlIO_fileno(self->fd), key, klen, &vlen) > 0 ) {
                MAKESV( val, vlen );
                if ( cdb_bread( PerlIO_fileno(self->fd), SvPVX(val), vlen ) < 0)  {
                    fileerror(self, "read", self->fn);
                };
                XPUSHs( sv_2mortal(newSVpvn(self->mem.val, vlen)) );
                PUSHWITHNULL( val, vlen );
            };
        };
    }

int
exists(self, key)
    CDB_TinyCDB *self
    char *key
    INIT:
        assert_status( self, METHOD_EXISTS );
    CODE:
    {
        STRLEN klen = strlen(key);

        if (self->alias & WITHTEMP && !( self->opts & COMMITTED)) { /* for_create | for_update | create */
            RETVAL = cdb_make_exists(&self->cdbm, key, klen);
            if ( RETVAL < 0 ) {
                fileerror(self, "read", self->fntemp);
            }
        } else {
            if (self->alias & DOLOAD) { /* tinyfile whole in memory */
                RETVAL = cdb_find(&self->cdb, key, klen);
            } else {
                unsigned int vlen;
                RETVAL = cdb_seek(PerlIO_fileno(self->fd), key, klen, &vlen);
            };

            if ( RETVAL < 0 ) {
                fileerror(self, "read", self->fn);
            }
        }
    }
    OUTPUT:
        RETVAL


void
getall(self, key)
    CDB_TinyCDB *self
    char *key
    ALIAS:
        getlast = DOGETLAST
    INIT:
        assert_status( self, METHOD_GETALL );
    PPCODE:
    {
        unsigned int kbufsize = 2048;
        unsigned int klen = 0, vlen = 0;
        unsigned int lastpos = 0, lastvlen = 0;
        STRLEN searchklen = strlen(key);

        int mode = ix ? ix : DOGETALL;

        if (self->alias & DOLOAD) { /* tinyfile whole in memory */
            struct cdb_find cdbf;

            cdb_findinit( &cdbf, &self->cdb, key, searchklen );
            while ( cdb_findnext(&cdbf) > 0 ) {
                vlen = cdb_datalen(&self->cdb); /* length of data */
                lastpos = cdb_datapos(&self->cdb);

                if ( mode == DOGETALL ) {
                    MAKESV( val, vlen );

                    if (cdb_read(&self->cdb, SvPVX(val), vlen, lastpos) < 0 ) {
                        fileerror(self, "read", self->fn);
                    }

                    PUSHWITHNULL( val, vlen );
                }
            }
            if ( mode == DOGETLAST && lastpos ) {
                MAKESV( val, vlen );
                if (cdb_read(&self->cdb, SvPVX(val), vlen, lastpos) < 0 ) {
                    fileerror(self, "read", self->fn);
                }
                PUSHWITHNULL( val, vlen );
            }
        } else { /* open */
            unsigned int bytes, dend, curpos = 0;
            Off_t prevpos = PerlIO_tell( self->fd );

            Newx(self->mem.buf, kbufsize + 1, unsigned char); /* allocate memory */
            Newx(self->mem.key, kbufsize + 1, char); /* allocate memory */

            PerlIO_rewind( self->fd );
            bytes = PerlIO_read( self->fd, self->mem.buf, 2048 );

            if ( bytes == 2048 ) {
                dend = cdb_unpack(self->mem.buf);
                curpos += bytes;

                while ( curpos < dend - 8) {
                    bytes = PerlIO_read( self->fd, self->mem.buf, 8 );
                    if ( bytes != 8 )
                        fileerror(self, "read", self->fn);
                    curpos += bytes;

                    klen = cdb_unpack(self->mem.buf);
                    vlen = cdb_unpack(self->mem.buf + 4);

                    if (dend - klen < curpos || dend - vlen < curpos + klen)
                        fileerror(self, "read", self->fn);

                    GROWIFNEEDED( self, self->mem.key, klen, kbufsize );

                    bytes = PerlIO_read( self->fd, self->mem.key, klen );
                    if (bytes != klen) {
                        fileerror(self, "read", self->fn);
                    };
                    curpos += bytes;
                    self->mem.key[klen] = '\0';

                    if ( klen == searchklen
                        && strnEQ( self->mem.key, key, klen )
                    ) {
                        lastpos = curpos;
                        lastvlen = vlen;

                        if ( mode == DOGETALL ) {
                            MAKESV( val, vlen );
                            if ( perlio_bread( self->fd, SvPVX(val), vlen ) < 0)  {
                                fileerror(self, "read", self->fn);
                            };
                            PUSHWITHNULL( val, vlen );
                        } else {
                            PerlIO_seek(self->fd, vlen, SEEK_CUR);
                        }
                    } else {
                        PerlIO_seek(self->fd, vlen, SEEK_CUR);
                    }
                    curpos += vlen;
                };
            } else {
                fileerror(self, "read", self->fn);
            }

            if ( mode == DOGETLAST && lastpos ) {
                PerlIO_seek( self->fd, lastpos, SEEK_SET );
                MAKESV( val, lastvlen );
                if ( perlio_bread( self->fd, SvPVX(val), lastvlen ) < 0)  {
                    fileerror(self, "read", self->fn);
                };
                PUSHWITHNULL( val, lastvlen );
            }

            /* go back to original position in file */
            PerlIO_seek( self->fd, prevpos, SEEK_SET );
            if ( PerlIO_error( self->fd ) )
                fileerror(self, "set position", self->fn);
        }
        memfree( self );
    }

void
each(self)
    CDB_TinyCDB *self
    INIT:
        assert_status( self, METHOD_EACH );
    PPCODE:
    {
        unsigned int klen = 0, vlen = 0;
        unsigned int kbufsize = 2048;
        int keep_looping = 1;

        if ( self->alias & DOLOAD ) { /* load */
            if ( !( self->opts & EACH_INITIALIZED ) ) {
                self->curpos = 0;
                cdb_seqinit( &self->curpos, &self->cdb );
                self->opts |= EACH_INITIALIZED;
            }
            while ( keep_looping-- ) {
                if ( cdb_seqnext(&self->curpos, &self->cdb) > 0 ) {
                    klen = cdb_keylen( &self->cdb );
                    vlen = cdb_datalen( &self->cdb );

                    if ( klen ) {
                        MAKESV( key, klen );
                        cdb_read( &self->cdb, SvPVX(key), klen, cdb_keypos(&self->cdb) );
                        PUSHWITHNULL( key, klen );

                        MAKESV( val, vlen );
                        cdb_read( &self->cdb, SvPVX(val), vlen, cdb_datapos(&self->cdb) );
                        PUSHWITHNULL( val, vlen );
                    } else {
                        keep_looping++;
                    }
                } else {
                    self->opts &= ~EACH_INITIALIZED;
                }
            }
        } else { /* open */
            unsigned int bytes;
            unsigned int klen, vlen;
            Newx(self->mem.buf, kbufsize + 1, unsigned char); /* allocate memory */

            if ( !( self->opts & EACH_INITIALIZED ) ) {
                self->curpos = 0;
                PerlIO_rewind( self->fd );
                self->opts |= EACH_INITIALIZED;
                bytes = PerlIO_read( self->fd, self->mem.buf, 2048 );
                if ( bytes == 2048 ) {
                    self->dend = cdb_unpack(self->mem.buf);
                } else {
                    fileerror(self, "read", self->fn);
                }
                self->curpos += bytes;
            }

            while ( keep_looping-- ) {
                if ( self->curpos < self->dend - 8) {
                    bytes = PerlIO_read( self->fd, self->mem.buf, 8 );
                    if ( bytes != 8 ) {
                        fileerror(self, "read", self->fn);
                    }
                    self->curpos += bytes;

                    klen = cdb_unpack(self->mem.buf);
                    vlen = cdb_unpack(self->mem.buf + 4);

                    if (self->dend - klen < self->curpos || self->dend - vlen < self->curpos + klen)
                        fileerror(self, "read", self->fn);

                    if ( klen ) {
                        MAKESV( key, klen );
                        if ( perlio_bread( self->fd, SvPVX(key), klen ) < 0)  {
                            fileerror(self, "read", self->fn);
                        };
                        self->curpos += klen;

                        PUSHWITHNULL( key, klen );

                        MAKESV( val, vlen );
                        if ( perlio_bread( self->fd, SvPVX(val), vlen ) < 0)  {
                            fileerror(self, "read", self->fn);
                        };
                        self->curpos += vlen;

                        PUSHWITHNULL( val, vlen );
                    } else {
                        /* skip nulled out records (from replace0) */
                        self->curpos += klen + vlen;
                        PerlIO_seek(self->fd, klen + vlen, SEEK_CUR);
                        keep_looping++;
                    }
                } else {
                    self->opts &= ~EACH_INITIALIZED;
                };
            }
            if ( PerlIO_error( self->fd ) )
                fileerror(self, "close", self->fn);
        }
        memfree( self );
    }



void
keys(self)
    CDB_TinyCDB *self
    INIT:
        assert_status( self, METHOD_KEYS );
    PPCODE:
    {
        unsigned int curpos = 0;
        unsigned int klen = 0, kbufsize = 2048;

        if ( self->alias & DOLOAD ) { /* load */

            cdb_seqinit( &curpos, &self->cdb );
            while ( cdb_seqnext(&curpos, &self->cdb) > 0 ) {
                klen = cdb_keylen( &self->cdb );

                if ( ! klen ) continue;

                MAKESV( key, klen );
                cdb_read( &self->cdb, SvPVX(key), klen, cdb_keypos(&self->cdb) );
                PUSHWITHNULL( key, klen );
            }
        } else { /* open */
            unsigned int bytes, dend;
            unsigned int klen, vlen;
            Newx(self->mem.buf, kbufsize + 1, unsigned char); /* allocate memory */

            Off_t prevpos = PerlIO_tell( self->fd );
            PerlIO_rewind( self->fd );
            bytes = PerlIO_read( self->fd, self->mem.buf, 2048 );

            if ( bytes == 2048 ) {
                dend = cdb_unpack(self->mem.buf);

                curpos += bytes;

                while ( curpos < dend - 8) {
                    bytes = PerlIO_read( self->fd, self->mem.buf, 8 );
                    if ( bytes != 8 )
                        fileerror(self, "read", self->fn);
                    curpos += bytes;

                    klen = cdb_unpack(self->mem.buf);
                    vlen = cdb_unpack(self->mem.buf + 4);

                    if (dend - klen < curpos || dend - vlen < curpos + klen)
                        fileerror(self, "read", self->fn);

                    if ( klen > 0 ) {
                        MAKESV( key, klen );
                        if ( perlio_bread( self->fd, SvPVX(key), klen ) < 0 )  {
                            fileerror(self, "read", self->fn);
                        };
                        curpos += klen;

                        PUSHWITHNULL( key, klen );
                    }
                    curpos += vlen;
                    PerlIO_seek(self->fd, vlen, SEEK_CUR);
                };
            } else {
                fileerror(self, "read", self->fn);
            }
            /* go back to original position in file */
            PerlIO_seek( self->fd, prevpos, SEEK_SET );
            if ( PerlIO_error( self->fd ) )

TinyCDB.xs  view on Meta::CPAN

        put_warn     = CDB_PUT_WARN
    INIT:
        assert_status( self, METHOD_ADD );
    CODE:
    {
        char *key, *val;
        STRLEN klen, vlen;
        int mode, result, i;

        mode = ix ? ix : CDB_PUT_ADD;
        RETVAL = 0;

        for ( i = 1; i < items; i += 2 ) {
            key = SvPV( ST(i), klen );
            val = SvPV( ST(i+1), vlen );

            result = cdb_make_put(&self->cdbm, key, klen, val, vlen, mode);
            if ( result < 0 ) {
                fileerror(self, "update", self->fntemp);
            } else if ( result > 0 && mode == CDB_PUT_WARN) {
                warn("Key %s already exists - added anyway", key);
            }
            if ( mode == CDB_PUT_ADD || mode == CDB_PUT_WARN) {
                RETVAL++;
            } else {
                RETVAL += result;
            };
        };
    }
    OUTPUT:
        RETVAL

int
put_insert(self, key, val)
    CDB_TinyCDB *self
    char *key
    char *val
    INIT:
        assert_status( self, METHOD_INSERT );
    CODE:
    {
        RETVAL = cdb_make_put(&self->cdbm, key, strlen(key), val, strlen(val), CDB_PUT_INSERT);
        if ( RETVAL < 0 ) {
            fileerror(self, "update", self->fntemp);
        } else if ( RETVAL > 0) {
            croak("Unable to insert new record - key exists");
        } else {
            RETVAL++;
        }
    }
    OUTPUT:
        RETVAL



void
finish( self, ... )
    CDB_TinyCDB *self
    INIT:
        assert_status( self, METHOD_FINISH );
    PPCODE:
    {
        int save_changes = 1;
        int reopen       = 1;
        char *key;
        STRLEN klen;
        int i;

        for ( i = 1; i < items; i += 2 ) {
            key = SvPVx( ST(i), klen);
            if ( strEQ(key, "save_changes") ) {
                save_changes = SvTRUE(ST(i+1)) ? 1 : 0;
            } else if ( strEQ(key, "reopen") ) {
                reopen = SvTRUE(ST(i+1)) ? 1 : 0;
            } else {
                croak("Invalid option %s", key);
            }
        }
        commit( self, save_changes, reopen );
    }

void
DESTROY(self)
    CDB_TinyCDB *self
    PPCODE:
    {
        commit( self, /* save_changes */ 0, /* reopen */ 0 );
        memfree( self );
        Safefree( self->fn );
        if ( self->fntemp ) {
            Safefree( self->fntemp );
        }
        Safefree( self );
    }



( run in 0.607 second using v1.01-cache-2.11-cpan-71847e10f99 )