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

Commit 4c38a41

Browse files
authored
Merge pull request #28 from ipfs/support-concurrent-writes-on-windows
fix: handle concurrent writes on windows
2 parents bb44723 + d5c8e4f commit 4c38a41

File tree

2 files changed

+36
-1
lines changed

2 files changed

+36
-1
lines changed

src/index.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const fs = require('fs')
44
const glob = require('glob')
55
const mkdirp = require('mkdirp')
66
const promisify = require('util').promisify
7-
const writeFile = promisify(require('fast-write-atomic'))
7+
const writeAtomic = promisify(require('fast-write-atomic'))
88
const path = require('path')
99

1010
const filter = require('interface-datastore').utils.filter
@@ -22,6 +22,26 @@ const fsUnlink = promisify(fs.unlink || noop)
2222
const Key = IDatastore.Key
2323
const Errors = IDatastore.Errors
2424

25+
async function writeFile (path, contents) {
26+
try {
27+
await writeAtomic(path, contents)
28+
} catch (err) {
29+
if (err.code === 'EPERM' && err.syscall === 'rename') {
30+
// fast-write-atomic writes a file to a temp location before renaming it.
31+
// On Windows, if the final file already exists this error is thrown.
32+
// No such error is thrown on Linux/Mac
33+
// Make sure we can read & write to this file
34+
await fsAccess(path, fs.constants.F_OK | fs.constants.W_OK)
35+
36+
// The file was created by another context - this means there were
37+
// attempts to write the same block by two different function calls
38+
return
39+
}
40+
41+
throw err
42+
}
43+
}
44+
2545
/**
2646
* A datastore backed by the file system.
2747
*

test/index.spec.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,4 +172,19 @@ describe('FsDatastore', () => {
172172
}
173173
})
174174
})
175+
176+
it('can survive concurrent writes', async () => {
177+
const dir = utils.tmpdir()
178+
const fstore = new FsStore(dir)
179+
const key = new Key('CIQGFTQ7FSI2COUXWWLOQ45VUM2GUZCGAXLWCTOKKPGTUWPXHBNIVOY')
180+
const value = Buffer.from('Hello world')
181+
182+
await Promise.all(
183+
new Array(100).fill(0).map(() => fstore.put(key, value))
184+
)
185+
186+
const res = await fstore.get(key)
187+
188+
expect(res).to.deep.equal(value)
189+
})
175190
})

0 commit comments

Comments
 (0)