123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129(******************************************************************************)(* Copyright (c) 2017 Török Edwin <edwin@etorok.net> *)(* Copyright (c) 2014-2016 Skylable Ltd. <info-copyright@skylable.com> *)(* *)(* Permission to use, copy, modify, and/or 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. *)(******************************************************************************)(* 2Q: A Low Overhead High Performance Buffer Management Replacement Algorithm
* Theodore Johnson, Dennis Shasha
* 1994
*)moduleMake(Key:Map.OrderedType)=structmoduletypeS=sigtypevvalfind:Key.t->voptionvalreplace:Key.t->v->unitendtype'acache=(moduleSwithtypev='a)letconst_1_=1letcreate(typea)?(weight=const_1)n:acache=(modulestructtypev=amoduleV=structtypet=aletweight=weightendmoduleL=Lru.F.Make(Key)(V)letamain=ref(L.empty(n/2))leta1in=ref(L.empty(n/4))leta1out=ref(L.empty(n/4))lettotal_size=nlethas_room()=L.size!a1in+L.size!a1out+L.size!amain<total_sizeletadd?trimkvlru=lru:=L.add?trimkv!lruletadd_a1outkv=add~trim:falsekva1outletadd_a1inkv=add~trim:falsekva1inletadd_mainkv=(* do not put it on A1out, it hasn't been accessed for a while *)add~trim:truekvamainletpop_if_fullt=letlru=!tinifL.sizelru>L.capacitylruthenmatchL.pop_lrulruwith|None->assertfalse|Some(kv,t')->t:=t';SomekvelseNoneletreclaim()=beginmatchpop_if_fulla1inwith|Some(ykey,yval)->add_a1outykeyyval|None->()end;ifnot(has_room())thenignore(pop_if_fulla1out)letfind_updatekeylru=matchL.findkey!lruwith|Some(data,t)->lru:=t;Somedata|None->Noneletfindkey=matchfind_updatekeyamainwith|Some_asresult->result|None->matchL.find~promote:falsekey!a1inwith|Some(data,_)->Somedata|None->matchL.find~promote:falsekey!a1outwith|Some(data,_)->a1out:=L.removekey!a1out;add_mainkeydata;Somedata|None->Noneletfind_and_replacekeydatalru=letfound=L.memkey!lruiniffoundthenlru:=L.add~trim:falsekeydata!lru;foundletreplacekeydata=ifnot(find_and_replacekeydataamain)thenifnot(find_and_replacekeydataa1in)thenifL.memkey!a1outthen(*BISECT-IGNORE-BEGIN*)begina1out:=L.removekey!a1out;add_mainkeydata;end(*BISECT-IGNORE-END*)elsebeginreclaim();add_a1inkeydataendend:Swithtypev=a)letfind(typea)(moduleCache:Swithtypev=a)=Cache.findletreplace(typea)(moduleCache:Swithtypev=a)=Cache.replaceend