123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198(*
* Copyright (c) 2021 Tarides <contact@tarides.com>
* Copyright (c) 2021 Gabriel Belouze <gabriel.belouze@ens.psl.eu>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)includeCache_intfmoduleMake(K:Hashtbl.HashedType)(V:sigtypetend)=structtypekey=K.ttypevalue=V.tmoduleLru=structmoduleV=structtypet=V.tletweight_=1endincludeLru.M.Make(K)(V)letcleart=letcap=capacitytinresize0t;trimt;resizecaptendmoduleHashtbl=Hashtbl.Make(K)typet={california:valueHashtbl.t;lru:Lru.t;volatile:valueHashtbl.t;flush:key->value->unit;load:?available:value->key->value;mutablefilter:value->[`California|`Lru|`Volatile];}letv~flush~load~filterlru_cap={flush;load;california=Hashtbl.create4096;lru=Lru.createlru_cap;volatile=Hashtbl.create16;filter;}(* Emit a warning when the lru if filled. *)letlru_filled=letflag=reftrueinfun()->if!flagthen(Log.warn(funreporter->reporter"LRU is filled");flag:=false)moduleQueue=structincludeQueueletpush=letlost_count=ref0infunvq->iflengthq<128thenpushvqelse(incrlost_count;if!lost_countmod1_000=0thenLog.warn(funreporter->reporter"%i buffers lost"!lost_count))endletreusable_buffer_pool=Queue.create()letlengtht=Hashtbl.lengtht.california+Hashtbl.lengtht.volatile+Lru.sizet.lru(* Remove the least recently used value, flush it and reuse the buffer. *)letremove_lru_and_reuset=matchLru.lrut.lruwith|Some(key,value)->t.flushkeyvalue;Queue.pushvaluereusable_buffer_pool;Lru.drop_lrut.lru|None->failwith"Empty LRU"letfindtkey=match(Hashtbl.find_optt.californiakey,Lru.findkeyt.lru,Hashtbl.find_optt.volatilekey)with|Somevalue,None,None|None,None,Somevalue->value|None,Somevalue,None->Lru.promotekeyt.lru;value|None,None,None->letvalue=matchQueue.is_emptyreusable_buffer_poolwith|true->t.loadkey|false->t.load~available:(Queue.popreusable_buffer_pool)keyin(matcht.filtervaluewith|`California->Hashtbl.addt.californiakeyvalue|`Lru->Lru.addkeyvaluet.lru;whileLru.weightt.lru>Lru.capacityt.lrudolru_filled();remove_lru_and_reusetdone|`Volatile->Hashtbl.addt.volatilekeyvalue;ifHashtbl.lengtht.volatile>64then(Log.warn(funreporter->reporter"Not enough release");assertfalse));value|_->failwith"Key loaded in several caches"letreloadtkey=match(Hashtbl.find_optt.californiakey,Lru.findkeyt.lru,Hashtbl.find_optt.volatilekey)with|Somevalue,None,None->(matcht.filtervaluewith|`California->()|`Lru->Hashtbl.removet.californiakey;Lru.addkeyvaluet.lru|`Volatile->Hashtbl.removet.californiakey;Hashtbl.addt.volatilekeyvalue)|None,Somevalue,None->(matcht.filtervaluewith|`California->Lru.removekeyt.lru;Hashtbl.addt.californiakeyvalue|`Lru->Lru.promotekeyt.lru|`Volatile->Lru.removekeyt.lru;Hashtbl.addt.volatilekeyvalue)|None,None,Somevalue->(matcht.filtervaluewith|`California->Hashtbl.removet.volatilekey;Hashtbl.addt.californiakeyvalue|`Lru->Hashtbl.removet.volatilekey;Lru.addkeyvaluet.lru|`Volatile->())|None,None,None->failwith"Key is not loaded"|_->failwith"Key loaded in several caches"letupdate_filtert~filter=t.filter<-filter;Hashtbl.filter_map_inplace(funkeyvalue->iffiltervalue=`CaliforniathenSomevalueelse(t.flushkeyvalue;None))t.california;Lru.iter(funkv->t.flushkv)t.lru;Lru.cleart.lruletreleaset=Hashtbl.iter(funkv->Queue.pushvreusable_buffer_pool;t.flushkv)t.volatile;Hashtbl.cleart.volatileletdeallocatetkey=Hashtbl.removet.californiakey;Lru.removekeyt.lru;Hashtbl.removet.volatilekeyletcleart=Hashtbl.cleart.volatile;Hashtbl.cleart.california;Lru.cleart.lruletflusht=Hashtbl.itert.flusht.california;Lru.itert.flusht.lru;releasetend