-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathDiskMap.fs
More file actions
94 lines (74 loc) · 3.21 KB
/
Copy pathDiskMap.fs
File metadata and controls
94 lines (74 loc) · 3.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
namespace Tensor.Utils
open System
open System.IO
open System.Linq
open System.Threading
open System.Security.Cryptography
/// a filesystem backed map for binary keys and values
type internal DiskBinaryMap (baseDir: string, keyFilename: string, valueFilename: string) =
let sha1 = new SHA1CryptoServiceProvider()
do
if baseDir.Length = 0 then
invalidArg "baseDir" "baseDir cannot be empty"
let hashDirForKey (key: byte[]) =
let keyHash =
sha1.ComputeHash key
|> Convert.ToBase64String
|> fun s -> [yield 'K'
for c in s.ToLower() do
if 'a' <= c && c <= 'z' then yield c]
|> List.toArray
|> String
Path.Combine(baseDir, keyHash)
let tryGetDirAndValueForKey (key: byte []) =
try
if Directory.Exists (hashDirForKey key) then
Directory.EnumerateDirectories (hashDirForKey key)
|> Seq.tryPick (fun dir ->
let keyPath = Path.Combine (dir, keyFilename)
let valuePath = Path.Combine (dir, valueFilename)
if File.Exists keyPath && File.Exists valuePath then
if key.SequenceEqual (File.ReadAllBytes keyPath) then
Some (dir, File.ReadAllBytes valuePath)
else None
else None)
else None
with :? IOException as excp ->
printfn "DiskMap: IOException while reading: %s" excp.Message
None
let tryIOWrite ioFunc =
let rng = System.Random ()
let rec performTry nRetries =
try ioFunc ()
with :? IOException as excp when nRetries < 10 ->
printfn "DiskMap: retrying due to IOException while writing: %s" excp.Message
Thread.Sleep 100
Thread.Sleep (rng.Next(100))
performTry (nRetries + 1)
performTry 0
new (baseDir: string) = DiskBinaryMap(baseDir, "key.dat", "value.dat")
member this.TryGet key =
match tryGetDirAndValueForKey key with
| Some (_, value) -> Some value
| None -> None
member this.Get key =
match this.TryGet key with
| Some value -> value
| None -> raise (System.Collections.Generic.KeyNotFoundException())
member this.Remove key =
match tryGetDirAndValueForKey key with
| Some (dir, _) -> tryIOWrite (fun () -> Directory.Delete (dir, true))
| None -> raise (System.Collections.Generic.KeyNotFoundException())
member this.Set key value =
let dir =
match tryGetDirAndValueForKey key with
| Some (dir, _) -> dir
| None -> Path.Combine (hashDirForKey key, Guid.NewGuid().ToString())
let keyPath = Path.Combine (dir, keyFilename)
let valuePath = Path.Combine (dir, valueFilename)
tryIOWrite (fun () ->
Directory.CreateDirectory dir |> ignore
File.WriteAllBytes (keyPath, key)
File.WriteAllBytes (valuePath, value))
member this.Clear () =
tryIOWrite (fun () -> Directory.Delete (baseDir, true))