|
|
|
|
|
|
|
|
|
|
|
#pike __REAL_VERSION__ |
#require constant(Gdbm.gdbm) |
|
|
#define CLUTTERED 1000 |
|
inherit Cache.Storage.Base; |
|
Gdbm.gdbm db, metadb; |
int deletion_ops=0; |
int have_dependants=0; |
|
|
class Data { |
inherit Cache.Data; |
|
int _size=0; |
string _key=0; |
mixed _data=0; |
|
int size() { |
return _size; |
} |
|
mixed data() { |
if (!_data) |
_data=decode_value(db[_key]); |
return _data; |
} |
|
private inline string metadata_dump () { |
return encode_value( (["size":_size,"atime":atime, |
"ctime":ctime,"etime":etime,"cost":cost]) ); |
} |
|
|
void sync() { |
metadb[_key]=metadata_dump(); |
} |
|
inline void touch() { |
atime=time(1); |
sync(); |
} |
|
protected void create(string key, Gdbm.gdbm data_db, |
Gdbm.gdbm metadata_db, string dumped_metadata) { |
mapping m=decode_value(dumped_metadata); |
_key=key; |
db=data_db; |
metadb=metadata_db; |
_size=m->size; |
atime=m->atime; |
ctime=m->ctime; |
etime=m->etime; |
cost=(float)(m->cost||1); |
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
private string iter=0; |
int(0..0)|string first() { |
return (iter=metadb->firstkey()); |
} |
|
int(0..0)|string next() { |
return (iter=metadb->nextkey(iter)); |
} |
|
|
|
void set(string key, mixed value, |
void|int expire_time, void|float preciousness, |
void|multiset(string) dependants) { |
|
if (programp(value)||functionp(value)) { |
werror("can't store value\n"); |
return 0; |
} |
string tmp; |
int tm=time(1); |
mapping meta; |
tmp=encode_value(value); |
db[key]=tmp; |
meta=(["size":sizeof(tmp),"atime":tm,"ctime":tm]); |
if (expire_time) meta->etime=expire_time; |
if (preciousness||!undefinedp(preciousness)) |
meta->cost=preciousness; |
else |
meta->cost=1.0; |
if (dependants) { |
meta->dependants=dependants; |
have_dependants=1; |
} |
|
metadb[key]=encode_value(meta); |
} |
|
|
|
|
int(0..0)|Cache.Data get(string key,void|int notouch) { |
string metadata=metadb[key]; |
Data rv; |
if (!metadata) return 0; |
rv = Data(key,db,metadb,metadata); |
if (!notouch) { |
rv->touch(); |
} |
return rv; |
} |
|
|
|
|
void aget(string key, |
function(string,int(0..0)|Cache.Data:void) callback) { |
callback(key,get(key)); |
} |
|
void delete(string key, void|int(0..1) hard) { |
multiset(string) dependants=0; |
|
if (have_dependants) { |
string emeta=metadb->fetch(key); |
if (!emeta) return; |
dependants=decode_value(emeta)->dependants; |
} |
|
|
db->delete(key); |
metadb->delete(key); |
deletion_ops++; |
|
if (dependants) { |
foreach((array)dependants, string chain) { |
|
delete(chain); |
} |
|
return; |
} |
|
if (deletion_ops > CLUTTERED) { |
|
db->reorganize(); |
metadb->reorganize(); |
deletion_ops=0; |
} |
} |
|
|
void create(string path) { |
db=Gdbm.gdbm(path+".db","rwcf"); |
metadb=Gdbm.gdbm(path+"_meta.db","rwcf"); |
} |
|
|
|
|
|
|
|
|
|
|