CDB-TinyCDB
view release on metacpan or search on metacpan
) < 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 ) )
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 )