123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293(*
* 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=function|[]->""|hd::_->hdletparent=function|_::tl->tl|[]->[]letcompare=compareletequal=(=)letppppfl=Fmt.(any"/"++(list~sep:(any"/")Dump.string))ppf(List.revl)letto_stringk="/"^String.concat"/"(List.revk)endtypekey=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.ttypetvaldisconnect:t->unitLwt.ttypekey=Key.tvalexists:t->key->([`Value|`Dictionary]option,error)resultLwt.tvalget:t->key->(string,error)resultLwt.tvalget_partial:t->key->offset:int->length:int->(string,error)resultLwt.tvallist:t->key->((string*[`Value|`Dictionary])list,error)resultLwt.tvallast_modified:t->key->(int*int64,error)resultLwt.tvaldigest:t->key->(string,error)resultLwt.tvalsize:t->key->(int,error)resultLwt.tendtypewrite_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->string->(unit,write_error)resultLwt.tvalset_partial:t->key->offset:int->string->(unit,write_error)resultLwt.tvalremove:t->key->(unit,write_error)resultLwt.tvalrename:t->source:key->dest:key->(unit,write_error)resultLwt.tvalbatch:t->?retries:int->(t->'aLwt.t)->'aLwt.tend