|
|
|
|
|
|
|
|
|
|
|
#pike __REAL_VERSION__ |
|
#if constant(thread_create) |
#define do_possibly_threaded_call thread_create |
#else |
#define do_possibly_threaded_call call_function |
#endif |
|
#define DEFAULT_CLEANUP_CYCLE 300 |
|
|
private int cleanup_cycle=DEFAULT_CLEANUP_CYCLE; |
protected object(Cache.Storage.Base) storage; |
protected object(Cache.Policy.Base) policy; |
|
|
|
|
mixed lookup(string key) { |
if (!stringp(key)) key=(string)key; |
object(Cache.Data) tmp=storage->get(key); |
return (tmp?tmp->data():UNDEFINED); |
} |
|
|
|
|
|
private mapping (string:multiset(array)) pending_requests=([]); |
|
private void got_results(string key, int|Cache.Data value) { |
mixed data=UNDEFINED; |
if (pending_requests[key]) { |
if (value) { |
data=value->data(); |
} |
foreach(indices(pending_requests[key]),array cb) { |
cb[0](key,value,@cb[1]); |
if (cb[2]) remove_call_out(cb[2]); |
} |
m_delete(pending_requests,key); |
} |
|
} |
|
|
|
private void no_results(string key, array req, mixed call_out_id) { |
pending_requests[key][req]=0; |
req[0](key,0,@req[1]); |
} |
|
|
|
|
|
|
void alookup(string key, |
function(string,mixed,mixed...:void) callback, |
int|float timeout, |
mixed ... args) { |
if (!stringp(key)) key=(string)key; |
array req = ({callback,args,0}); |
if (!pending_requests[key]) { |
pending_requests[key]=(< req >); |
storage->aget(key,got_results); |
} else { |
pending_requests[key][req]=1; |
|
} |
if (timeout) |
req[2]=call_out(no_results,timeout,key,req); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void store(string key, mixed value, void|int max_life, |
void|float preciousness, void|multiset(string) dependants ) { |
if (!stringp(key)) key=(string)key; |
multiset(string) rd=UNDEFINED; |
if (dependants) { |
rd=(<>); |
foreach((array)dependants,mixed d) { |
rd[(string)d]=1; |
} |
} |
storage->set(key,value, |
(max_life?time(1)+max_life:0), |
preciousness,rd); |
} |
|
|
|
|
|
void delete(string key, void|int(0..1)hard) { |
if (!stringp(key)) key=(string)key; |
storage->delete(key,hard); |
} |
|
|
|
|
|
|
|
|
int cleanup_lock=0; |
|
private void do_cleanup(function expiry_function, object storage) { |
|
|
if (cleanup_lock) |
return; |
cleanup_lock=1; |
expiry_function(storage); |
cleanup_lock=0; |
} |
|
#if constant(thread_create) |
protected Thread.Thread cleanup_thread; |
|
protected void _destruct() |
{ |
if (Thread.Thread t = cleanup_thread) { |
cleanup_thread = 0; |
t->wait(); |
} |
} |
#endif |
|
|
void start_cleanup_cycle() { |
if (master()->asyncp()) { |
call_out(async_cleanup_cache,cleanup_cycle); |
return; |
} |
#if constant(thread_create) |
cleanup_thread = thread_create(threaded_cleanup_cycle); |
#else |
call_out(async_cleanup_cache,cleanup_cycle); |
|
#endif |
} |
|
|
void async_cleanup_cache() { |
mixed err=catch { |
do_possibly_threaded_call(do_cleanup,policy->expire,storage); |
}; |
call_out(async_cleanup_cache,cleanup_cycle); |
if (err) |
throw (err); |
} |
|
#if constant(thread_create) |
|
void threaded_cleanup_cycle() { |
while (1) { |
if (master()->asyncp()) { |
call_out(async_cleanup_cache,0); |
return; |
} |
for (int wait = 0; wait < cleanup_cycle; wait++) { |
sleep (1); |
if (!cleanup_thread) return; |
} |
do_cleanup(policy->expire,storage); |
} |
} |
#endif |
|
|
|
void create(Cache.Storage.Base storage_mgr, |
Cache.Policy.Base policy_mgr, |
void|int cleanup_cycle_delay) { |
if (!storage_mgr || !policy_mgr) |
error ( "I need a storage manager and a policy manager\n" ); |
storage=storage_mgr; |
policy=policy_mgr; |
if (cleanup_cycle_delay) cleanup_cycle=cleanup_cycle_delay; |
start_cleanup_cycle(); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|