-
Notifications
You must be signed in to change notification settings - Fork 0
/
file-system-blob-store.js
127 lines (106 loc) · 2.87 KB
/
file-system-blob-store.js
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
'use strict'
const fs = require('fs-plus')
const path = require('path')
module.exports =
class FileSystemBlobStore {
static load (directory) {
let instance = new FileSystemBlobStore(directory)
instance.load()
return instance
}
constructor (directory) {
this.blobFilename = path.join(directory, 'BLOB')
this.blobMapFilename = path.join(directory, 'MAP')
this.lockFilename = path.join(directory, 'LOCK')
this.reset()
}
reset () {
this.inMemoryBlobs = new Map()
this.storedBlob = new Buffer(0)
this.storedBlobMap = {}
this.usedKeys = new Set()
}
load () {
if (!fs.existsSync(this.blobMapFilename)) {
return
}
if (!fs.existsSync(this.blobFilename)) {
return
}
try {
this.storedBlob = fs.readFileSync(this.blobFilename)
this.storedBlobMap = JSON.parse(fs.readFileSync(this.blobMapFilename))
} catch (e) {
this.reset()
}
}
save () {
let dump = this.getDump()
let blobToStore = Buffer.concat(dump[0])
let mapToStore = JSON.stringify(dump[1])
let acquiredLock = false
try {
fs.writeFileSync(this.lockFilename, 'LOCK', {flag: 'wx'})
acquiredLock = true
fs.writeFileSync(this.blobFilename, blobToStore)
fs.writeFileSync(this.blobMapFilename, mapToStore)
} catch (error) {
// Swallow the exception silently only if we fail to acquire the lock.
if (error.code !== 'EEXIST') {
throw error
}
} finally {
if (acquiredLock) {
fs.unlinkSync(this.lockFilename)
}
}
}
has (key) {
return this.inMemoryBlobs.has(key) || this.storedBlobMap.hasOwnProperty(key)
}
get (key) {
if (this.has(key)) {
this.usedKeys.add(key)
return this.getFromMemory(key) || this.getFromStorage(key)
}
}
set (key, buffer) {
this.usedKeys.add(key)
return this.inMemoryBlobs.set(key, buffer)
}
delete (key) {
this.inMemoryBlobs.delete(key)
delete this.storedBlobMap[key]
}
getFromMemory (key) {
return this.inMemoryBlobs.get(key)
}
getFromStorage (key) {
if (!this.storedBlobMap[key]) {
return
}
return this.storedBlob.slice.apply(this.storedBlob, this.storedBlobMap[key])
}
getDump () {
let buffers = []
let blobMap = {}
let currentBufferStart = 0
function dump (key, getBufferByKey) {
let buffer = getBufferByKey(key)
buffers.push(buffer)
blobMap[key] = [currentBufferStart, currentBufferStart + buffer.length]
currentBufferStart += buffer.length
}
for (let key of this.inMemoryBlobs.keys()) {
if (this.usedKeys.has(key)) {
dump(key, this.getFromMemory.bind(this))
}
}
for (let key of Object.keys(this.storedBlobMap)) {
if (!blobMap[key] && this.usedKeys.has(key)) {
dump(key, this.getFromStorage.bind(this))
}
}
return [buffers, blobMap]
}
}