Skip to content

Commit db1e094

Browse files
committed
feat(get): add sync API for reading
1 parent 93b0893 commit db1e094

File tree

6 files changed

+199
-25
lines changed

6 files changed

+199
-25
lines changed

Diff for: get.js

+49
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,55 @@ function getData (byDigest, cache, key, opts) {
6363
})
6464
}
6565

66+
module.exports.sync = function get (cache, key, opts) {
67+
return getDataSync(false, cache, key, opts)
68+
}
69+
module.exports.sync.byDigest = function getByDigest (cache, digest, opts) {
70+
return getDataSync(true, cache, digest, opts)
71+
}
72+
function getDataSync (byDigest, cache, key, opts) {
73+
opts = GetOpts(opts)
74+
const memoized = (
75+
byDigest
76+
? memo.get.byDigest(cache, key, opts)
77+
: memo.get(cache, key, opts)
78+
)
79+
if (memoized && opts.memoize !== false) {
80+
return byDigest ? memoized : {
81+
metadata: memoized.entry.metadata,
82+
data: memoized.data,
83+
integrity: memoized.entry.integrity,
84+
size: memoized.entry.size
85+
}
86+
}
87+
const entry = !byDigest && index.find.sync(cache, key, opts)
88+
if (!entry && !byDigest) {
89+
throw new index.NotFoundError(cache, key)
90+
}
91+
const data = read.sync(
92+
cache,
93+
byDigest ? key : entry.integrity,
94+
{
95+
integrity: opts.integrity,
96+
size: opts.size
97+
}
98+
)
99+
const res = byDigest
100+
? data
101+
: {
102+
metadata: entry.metadata,
103+
data: data,
104+
size: entry.size,
105+
integrity: entry.integrity
106+
}
107+
if (opts.memoize && byDigest) {
108+
memo.put.byDigest(cache, key, res, opts)
109+
} else if (opts.memoize) {
110+
memo.put(cache, entry, res.data, opts)
111+
}
112+
return res
113+
}
114+
66115
module.exports.stream = getStream
67116
function getStream (cache, key, opts) {
68117
opts = GetOpts(opts)

Diff for: lib/entry-index.js

+82-25
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,36 @@ function insert (cache, key, integrity, opts) {
7575
})
7676
}
7777

