From 2d4cdc4c7cda57379b9e88a042224468240b2cb4 Mon Sep 17 00:00:00 2001 From: Martin Acosta Date: Wed, 29 Apr 2020 18:12:31 -0300 Subject: [PATCH 1/9] First test --- index.js | 97 ++++++++++++++++++++++++++++++++++++++++------------ package.json | 1 + 2 files changed, 76 insertions(+), 22 deletions(-) diff --git a/index.js b/index.js index 2763424..decc1a0 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,5 @@ const ras = require('random-access-storage') +const mutexify = require('mutexify') const TYPE = {type: 'octet/stream'} const requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem @@ -29,6 +30,7 @@ function createFile (name, opts) { var fs = null var entry = null + var file = null var toDestroy = null var readers = [] var writers = [] @@ -36,12 +38,12 @@ function createFile (name, opts) { return ras({read, write, open, stat, close, destroy}) function read (req) { - const r = readers.pop() || new ReadRequest(readers, entry, mutex) + const r = readers.pop() || new ReadRequest(readers, entry, file, mutex) r.run(req) } function write (req) { - const w = writers.pop() || new WriteRequest(writers, entry, mutex) + const w = writers.pop() || new WriteRequest(writers, entry, file, mutex) w.run(req) } @@ -51,9 +53,10 @@ function createFile (name, opts) { } function stat (req) { - entry.file(file => { + file.get((err, file) => { + if (err) return req.callback(err) req.callback(null, file) - }, err => req.callback(err)) + }) } function destroy (req) { @@ -78,7 +81,11 @@ function createFile (name, opts) { mkdirp(parentFolder(name), function () { fs.root.getFile(name, {create: true}, function (e) { entry = toDestroy = e - req.callback(null) + file = new EntryFile(entry) + file.get((err) => { + if (err) return onerror(err) + req.callback(null) + }) }, onerror) }) }, onerror) @@ -107,9 +114,10 @@ function parentFolder (path) { return /^\w:$/.test(p) ? '' : p } -function WriteRequest (pool, entry, mutex) { +function WriteRequest (pool, entry, file, mutex) { this.pool = pool this.entry = entry + this.file = file this.mutex = mutex this.writer = null this.req = null @@ -122,7 +130,8 @@ WriteRequest.prototype.makeWriter = function () { this.entry.createWriter(function (writer) { self.writer = writer - writer.onwriteend = function () { + writer.onwriteend = function (e) { + self.file.updateSize(e.currentTarget.length) self.onwrite(null) } @@ -164,21 +173,21 @@ WriteRequest.prototype.lock = function () { } WriteRequest.prototype.run = function (req) { - this.entry.file(file => { - this.req = req - if (!this.writer || this.writer.length !== file.size) return this.makeWriter() + var file = this.file - const end = req.offset + req.size - if (end > file.size && !this.lock()) return + this.req = req + if (!this.writer || this.writer.length !== file.size) return this.makeWriter() - if (req.offset > this.writer.length) { - if (req.offset > file.size) return this.truncate() - return this.makeWriter() - } + const end = req.offset + req.size + if (end > file.size && !this.lock()) return + + if (req.offset > this.writer.length) { + if (req.offset > file.size) return this.truncate() + return this.makeWriter() + } - this.writer.seek(req.offset) - this.writer.write(new Blob([req.data], TYPE)) - }, err => req.callback(err)) + this.writer.seek(req.offset) + this.writer.write(new Blob([req.data], TYPE)) } function Mutex () { @@ -202,9 +211,10 @@ Mutex.prototype.lock = function (req) { return true } -function ReadRequest (pool, entry, mutex) { +function ReadRequest (pool, entry, file, mutex) { this.pool = pool this.entry = entry + this.file = file this.mutex = mutex this.reader = new FileReader() this.req = null @@ -251,10 +261,53 @@ ReadRequest.prototype.onread = function (err, buf) { } ReadRequest.prototype.run = function (req) { - this.entry.file(file => { + this.file.get((err, file) => { + if (err) return req.callback(err) + const end = req.offset + req.size this.req = req if (end > file.size) return this.onread(new Error('Could not satisfy length'), null) this.reader.readAsArrayBuffer(file.slice(req.offset, end)) - }, err => req.callback(err)) + }) +} + +class EntryFile { + constructor (entry) { + this._entry = entry + this._lock = mutexify() + this._file = null + this._size = 0 + } + + get locked () { + return this._lock.locked + } + + get size () { + return this._size + } + + updateSize (size) { + this._size = size + this._file = null + } + + get (cb) { + if (this._file) { + cb(null, this._file) + return + } + + this._lock(release => { + if (this._file) { + return release(cb, null, this._file) + } + + this._entry.file(file => { + this._file = file + this._size = file.size + release(cb, null, file) + }, err => release(cb, err)) + }) + } } diff --git a/package.json b/package.json index 5f62f58..0b8dfb5 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "random-access-storage instance backed by the Chrome file system api.", "main": "index.js", "dependencies": { + "mutexify": "^1.3.0", "random-access-storage": "^1.3.0" }, "devDependencies": { From fe99ac1477306f6bb5201e50d3eb7ff3692abf3c Mon Sep 17 00:00:00 2001 From: Martin Acosta Date: Thu, 30 Apr 2020 11:42:41 -0300 Subject: [PATCH 2/9] Added test --- .travis.yml | 4 ++++ bench.js | 6 ++++- browser-runner.js | 57 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 11 +++++++-- test.js | 10 +++++++++ 5 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 .travis.yml create mode 100644 browser-runner.js create mode 100644 test.js diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..2846363 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node: + - lts/* +services: xvfb diff --git a/bench.js b/bench.js index 88f29b6..7ae5e1e 100644 --- a/bench.js +++ b/bench.js @@ -37,7 +37,11 @@ function benchRead () { console.time('512mb read') st.read(0, 65536, function onread (err, buf) { if (err) throw err - if (offset >= 512 * 1024 * 1024) return console.timeEnd('512mb read') + if (offset >= 512 * 1024 * 1024) { + console.timeEnd('512mb read') + console.log('### EXIT') + return + } st.read(offset += buf.length, 65536, onread) }) } diff --git a/browser-runner.js b/browser-runner.js new file mode 100644 index 0000000..bf7ad82 --- /dev/null +++ b/browser-runner.js @@ -0,0 +1,57 @@ +const puppeteer = require('puppeteer') +const budo = require('budo') +const tapFinished = require('tap-finished') +const { PassThrough, pipeline } = require('stream') + +const args = process.argv.slice(2) + +budo.cli(args, { live: false, watchGlob: '', stream: false }).on('connect', runTests) + +async function runTests (ev) { + const results = new PassThrough() + let browser + let page + + try { + browser = await puppeteer.launch() + page = await browser.newPage() + } catch (err) { + console.error(err) + shutdown(1) + } + + page.on('error', async err => { + console.error(err) + shutdown(1) + }) + + page.on('pageerror', async err => { + console.error(err) + shutdown(1) + }) + + page.on('console', msg => { + msg = msg.text() + if (msg.includes('### EXIT')) { + shutdown() + } else { + results.push(`${msg}\n`) + } + }) + + pipeline(results, tapFinished(result => { + shutdown(result.ok ? 0 : 1) + }), () => {}) + + pipeline(results, process.stdout, () => {}) + + await page.goto(`http://localhost:${ev.port}`) + + async function shutdown (code = 0) { + if (browser) { + await browser.close().catch(() => {}) + } + + process.exit(code) + } +} diff --git a/package.json b/package.json index 0b8dfb5..b23afb8 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,17 @@ "random-access-storage": "^1.3.0" }, "devDependencies": { - "standard": "^11.0.1" + "budo": "^11.6.3", + "puppeteer": "^3.0.2", + "random-access-test": "github:random-access-storage/random-access-test", + "standard": "^11.0.1", + "tap-finished": "0.0.1", + "tape": "^5.0.0" }, "scripts": { - "test": "standard" + "test": "browserify ./test.js | tape-puppet --devtools", + "posttest": "npm run lint", + "lint": "standard" }, "repository": { "type": "git", diff --git a/test.js b/test.js new file mode 100644 index 0000000..04dabb7 --- /dev/null +++ b/test.js @@ -0,0 +1,10 @@ +const test = require('random-access-test') +const racf = require('./') + +const createStorage = (root) => (file, opts) => racf(`${root}/${file}`, opts) + +const storage = createStorage('tests-' + Math.random()) + +test(function (name, options, callback) { + callback(storage(name, options)) +}, {}) From 8c566ea812c5b4aa76fb13b19a65f3009a0144f8 Mon Sep 17 00:00:00 2001 From: Martin Acosta Date: Thu, 30 Apr 2020 11:44:14 -0300 Subject: [PATCH 3/9] Updated readme --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 05b3ce5..25ebaff 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # random-access-chrome-file +[![Build Status](https://travis-ci.com/random-access-storage/random-access-chrome-file.svg?branch=master)](https://travis-ci.com/random-access-storage/random-access-chrome-file) +[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) + A [random-access-storage](https://github.com/random-access-storage/random-access-storage) instance backed by the Chrome file system api ``` From bae971cfaf2c85f926c724ef42362cfe7a1f2354 Mon Sep 17 00:00:00 2001 From: Martin Acosta Date: Thu, 30 Apr 2020 11:47:03 -0300 Subject: [PATCH 4/9] Updated package.json --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index b23afb8..82aed98 100644 --- a/package.json +++ b/package.json @@ -16,9 +16,10 @@ "tape": "^5.0.0" }, "scripts": { - "test": "browserify ./test.js | tape-puppet --devtools", + "test": "node browser-runner.js test.js", "posttest": "npm run lint", - "lint": "standard" + "lint": "standard", + "bench": "node browser-runner.js bench.js" }, "repository": { "type": "git", From 87629aad92871313eaf22dbe9445dd9563220a94 Mon Sep 17 00:00:00 2001 From: Martin Acosta Date: Mon, 4 May 2020 16:39:15 -0300 Subject: [PATCH 5/9] fixed race condition getting an old file version to read --- index.js | 31 +++++++++++++++++++++++++------ package.json | 2 +- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/index.js b/index.js index decc1a0..90e011c 100644 --- a/index.js +++ b/index.js @@ -131,8 +131,7 @@ WriteRequest.prototype.makeWriter = function () { self.writer = writer writer.onwriteend = function (e) { - self.file.updateSize(e.currentTarget.length) - self.onwrite(null) + self.onwrite(null, e) } writer.onerror = function (err) { @@ -143,7 +142,7 @@ WriteRequest.prototype.makeWriter = function () { }) } -WriteRequest.prototype.onwrite = function (err) { +WriteRequest.prototype.onwrite = function (err, e) { const req = this.req this.req = null @@ -152,6 +151,10 @@ WriteRequest.prototype.onwrite = function (err) { this.mutex.release() } + if (!err) { + this.file.updateSize(e.currentTarget.length, this.truncating) + } + if (this.truncating) { this.truncating = false if (!err) return this.run(req) @@ -244,7 +247,16 @@ ReadRequest.prototype.onread = function (err, buf) { if (err && this.retry) { this.retry = false - if (this.lock(this)) this.run(req) + if (this.lock(this)) { + this.file.clearFile() + this.run(req) + } + return + } + + if (err && err.name === 'NotReadableError') { + this.file.clearFile() + this.run(req) return } @@ -287,8 +299,15 @@ class EntryFile { return this._size } - updateSize (size) { - this._size = size + updateSize (size, truncating = false) { + if (truncating || size > this._size) { + this._size = size + } + + this.clearFile() + } + + clearFile () { this._file = null } diff --git a/package.json b/package.json index 82aed98..62012ce 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "devDependencies": { "budo": "^11.6.3", "puppeteer": "^3.0.2", - "random-access-test": "github:random-access-storage/random-access-test", + "random-access-test": "^1.0.0", "standard": "^11.0.1", "tap-finished": "0.0.1", "tape": "^5.0.0" From 211b40f835f0ecf6cf647c920c7d5cc515a52b24 Mon Sep 17 00:00:00 2001 From: Martin Acosta Date: Tue, 5 May 2020 09:46:58 -0300 Subject: [PATCH 6/9] minor changes --- bench.js | 2 +- browser-runner.js | 2 +- index.js | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/bench.js b/bench.js index 7ae5e1e..5925f09 100644 --- a/bench.js +++ b/bench.js @@ -39,7 +39,7 @@ function benchRead () { if (err) throw err if (offset >= 512 * 1024 * 1024) { console.timeEnd('512mb read') - console.log('### EXIT') + console.log('BROWSER_RUNNER_EXIT') return } st.read(offset += buf.length, 65536, onread) diff --git a/browser-runner.js b/browser-runner.js index bf7ad82..fcf5d97 100644 --- a/browser-runner.js +++ b/browser-runner.js @@ -32,7 +32,7 @@ async function runTests (ev) { page.on('console', msg => { msg = msg.text() - if (msg.includes('### EXIT')) { + if (msg.includes('BROWSER_RUNNER_EXIT')) { shutdown() } else { results.push(`${msg}\n`) diff --git a/index.js b/index.js index 90e011c..57518b8 100644 --- a/index.js +++ b/index.js @@ -246,6 +246,12 @@ ReadRequest.prototype.onread = function (err, buf) { const req = this.req if (err && this.retry) { + if (err.name === 'NotReadableError') { + this.file.clearFile() + this.run(req) + return + } + this.retry = false if (this.lock(this)) { this.file.clearFile() @@ -254,12 +260,6 @@ ReadRequest.prototype.onread = function (err, buf) { return } - if (err && err.name === 'NotReadableError') { - this.file.clearFile() - this.run(req) - return - } - this.req = null this.pool.push(this) this.retry = true From fa10329091074ed24dcfdac5bd744bfbf54ffd30 Mon Sep 17 00:00:00 2001 From: Martin Acosta Date: Tue, 26 May 2020 10:16:24 -0300 Subject: [PATCH 7/9] Added dxos/browser-runner for browser testing --- .travis.yml | 1 - bench.js | 3 +-- browser-runner.config.js | 17 ++++++++++++ browser-runner.js | 57 ---------------------------------------- package.json | 7 +++-- 5 files changed, 21 insertions(+), 64 deletions(-) create mode 100644 browser-runner.config.js delete mode 100644 browser-runner.js diff --git a/.travis.yml b/.travis.yml index 2846363..4a4833c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,3 @@ language: node_js node: - lts/* -services: xvfb diff --git a/bench.js b/bench.js index 5925f09..7f4e401 100644 --- a/bench.js +++ b/bench.js @@ -39,8 +39,7 @@ function benchRead () { if (err) throw err if (offset >= 512 * 1024 * 1024) { console.timeEnd('512mb read') - console.log('BROWSER_RUNNER_EXIT') - return + return process.exit(0) // we do this to close browser-runner } st.read(offset += buf.length, 65536, onread) }) diff --git a/browser-runner.config.js b/browser-runner.config.js new file mode 100644 index 0000000..c15a2e8 --- /dev/null +++ b/browser-runner.config.js @@ -0,0 +1,17 @@ +const finished = require('tap-finished') + +let stream = null + +module.exports = { + beforeAll ({ shutdown }) { + stream = finished(function (results) { + if (results.ok) { + return shutdown(0) + } + shutdown(1) + }) + }, + onMessage (msg) { + stream.write(msg + '\n') + } +} diff --git a/browser-runner.js b/browser-runner.js deleted file mode 100644 index fcf5d97..0000000 --- a/browser-runner.js +++ /dev/null @@ -1,57 +0,0 @@ -const puppeteer = require('puppeteer') -const budo = require('budo') -const tapFinished = require('tap-finished') -const { PassThrough, pipeline } = require('stream') - -const args = process.argv.slice(2) - -budo.cli(args, { live: false, watchGlob: '', stream: false }).on('connect', runTests) - -async function runTests (ev) { - const results = new PassThrough() - let browser - let page - - try { - browser = await puppeteer.launch() - page = await browser.newPage() - } catch (err) { - console.error(err) - shutdown(1) - } - - page.on('error', async err => { - console.error(err) - shutdown(1) - }) - - page.on('pageerror', async err => { - console.error(err) - shutdown(1) - }) - - page.on('console', msg => { - msg = msg.text() - if (msg.includes('BROWSER_RUNNER_EXIT')) { - shutdown() - } else { - results.push(`${msg}\n`) - } - }) - - pipeline(results, tapFinished(result => { - shutdown(result.ok ? 0 : 1) - }), () => {}) - - pipeline(results, process.stdout, () => {}) - - await page.goto(`http://localhost:${ev.port}`) - - async function shutdown (code = 0) { - if (browser) { - await browser.close().catch(() => {}) - } - - process.exit(code) - } -} diff --git a/package.json b/package.json index 62012ce..f4ed100 100644 --- a/package.json +++ b/package.json @@ -8,18 +8,17 @@ "random-access-storage": "^1.3.0" }, "devDependencies": { - "budo": "^11.6.3", - "puppeteer": "^3.0.2", + "@dxos/browser-runner": "1.0.0-beta.6", "random-access-test": "^1.0.0", "standard": "^11.0.1", "tap-finished": "0.0.1", "tape": "^5.0.0" }, "scripts": { - "test": "node browser-runner.js test.js", + "test": "browser-runner test.js", "posttest": "npm run lint", "lint": "standard", - "bench": "node browser-runner.js bench.js" + "bench": "browser-runner bench.js" }, "repository": { "type": "git", From fb300c26ec10e6daff44ea7660842c72dccd467e Mon Sep 17 00:00:00 2001 From: Martin Acosta Date: Tue, 16 Jun 2020 13:07:02 -0300 Subject: [PATCH 8/9] Fixed crash on random concurrent requests --- index.js | 62 ++++++++++++++++++++++++++++------------------------ package.json | 6 ++--- test.js | 51 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 86 insertions(+), 33 deletions(-) diff --git a/index.js b/index.js index 57518b8..5b2edee 100644 --- a/index.js +++ b/index.js @@ -152,7 +152,7 @@ WriteRequest.prototype.onwrite = function (err, e) { } if (!err) { - this.file.updateSize(e.currentTarget.length, this.truncating) + this.file.updateSize(e.currentTarget.length) } if (this.truncating) { @@ -166,6 +166,7 @@ WriteRequest.prototype.onwrite = function (err, e) { WriteRequest.prototype.truncate = function () { this.truncating = true + this.file.truncate() this.writer.truncate(this.req.offset) } @@ -176,21 +177,23 @@ WriteRequest.prototype.lock = function () { } WriteRequest.prototype.run = function (req) { - var file = this.file + this.file.getWritableFile((err, file) => { + if (err) return req.callback(err) - this.req = req - if (!this.writer || this.writer.length !== file.size) return this.makeWriter() + this.req = req + if (!this.writer || this.writer.length !== file.size) return this.makeWriter() - const end = req.offset + req.size - if (end > file.size && !this.lock()) return + const end = req.offset + req.size + if (end > file.size && !this.lock()) return - if (req.offset > this.writer.length) { - if (req.offset > file.size) return this.truncate() - return this.makeWriter() - } + if (req.offset > this.writer.length) { + if (req.offset > file.size) return this.truncate() + return this.makeWriter() + } - this.writer.seek(req.offset) - this.writer.write(new Blob([req.data], TYPE)) + this.writer.seek(req.offset) + this.writer.write(new Blob([req.data], TYPE)) + }) } function Mutex () { @@ -246,12 +249,6 @@ ReadRequest.prototype.onread = function (err, buf) { const req = this.req if (err && this.retry) { - if (err.name === 'NotReadableError') { - this.file.clearFile() - this.run(req) - return - } - this.retry = false if (this.lock(this)) { this.file.clearFile() @@ -289,44 +286,53 @@ class EntryFile { this._lock = mutexify() this._file = null this._size = 0 - } - - get locked () { - return this._lock.locked + this._truncated = false } get size () { return this._size } - updateSize (size, truncating = false) { - if (truncating || size > this._size) { + updateSize (size) { + if (!this._truncated) { this._size = size } this.clearFile() } + truncate () { + this._truncated = true + } + clearFile () { this._file = null } get (cb) { - if (this._file) { - cb(null, this._file) - return + if (this._file && !this._truncated) { + return cb(null, this._file) } this._lock(release => { - if (this._file) { + if (this._file && !this._truncated) { return release(cb, null, this._file) } this._entry.file(file => { + this._truncated = false this._file = file this._size = file.size release(cb, null, file) }, err => release(cb, err)) }) } + + getWritableFile (cb) { + if (!this._truncated) { + return cb(null, this) + } + + this.get(cb) + } } diff --git a/package.json b/package.json index f4ed100..e95089d 100644 --- a/package.json +++ b/package.json @@ -8,17 +8,17 @@ "random-access-storage": "^1.3.0" }, "devDependencies": { - "@dxos/browser-runner": "1.0.0-beta.6", + "@dxos/browser-runner": "^1.0.0-beta.9", "random-access-test": "^1.0.0", "standard": "^11.0.1", "tap-finished": "0.0.1", - "tape": "^5.0.0" + "tape": "^5.0.1" }, "scripts": { "test": "browser-runner test.js", "posttest": "npm run lint", "lint": "standard", - "bench": "browser-runner bench.js" + "bench": "browser-runner bench.js --timeout 0" }, "repository": { "type": "git", diff --git a/test.js b/test.js index 04dabb7..f1d67b8 100644 --- a/test.js +++ b/test.js @@ -1,10 +1,57 @@ -const test = require('random-access-test') +const test = require('tape') +const randomAccessTest = require('random-access-test') const racf = require('./') const createStorage = (root) => (file, opts) => racf(`${root}/${file}`, opts) const storage = createStorage('tests-' + Math.random()) -test(function (name, options, callback) { +randomAccessTest(function (name, options, callback) { callback(storage(name, options)) }, {}) + +test('write/read concurrent requests', async t => { + const st = storage('random') + + const rand = (min, max) => Math.floor(Math.random() * max) + min + + const read = (...args) => new Promise((resolve, reject) => { + st.read(...args, (err) => { + if (err) return reject(err) + resolve() + }) + }) + + const write = (...args) => new Promise((resolve, reject) => { + st.write(...args, (err) => { + if (err) return reject(err) + resolve() + }) + }) + + try { + await new Promise(resolve => st.open(() => resolve())) + + const buf = Buffer.alloc(1) + + await Promise.all([...Array(1000).keys()].map(from => { + return write(from, buf) + })) + + await Promise.all([...Array(1000).keys()].map(() => { + const row = rand(0, 2) + const from = rand(0, 1000) + const to = 1 + + if (row === 0) { + return read(from, to) + } + return write(from, buf) + })) + + t.pass('should work ok with random concurrent request') + t.end() + } catch (err) { + t.end(err) + } +}) From 7c73c6f8df4403035cb98c1f93f90c179ed0a9b4 Mon Sep 17 00:00:00 2001 From: Martin Acosta Date: Thu, 2 Jul 2020 10:58:58 -0300 Subject: [PATCH 9/9] Fixed race condition --- index.js | 7 +++++-- test.js | 38 ++++++++++++++++++++++++-------------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/index.js b/index.js index 5b2edee..fadb037 100644 --- a/index.js +++ b/index.js @@ -249,7 +249,10 @@ ReadRequest.prototype.onread = function (err, buf) { const req = this.req if (err && this.retry) { - this.retry = false + if (err.code !== 0) { + this.retry = false + } + if (this.lock(this)) { this.file.clearFile() this.run(req) @@ -294,7 +297,7 @@ class EntryFile { } updateSize (size) { - if (!this._truncated) { + if (!this._truncated && size > this._size) { this._size = size } diff --git a/test.js b/test.js index f1d67b8..1793044 100644 --- a/test.js +++ b/test.js @@ -1,3 +1,4 @@ +const { promisify } = require('util') const test = require('tape') const randomAccessTest = require('random-access-test') const racf = require('./') @@ -14,20 +15,8 @@ test('write/read concurrent requests', async t => { const st = storage('random') const rand = (min, max) => Math.floor(Math.random() * max) + min - - const read = (...args) => new Promise((resolve, reject) => { - st.read(...args, (err) => { - if (err) return reject(err) - resolve() - }) - }) - - const write = (...args) => new Promise((resolve, reject) => { - st.write(...args, (err) => { - if (err) return reject(err) - resolve() - }) - }) + const read = promisify(st.read.bind(st)) + const write = promisify(st.write.bind(st)) try { await new Promise(resolve => st.open(() => resolve())) @@ -55,3 +44,24 @@ test('write/read concurrent requests', async t => { t.end(err) } }) + +test('write concurrent requests over the same offset different size', async t => { + const st = storage('random') + + const write = promisify(st.write.bind(st)) + + try { + await new Promise(resolve => st.open(() => resolve())) + + await Promise.all([ + write(0, Buffer.alloc(10)), + write(0, Buffer.alloc(1)), + write(0, Buffer.alloc(5)) + ]) + + t.pass('should write multiple requests over the same offset different size') + t.end() + } catch (err) { + t.end(err) + } +})