1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889(*
* Copyright (c) 2011-2015 Anil Madhavapeddy <anil@recoil.org>
* Copyright (c) 2013-2015 Thomas Gazagnaire <thomas@gazagnaire.org>
* Copyright (c) 2013 Citrix Systems Inc
*
* 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.
*)moduleKey=structtypet=stringlist(* Store the path as a reverse list to optimise basename and (/)
operations *)leterr_invalid_segmentx=Fmt.failwith"%S is not a valid segment"xletcheck_segmentx=String.iter(function'/'->err_invalid_segmentx|_->())x;xletempty=[]letvs=List.filter((<>)"")@@List.rev(String.split_on_char'/'s)letaddtv=(check_segmentv)::tlet(/)=addletappendxy=y@xlet(//)=appendletsegments=List.revletbasename=List.hdletparent=List.tlletcompare=compareletequal=(=)letppppfl=Fmt.pfppf"/%a"Fmt.(list~sep:(unit"/")string)(List.revl)letto_string=Fmt.to_to_stringppendtypekey=Key.ttypeerror=[|`Not_foundofkey|`Dictionary_expectedofkey|`Value_expectedofkey]letpp_errorppf=function|`Not_foundk->Fmt.pfppf"Cannot find the key %a"Key.ppk|`Dictionary_expectedk->Fmt.pfppf"Expecting a dictionary for the key %a"Key.ppk|`Value_expectedk->Fmt.pfppf"Expecting a value for the key %a"Key.ppkmoduletypeRO=sigtypenonrecerror=private[>error]valpp_error:errorFmt.tincludeMirage_device.Stypekey=Key.ttypevaluevalexists:t->key->([`Value|`Dictionary]option,error)resultiovalget:t->key->(value,error)resultiovallist:t->key->((string*[`Value|`Dictionary])list,error)resultiovallast_modified:t->key->(int*int64,error)resultiovaldigest:t->key->(string,error)resultioendtypewrite_error=[error|`No_space|`Too_many_retriesofint]letpp_write_errorppf=function|#errorase->pp_errorppfe|`No_space->Fmt.pfppf"No space left on device"|`Too_many_retriesn->Fmt.pfppf"Aborting after %d attempts to apply the batch operations."nmoduletypeRW=sigincludeROtypenonrecwrite_error=private[>write_error]valpp_write_error:write_errorFmt.tvalset:t->key->value->(unit,write_error)resultiovalremove:t->key->(unit,write_error)resultiovalbatch:t->?retries:int->(t->'aio)->'aioend