78+
module.exports.insert.sync = insertSync
79+
function insertSync (cache, key, integrity, opts) {
80+
opts = IndexOpts(opts)
81+
const bucket = bucketPath(cache, key)
82+
const entry = {
83+
key,
84+
integrity: integrity && ssri.stringify(integrity),
85+
time: Date.now(),
86+
size: opts.size,
87+
metadata: opts.metadata
88+
}
89+
fixOwner.mkdirfix.sync(path.dirname(bucket), opts.uid, opts.gid)
90+
const stringified = JSON.stringify(entry)
91+
fs.appendFileSync(
92+
bucket, `\n${hashEntry(stringified)}\t${stringified}`
93+
)
94+
try {
95+
fixOwner.chownr.sync(bucket, opts.uid, opts.gid)
96+
} catch (err) {
97+
if (err.code !== 'ENOENT') {
98+
throw err
99+
}
100+
}
101+
return formatEntry(cache, entry)
102+
}
103+
78104
module.exports.find = find
79105
function find (cache, key) {
80106
const bucket = bucketPath(cache, key)
81-
return bucketEntries(cache, bucket).then(entries => {
107+
return bucketEntries(bucket).then(entries => {
82108
return entries.reduce((latest, next) => {
83109
if (next && next.key === key) {
84110
return formatEntry(cache, next)
@@ -95,11 +121,36 @@ function find (cache, key) {
95121
})
96122
}
97123

124+
module.exports.find.sync = findSync
125+
function findSync (cache, key) {
126+
const bucket = bucketPath(cache, key)
127+
try {
128+
return bucketEntriesSync(bucket).reduce((latest, next) => {
129+
if (next && next.key === key) {
130+
return formatEntry(cache, next)
131+
} else {
132+
return latest
133+
}
134+
}, null)
135+
} catch (err) {
136+
if (err.code === 'ENOENT') {
137+
return null
138+
} else {
139+
throw err
140+
}
141+
}
142+
}
143+
98144
module.exports.delete = del
99145
function del (cache, key, opts) {
100146
return insert(cache, key, null, opts)
101147
}
102148

149+
module.exports.delete.sync = delSync
150+
function delSync (cache, key, opts) {
151+
return insertSync(cache, key, null, opts)
152+
}
153+
103154
module.exports.lsStream = lsStream
104155
function lsStream (cache) {
105156
const indexDir = bucketDir(cache)
@@ -116,7 +167,6 @@ function lsStream (cache) {
116167
// "/cachename/<bucket 0xFF>/<bucket 0xFF>/*"
117168
return readdirOrEmpty(subbucketPath).map(entry => {
118169
const getKeyToEntry = bucketEntries(
119-
cache,
120170
path.join(subbucketPath, entry)
121171
).reduce((acc, entry) => {
122172
acc.set(entry.key, entry)
@@ -152,32 +202,39 @@ function ls (cache) {
152202
})
153203
}
154204

155-
function bucketEntries (cache, bucket, filter) {
205+
function bucketEntries (bucket, filter) {
156206
return readFileAsync(
157207
bucket, 'utf8'
158-
).then(data => {
159-
let entries = []
160-
data.split('\n').forEach(entry => {
161-
if (!entry) { return }
162-
const pieces = entry.split('\t')
163-
if (!pieces[1] || hashEntry(pieces[1]) !== pieces[0]) {
164-
// Hash is no good! Corruption or malice? Doesn't matter!
165-
// EJECT EJECT
166-
return
167-
}
168-
let obj
169-
try {
170-
obj = JSON.parse(pieces[1])
171-
} catch (e) {
172-
// Entry is corrupted!
173-
return
174-
}
175-
if (obj) {
176-
entries.push(obj)
177-
}
178-
})
179-
return entries
208+
).then(data => _bucketEntries(data, filter))
209+
}
210+
211+
function bucketEntriesSync (bucket, filter) {
212+
const data = fs.readFileSync(bucket, 'utf8')
213+
return _bucketEntries(data, filter)
214+
}
215+
216+
function _bucketEntries (data, filter) {
217+
let entries = []
218+
data.split('\n').forEach(entry => {
219+
if (!entry) { return }
220+
const pieces = entry.split('\t')
221+
if (!pieces[1] || hashEntry(pieces[1]) !== pieces[0]) {
222+
// Hash is no good! Corruption or malice? Doesn't matter!
223+
// EJECT EJECT
224+
return
225+
}
226+
let obj
227+
try {
228+
obj = JSON.parse(pieces[1])
229+
} catch (e) {
230+
// Entry is corrupted!
231+
return
232+
}
233+
if (obj) {
234+
entries.push(obj)
235+
}
180236
})
237+
return entries
181238
}
182239

183240
module.exports._bucketDir = bucketDir

Diff for: lib/util/fix-owner.js

+46
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,34 @@ function fixOwner (filepath, uid, gid) {
3131
)
3232
}
3333

34+
module.exports.chownr.sync = fixOwnerSync
35+
function fixOwnerSync (filepath, uid, gid) {
36+
if (!process.getuid) {
37+
// This platform doesn't need ownership fixing
38+
return
39+
}
40+
if (typeof uid !== 'number' && typeof gid !== 'number') {
41+
// There's no permissions override. Nothing to do here.
42+
return
43+
}
44+
if ((typeof uid === 'number' && process.getuid() === uid) &&
45+
(typeof gid === 'number' && process.getgid() === gid)) {
46+
// No need to override if it's already what we used.
47+
return
48+
}
49+
try {
50+
chownr.sync(
51+
filepath,
52+
typeof uid === 'number' ? uid : process.getuid(),
53+
typeof gid === 'number' ? gid : process.getgid()
54+
)
55+
} catch (err) {
56+
if (err.code === 'ENOENT') {
57+
return null
58+
}
59+
}
60+
}
61+
3462
module.exports.mkdirfix = mkdirfix
3563
function mkdirfix (p, uid, gid, cb) {
3664
return mkdirp(p).then(made => {
@@ -42,3 +70,21 @@ function mkdirfix (p, uid, gid, cb) {
4270
return fixOwner(p, uid, gid).then(() => null)
4371
})
4472
}
73+
74+
module.exports.mkdirfix.sync = mkdirfixSync
75+
function mkdirfixSync (p, uid, gid) {
76+
try {
77+
const made = mkdirp.sync(p)
78+
if (made) {
79+
fixOwnerSync(made, uid, gid)
80+
return made
81+
}
82+
} catch (err) {
83+
if (err.code === 'EEXIST') {
84+
fixOwnerSync(p, uid, gid)
85+
return null
86+
} else {
87+
throw err
88+
}
89+
}
90+
}

Diff for: locales/en.js

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ x.ls.stream = cache => ls.stream(cache)
1818

1919
x.get = (cache, key, opts) => get(cache, key, opts)
2020
x.get.byDigest = (cache, hash, opts) => get.byDigest(cache, hash, opts)
21+
x.get.sync = (cache, key, opts) => get.sync(cache, key, opts)
22+
x.get.sync.byDigest = (cache, key, opts) => get.sync.byDigest(cache, key, opts)
2123
x.get.stream = (cache, key, opts) => get.stream(cache, key, opts)
2224
x.get.stream.byDigest = (cache, hash, opts) => get.stream.byDigest(cache, hash, opts)
2325
x.get.copy = (cache, key, dest, opts) => get.copy(cache, key, dest, opts)

Diff for: locales/es.js

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ x.ls.flujo = cache => ls.stream(cache)
1818

1919
x.saca = (cache, clave, ops) => get(cache, clave, ops)
2020
x.saca.porHacheo = (cache, hacheo, ops) => get.byDigest(cache, hacheo, ops)
21+
x.saca.sinc = (cache, clave, ops) => get.sync(cache, clave, ops)
22+
x.saca.sinc.porHacheo = (cache, hacheo, ops) => get.sync.byDigest(cache, hacheo, ops)
2123
x.saca.flujo = (cache, clave, ops) => get.stream(cache, clave, ops)
2224
x.saca.flujo.porHacheo = (cache, hacheo, ops) => get.stream.byDigest(cache, hacheo, ops)
2325
x.sava.copia = (cache, clave, destino, opts) => get.copy(cache, clave, destino, opts)

Diff for: test/get.js

+18
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,24 @@ test('basic bulk get', t => {
8080
})
8181
})
8282

83+
test('basic sync get', t => {
84+
const fixture = new Tacks(CacheContent({
85+
[INTEGRITY]: CONTENT
86+
}))
87+
fixture.create(CACHE)
88+
index.insert.sync(CACHE, KEY, INTEGRITY, opts())
89+
const res = get.sync(CACHE, KEY)
90+
t.deepEqual(res, {
91+
metadata: METADATA,
92+
data: CONTENT,
93+
integrity: INTEGRITY,
94+
size: SIZE
95+
}, 'bulk key get returned proper data')
96+
const resByDig = get.sync.byDigest(CACHE, INTEGRITY)
97+
t.deepEqual(resByDig, CONTENT, 'byDigest returned proper data')
98+
t.done()
99+
})
100+
83101
test('basic stream get', t => {
84102
const fixture = new Tacks(CacheContent({
85103
[INTEGRITY]: CONTENT

0 commit comments

Comments
 (0)