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

more

Changed files
+102 -24
stack
cacheio
+102 -24
stack/cacheio/lib/cacheio.ml
···
(* Remove any existing file for this key *)
(match find_file t.base_dir key with
| Some (old_path, _, _) ->
-
(try Path.unlink old_path
with Eio.Io (Eio.Fs.E (Not_found _), _) -> ()
| e -> raise e)
| None -> ());
···
(* Create final filename and move *)
let final_name = key_to_filename ?ttl:ttl_abs ~flags key in
let final_path = Path.(dir / final_name) in
-
Path.rename temp_path final_path
(** {1 Basic Operations} *)
···
Mutex.use_rw ~protect:false t.mutex @@ fun () ->
match find_file t.base_dir key with
| Some (path, _, _) ->
-
(try Path.unlink path
with Eio.Io (Eio.Fs.E (Not_found _), _) -> ()
| e -> raise e)
| None -> ()
···
let dir2_path = Path.(dir1_path / dir2) in
try
List.fold_left (fun acc filename ->
-
match parse_filename filename with
-
| None -> acc
-
| Some (hash_rest, ttl, flags) ->
-
let path = Path.(dir2_path / filename) in
-
try
-
let stat = Path.stat ~follow:false path in
-
(* Reconstruct the original key from the hash *)
-
(* This is a limitation - we lose the original key *)
-
(* For now, use the hash as the key *)
-
let hash = dir1 ^ dir2 ^ hash_rest in
-
let entry = Entry.create
-
~key:hash
-
~size:(Optint.Int63.to_int64 stat.size)
-
~mtime:stat.mtime
-
~ttl
-
~flags
-
in
-
entry :: acc
-
with _ -> acc
) acc (Path.read_dir dir2_path)
with _ -> acc
) acc (Path.read_dir dir1_path)
···
(* Move to final location *)
let final_path = Path.(dir / filename) in
-
Path.rename temp_path final_path
let get_range t ~key ~range ~sw =
(* First check for complete file *)
···
let cleanup_chunks t ~key =
let chunks = list_chunks t ~key in
List.iter (fun chunk ->
-
try Path.unlink (Chunk.path chunk)
with _ -> ()
) chunks
···
(* Remove any existing file for this key *)
(match find_file t.base_dir key with
| Some (old_path, _, _) ->
+
(try
+
Path.unlink old_path;
+
(* Also remove the sidecar .key file if it exists *)
+
(* Get the parent directory and filename from the path *)
+
let dirs = key_to_dirs key in
+
let dir_path = List.fold_left (fun acc d -> Path.(acc / d)) t.base_dir dirs in
+
(* We need to find the actual filename to append .key to it *)
+
(match find_file t.base_dir key with
+
| Some (_, _, _) ->
+
(* The file was found, so let's find its name and remove the .key file *)
+
(try
+
let entries = Path.read_dir dir_path in
+
let hash = hash_key key in
+
let hash_rest = String.sub hash 4 (String.length hash - 4) in
+
List.iter (fun entry ->
+
if String.starts_with ~prefix:(hash_rest ^ ":2") entry then
+
let key_file_path = Path.(dir_path / (entry ^ ".key")) in
+
(try Path.unlink key_file_path with _ -> ())
+
) entries
+
with _ -> ())
+
| None -> ())
with Eio.Io (Eio.Fs.E (Not_found _), _) -> ()
| e -> raise e)
| None -> ());
···
(* Create final filename and move *)
let final_name = key_to_filename ?ttl:ttl_abs ~flags key in
let final_path = Path.(dir / final_name) in
+
Path.rename temp_path final_path;
+
+
(* Write the sidecar .key file containing the original key *)
+
let key_file_path = Path.(dir / (final_name ^ ".key")) in
+
Switch.run @@ fun sw ->
+
let key_sink = Path.open_out ~sw ~create:(`Or_truncate 0o644) key_file_path in
+
Flow.copy (Flow.string_source key) key_sink;
+
Flow.close key_sink
(** {1 Basic Operations} *)
···
Mutex.use_rw ~protect:false t.mutex @@ fun () ->
match find_file t.base_dir key with
| Some (path, _, _) ->
+
(try
+
Path.unlink path;
+
(* Also remove the sidecar .key file if it exists *)
+
(* Since we have the full path, we need to extract the directory and filename *)
+
let dirs = key_to_dirs key in
+
let dir_path = List.fold_left (fun acc d -> Path.(acc / d)) t.base_dir dirs in
+
(try
+
let entries = Path.read_dir dir_path in
+
let hash = hash_key key in
+
let hash_rest = String.sub hash 4 (String.length hash - 4) in
+
List.iter (fun entry ->
+
if String.starts_with ~prefix:(hash_rest ^ ":2") entry then
+
let key_file_path = Path.(dir_path / (entry ^ ".key")) in
+
(try Path.unlink key_file_path with _ -> ())
+
) entries
+
with _ -> ())
with Eio.Io (Eio.Fs.E (Not_found _), _) -> ()
| e -> raise e)
| None -> ()
···
let dir2_path = Path.(dir1_path / dir2) in
try
List.fold_left (fun acc filename ->
+
(* Skip .key files themselves *)
+
if String.ends_with ~suffix:".key" filename then
+
acc
+
else
+
match parse_filename filename with
+
| None -> acc
+
| Some (hash_rest, ttl, flags) ->
+
let path = Path.(dir2_path / filename) in
+
try
+
let stat = Path.stat ~follow:false path in
+
(* Try to read the original key from the sidecar file *)
+
let key =
+
let key_path = Path.(dir2_path / (filename ^ ".key")) in
+
try
+
Switch.run @@ fun sw ->
+
let source = Path.open_in ~sw key_path in
+
let buf_read = Eio.Buf_read.of_flow ~max_size:4096 source in
+
let content = Eio.Buf_read.take_all buf_read in
+
Eio.Flow.close source;
+
content
+
with _ ->
+
(* Fall back to using the hash if sidecar file doesn't exist *)
+
dir1 ^ dir2 ^ hash_rest
+
in
+
let entry = Entry.create
+
~key
+
~size:(Optint.Int63.to_int64 stat.size)
+
~mtime:stat.mtime
+
~ttl
+
~flags
+
in
+
entry :: acc
+
with _ -> acc
) acc (Path.read_dir dir2_path)
with _ -> acc
) acc (Path.read_dir dir1_path)
···
(* Move to final location *)
let final_path = Path.(dir / filename) in
+
Path.rename temp_path final_path;
+
+
(* Write the sidecar .key file for chunks too *)
+
let key_file_path = Path.(dir / (filename ^ ".key")) in
+
Switch.run @@ fun sw ->
+
let key_sink = Path.open_out ~sw ~create:(`Or_truncate 0o644) key_file_path in
+
Flow.copy (Flow.string_source key) key_sink;
+
Flow.close key_sink
let get_range t ~key ~range ~sw =
(* First check for complete file *)
···
let cleanup_chunks t ~key =
let chunks = list_chunks t ~key in
List.iter (fun chunk ->
+
try
+
let path = Chunk.path chunk in
+
Path.unlink path;
+
(* Also remove the sidecar .key file if it exists *)
+
(* We need to derive the key file path from the chunk path *)
+
(* Since chunk.path is the full path to the chunk file, we can't decompose it easily *)
+
(* Instead, let's find and remove any matching .key files in the directory *)
+
let dirs = key_to_dirs (Chunk.key chunk) in
+
let dir_path = List.fold_left (fun acc d -> Path.(acc / d)) t.base_dir dirs in
+
(try
+
let entries = Path.read_dir dir_path in
+
List.iter (fun entry ->
+
if String.ends_with ~suffix:".key" entry && String.starts_with ~prefix:(Chunk.hash chunk |> fun h -> String.sub h 4 (String.length h - 4)) entry then
+
(try Path.unlink Path.(dir_path / entry) with _ -> ())
+
) entries
+
with _ -> ())
with _ -> ()
) chunks