Skip to content
This repository was archived by the owner on Mar 23, 2023. It is now read-only.

Commit 4cee21c

Browse files
authored
Merge pull request #27 from ipfs/support-concurrent-writes-on-windows
fix: handle concurrent writes on windows
2 parents 45ec48b + 5aea24f commit 4cee21c

File tree

2 files changed

+52
-1
lines changed

2 files changed

+52
-1
lines changed

src/index.js

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const setImmediate = require('async/setImmediate')
1010
const waterfall = require('async/series')
1111
const each = require('async/each')
1212
const mkdirp = require('mkdirp')
13-
const writeFile = require('fast-write-atomic')
13+
const writeAtomic = require('fast-write-atomic')
1414
const path = require('path')
1515

1616
const asyncFilter = require('interface-datastore').utils.asyncFilter
@@ -19,6 +19,32 @@ const IDatastore = require('interface-datastore')
1919
const Key = IDatastore.Key
2020
const Errors = IDatastore.Errors
2121

22+
function writeFile (path, contents, callback) {
23+
writeAtomic(path, contents, (err) => {
24+
if (err) {
25+
if (err.code === 'EPERM' && err.syscall === 'rename') {
26+
// fast-write-atomic writes a file to a temp location before renaming it.
27+
// On Windows, if the final file already exists this error is thrown.
28+
// No such error is thrown on Linux/Mac
29+
// Make sure we can read & write to this file
30+
return fs.access(path, fs.constants.F_OK | fs.constants.W_OK, (err) => {
31+
if (err) {
32+
return callback(err)
33+
}
34+
35+
// The file was created by another context - this means there were
36+
// attempts to write the same block by two different function calls
37+
return callback()
38+
})
39+
}
40+
41+
return callback(err)
42+
}
43+
44+
callback()
45+
})
46+
}
47+
2248
/* :: export type FsInputOptions = {
2349
createIfMissing?: bool,
2450
errorIfExists?: bool,

test/index.spec.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,4 +153,29 @@ describe('FsDatastore', () => {
153153
}
154154
})
155155
})
156+
157+
it('can survive concurrent writes', (done) => {
158+
const dir = utils.tmpdir()
159+
const fstore = new FsStore(dir)
160+
const key = new Key('CIQGFTQ7FSI2COUXWWLOQ45VUM2GUZCGAXLWCTOKKPGTUWPXHBNIVOY')
161+
const value = Buffer.from('Hello world')
162+
163+
parallel(
164+
new Array(100).fill(0).map(() => {
165+
return (cb) => {
166+
fstore.put(key, value, cb)
167+
}
168+
}),
169+
(err) => {
170+
expect(err).to.not.exist()
171+
172+
fstore.get(key, (err, res) => {
173+
expect(err).to.not.exist()
174+
expect(res).to.deep.equal(value)
175+
176+
done()
177+
})
178+
}
179+
)
180+
})
156181
})

0 commit comments

Comments
 (0)