My agentic slop goes here. Not intended for anyone else!

more

+1 -1
stack/cacheio/bin/cache_cli.ml
···
`P "This tool provides subcommands for listing, clearing, and managing cached files.";
] in
let info = Cmd.info "cache" ~doc ~man in
-
let cmd = Cmd.group info (Cacheio_cmd.make_commands ~app_name fs) in
+
let cmd = Cmd.group info (Cacheio_cmd.Cmd.make_commands ~app_name fs) in
exit (Cmd.eval cmd)
+1 -1
stack/cacheio/bin/dune
···
(executable
(public_name cache-cli)
(name cache_cli)
-
(libraries cacheio.cmd cmdliner))
+
(libraries cacheio.cmd cmdliner eio_main))
+5 -1
stack/cacheio/bin/example.ml
···
let setup_logs () =
Logs.set_level (Some Logs.Info);
-
Logs.set_reporter (Logs_fmt.reporter ())
+
let reporter = Logs.format_reporter
+
~pp_header:Logs.pp_header
+
~app:Format.std_formatter
+
~dst:Format.err_formatter () in
+
Logs.set_reporter reporter
(** Example: Using CacheIO for caching data *)
let cache_example env sw =
+5 -5
stack/cacheio/lib/cacheio.ml
···
open Eio
(** Module aliases *)
-
module Flags = Cacheio_flags
-
module Entry = Cacheio_entry
-
module Stats = Cacheio_stats
+
module Flags = Flags
+
module Entry = Entry
+
module Stats = Stats
(** {1 Internal Key Management} *)
···
(** {1 Chunk Support} *)
-
module Range = Cacheio_range
-
module Chunk = Cacheio_chunk
+
module Range = Range
+
module Chunk = Chunk
let put_chunk t ~key ~range ~source ?(ttl=None) ?(flags=Flags.empty) () =
(* Add Chunk flag *)
+37 -12
stack/cacheio/lib/cacheio.mli
···
-
(** File-backed cache with streaming API and TTL support
+
(** File-backed persistent cache with streaming API and TTL support
+
+
Cacheio provides a robust file-backed caching system designed for high-performance
+
applications that need persistent storage with automatic expiry management.
+
+
{2 Key Features}
+
+
- {b SHA256-based key hashing}: Uniform distribution across subdirectories
+
- {b Maildir++-style naming}: Atomic operations with flag and TTL encoding
+
- {b Streaming API}: Built on Eio.Flow for efficient, non-blocking I/O
+
- {b Automatic expiry}: TTL-based cache expiration with manual control
+
- {b Thread-safe}: All operations are safe for concurrent access
+
- {b Chunk support}: Resume partial downloads with range-based chunks
+
- {b XDG integration}: Automatic directory management via XDG Base Directory spec
+
+
{2 Usage Example}
+
+
{[
+
let cache = Cacheio.create ~base_dir:cache_dir in
+
+
(* Store data with 1 hour TTL *)
+
Eio.Switch.run @@ fun sw ->
+
let source = Eio.Flow.string_source "Hello, World!" in
+
Cacheio.put cache ~key:"greeting" ~source ~ttl:(Some 3600.0) ();
-
This module provides a file-backed cache implementation with:
-
- SHA256-based key hashing for uniform distribution
-
- Maildir++-style filename encoding with TTL and flags
-
- Streaming API using Eio.Flow for efficient I/O
-
- Automatic expiry management
-
- Thread-safe operations *)
+
(* Retrieve data *)
+
Eio.Switch.run @@ fun sw ->
+
match Cacheio.get cache ~key:"greeting" ~sw with
+
| Some source ->
+
let content = Eio.Buf_read.(parse_exn take_all) source ~max_size:Int.max_int in
+
print_endline content
+
| None -> print_endline "Not found"
+
]}*)
(** {1 Core Operations} *)
···
val get : t -> key:string -> sw:Eio.Switch.t -> Eio.Flow.source_ty Eio.Resource.t option
(** Cache flags management *)
-
module Flags = Cacheio_flags
+
module Flags = Flags
(** Store data from a stream source with optional TTL and flags *)
val put : t -> key:string -> source:Eio.Flow.source_ty Eio.Resource.t ->
···
(** {1 Cache Management} *)
(** Cache entry information *)
-
module Entry = Cacheio_entry
+
module Entry = Entry
(** Cache statistics *)
-
module Stats = Cacheio_stats
+
module Stats = Stats
(** Scan the cache and return all entries *)
val scan : t -> Entry.t list
···
(** {1 Chunk Support for Partial Downloads} *)
(** Range management for partial downloads *)
-
module Range = Cacheio_range
+
module Range = Range
(** Chunk file management *)
-
module Chunk = Cacheio_chunk
+
module Chunk = Chunk
(** Store a chunk of data with a specific byte range *)
val put_chunk : t -> key:string -> range:Range.t ->
+2 -2
stack/cacheio/lib/cacheio_chunk.ml stack/cacheio/lib/chunk.ml
···
open Eio
-
module Range = Cacheio_range
-
module Flags = Cacheio_flags
+
module Range = Range
+
module Flags = Flags
type t = {
key : string;
-45
stack/cacheio/lib/cacheio_chunk.mli
···
-
(** Chunk file management for partial downloads *)
-
-
(** Information about a chunk file *)
-
type t
-
-
(** Get the key *)
-
val key : t -> string
-
-
(** Get the hash *)
-
val hash : t -> string
-
-
(** Get the range *)
-
val range : t -> Cacheio_range.t
-
-
(** Get the path *)
-
val path : t -> Eio.Fs.dir_ty Eio.Path.t
-
-
(** Get the flags *)
-
val flags : t -> Cacheio_flags.t
-
-
(** Get the TTL *)
-
val ttl : t -> float option
-
-
(** Parse a chunk from a filename and path *)
-
val parse : path:Eio.Fs.dir_ty Eio.Path.t -> filename:string -> t option
-
-
(** Generate a chunk filename *)
-
val make_filename : hash:string -> range:Cacheio_range.t ->
-
?ttl:float -> ?flags:Cacheio_flags.t -> unit -> string
-
-
(** Find all chunks for a key in a directory structure *)
-
val find_chunks : base_dir:Eio.Fs.dir_ty Eio.Path.t ->
-
key:string -> t list
-
-
(** Check if chunks form a complete sequence *)
-
val is_complete_sequence : t list -> total_size:int64 -> bool
-
-
(** Get missing ranges from a list of chunks *)
-
val missing_ranges : t list -> total_size:int64 -> Cacheio_range.t list
-
-
(** Sort chunks by range start position *)
-
val sort_by_range : t list -> t list
-
-
(** Pretty printer *)
-
val pp : Format.formatter -> t -> unit
stack/cacheio/lib/cacheio_cmd.ml stack/cacheio/lib/cmd.ml
stack/cacheio/lib/cacheio_cmd.mli stack/cacheio/lib/cmd.mli
+5 -5
stack/cacheio/lib/cacheio_entry.ml stack/cacheio/lib/entry.ml
···
size : int64;
mtime : float;
ttl : float option;
-
flags : Cacheio_flags.t;
+
flags : Flags.t;
}
let create ~key ~size ~mtime ~ttl ~flags =
···
| Some expiry -> Unix.time () > expiry
let is_pinned t =
-
Cacheio_flags.is_pinned t.flags
+
Flags.is_pinned t.flags
let is_stale t =
-
Cacheio_flags.is_stale t.flags
+
Flags.is_stale t.flags
let is_temporary t =
-
Cacheio_flags.is_temporary t.flags
+
Flags.is_temporary t.flags
let compare_by_mtime a b =
Float.compare a.mtime b.mtime
···
(match t.ttl with
| None -> "never"
| Some exp -> Printf.sprintf "%.1f" exp)
-
Cacheio_flags.pp t.flags
+
Flags.pp t.flags
+2 -2
stack/cacheio/lib/cacheio_entry.mli stack/cacheio/lib/entry.mli
···
(** Create an entry from components *)
val create : key:string -> size:int64 -> mtime:float -> ttl:float option ->
-
flags:Cacheio_flags.t -> t
+
flags:Flags.t -> t
(** {1 Accessors} *)
···
val ttl : t -> float option
(** Get the flags *)
-
val flags : t -> Cacheio_flags.t
+
val flags : t -> Flags.t
(** {1 Predicates} *)
stack/cacheio/lib/cacheio_flags.ml stack/cacheio/lib/flags.ml
+10 -6
stack/cacheio/lib/cacheio_flags.mli stack/cacheio/lib/flags.mli
···
(** Cache entry flags management
-
This module handles flags that can be attached to cache entries
-
to control their behavior and lifecycle. *)
+
This module provides a type-safe interface for managing cache entry flags.
+
Flags control entry behavior such as pinning (preventing eviction),
+
marking entries as stale (needing revalidation), or temporary.
+
+
Flags are encoded in the filesystem using Maildir++-style conventions,
+
making them persistent across program restarts and visible to external tools. *)
(** Abstract type representing a set of flags *)
type t
(** Individual flag types *)
type flag = [
-
| `Pinned (** Entry is pinned and won't be evicted *)
-
| `Stale (** Entry needs revalidation *)
-
| `Temporary (** Entry is temporary and can be cleared *)
-
| `Chunk (** Entry is a partial chunk of a file *)
+
| `Pinned (** Entry is pinned and won't be automatically evicted during cleanup *)
+
| `Stale (** Entry needs revalidation before use *)
+
| `Temporary (** Entry is temporary and will be removed on cache clear *)
+
| `Chunk (** Entry is a partial chunk of a larger file (used for resume support) *)
]
(** {1 Construction} *)
stack/cacheio/lib/cacheio_range.ml stack/cacheio/lib/range.ml
-40
stack/cacheio/lib/cacheio_range.mli
···
-
(** Byte range management for partial downloads *)
-
-
(** A byte range with inclusive start and end positions *)
-
type t
-
-
(** Create a range from start to end (inclusive) *)
-
val create : start:int64 -> end_:int64 -> t
-
-
(** Get the start position *)
-
val start : t -> int64
-
-
(** Get the end position (inclusive) *)
-
val end_ : t -> int64
-
-
(** Calculate the length of a range *)
-
val length : t -> int64
-
-
(** Check if two ranges are adjacent (no gap between them) *)
-
val adjacent : t -> t -> bool
-
-
(** Check if two ranges overlap *)
-
val overlaps : t -> t -> bool
-
-
(** Check if a range contains a position *)
-
val contains : t -> int64 -> bool
-
-
(** Merge two ranges if they overlap or are adjacent *)
-
val merge : t -> t -> t option
-
-
(** Compare ranges by start position *)
-
val compare : t -> t -> int
-
-
(** Convert to string format "start-end" *)
-
val to_string : t -> string
-
-
(** Parse from string format "start-end" *)
-
val of_string : string -> t option
-
-
(** Pretty printer *)
-
val pp : Format.formatter -> t -> unit
+1 -1
stack/cacheio/lib/cacheio_stats.ml stack/cacheio/lib/stats.ml
···
let of_entries entries =
List.fold_left (fun acc entry ->
-
let open Cacheio_entry in
+
let open Entry in
{ total_size = Int64.add acc.total_size (size entry);
entry_count = acc.entry_count + 1;
expired_count = acc.expired_count + (if is_expired entry then 1 else 0);
+1 -1
stack/cacheio/lib/cacheio_stats.mli stack/cacheio/lib/stats.mli
···
pinned_count:int -> stale_count:int -> temporary_count:int -> t
(** Compute statistics from a list of entries *)
-
val of_entries : Cacheio_entry.t list -> t
+
val of_entries : Entry.t list -> t
(** {1 Accessors} *)
+53
stack/cacheio/lib/chunk.mli
···
+
(** Chunk file management for partial downloads and resumable transfers
+
+
This module manages partial cache entries (chunks) that can be combined
+
to form complete files. Chunks enable resumable downloads and efficient
+
caching of large files by storing byte ranges independently.
+
+
Each chunk is stored as a separate file with range information encoded
+
in its filename, allowing the cache to resume interrupted downloads
+
and serve partial content requests efficiently. *)
+
+
(** Information about a chunk file *)
+
type t
+
+
(** Get the key *)
+
val key : t -> string
+
+
(** Get the hash *)
+
val hash : t -> string
+
+
(** Get the range *)
+
val range : t -> Range.t
+
+
(** Get the path *)
+
val path : t -> Eio.Fs.dir_ty Eio.Path.t
+
+
(** Get the flags *)
+
val flags : t -> Flags.t
+
+
(** Get the TTL *)
+
val ttl : t -> float option
+
+
(** Parse a chunk from a filename and path *)
+
val parse : path:Eio.Fs.dir_ty Eio.Path.t -> filename:string -> t option
+
+
(** Generate a chunk filename *)
+
val make_filename : hash:string -> range:Range.t ->
+
?ttl:float -> ?flags:Flags.t -> unit -> string
+
+
(** Find all chunks for a key in a directory structure *)
+
val find_chunks : base_dir:Eio.Fs.dir_ty Eio.Path.t ->
+
key:string -> t list
+
+
(** Check if chunks form a complete sequence *)
+
val is_complete_sequence : t list -> total_size:int64 -> bool
+
+
(** Get missing ranges from a list of chunks *)
+
val missing_ranges : t list -> total_size:int64 -> Range.t list
+
+
(** Sort chunks by range start position *)
+
val sort_by_range : t list -> t list
+
+
(** Pretty printer *)
+
val pp : Format.formatter -> t -> unit
+2 -2
stack/cacheio/lib/dune
···
(library
(public_name cacheio)
(name cacheio)
-
(modules cacheio cacheio_flags cacheio_entry cacheio_stats cacheio_range cacheio_chunk)
+
(modules cacheio flags entry stats range chunk)
(libraries eio eio_main digestif yojson ptime ptime.clock.os logs fmt xdge mirage-crypto-rng cstruct))
(library
(public_name cacheio.cmd)
(name cacheio_cmd)
-
(modules cacheio_cmd)
+
(modules cmd)
(libraries cacheio cmdliner eio eio_main xdge))
+57
stack/cacheio/lib/range.mli
···
+
(** Byte range management for partial downloads and chunked caching
+
+
This module provides utilities for working with byte ranges,
+
primarily used for HTTP Range requests and partial file caching.
+
Ranges are inclusive on both ends (e.g., bytes 0-99 includes 100 bytes).
+
+
{2 Example}
+
+
{[
+
let r1 = Range.create ~start:0L ~end_:999L in
+
let r2 = Range.create ~start:1000L ~end_:1999L in
+
assert (Range.adjacent r1 r2 = true);
+
assert (Range.length r1 = 1000L);
+
match Range.merge r1 r2 with
+
| Some merged -> assert (Range.length merged = 2000L)
+
| None -> failwith "Should merge"
+
]}*)
+
+
(** A byte range with inclusive start and end positions.
+
For example, range [0,99] includes bytes 0 through 99 (100 bytes total). *)
+
type t
+
+
(** Create a range from start to end (inclusive) *)
+
val create : start:int64 -> end_:int64 -> t
+
+
(** Get the start position *)
+
val start : t -> int64
+
+
(** Get the end position (inclusive) *)
+
val end_ : t -> int64
+
+
(** Calculate the length of a range *)
+
val length : t -> int64
+
+
(** Check if two ranges are adjacent (no gap between them) *)
+
val adjacent : t -> t -> bool
+
+
(** Check if two ranges overlap *)
+
val overlaps : t -> t -> bool
+
+
(** Check if a range contains a position *)
+
val contains : t -> int64 -> bool
+
+
(** Merge two ranges if they overlap or are adjacent *)
+
val merge : t -> t -> t option
+
+
(** Compare ranges by start position *)
+
val compare : t -> t -> int
+
+
(** Convert to string format "start-end" *)
+
val to_string : t -> string
+
+
(** Parse from string format "start-end" *)
+
val of_string : string -> t option
+
+
(** Pretty printer *)
+
val pp : Format.formatter -> t -> unit