aligned-block-file
Advanced tools
Comparing version 1.2.0 to 1.2.1
83
file.js
@@ -10,12 +10,53 @@ var fs = require('fs') | ||
var offset = Obv() | ||
var writing = false | ||
var waitingForWrite = [] | ||
function readyToWrite () { | ||
if(!writing) throw new Error('should be writing') | ||
writing = false | ||
while(waitingForWrite.length) | ||
waitingForWrite.shift()() | ||
// Positional read and write operations may be hazardous. We want to avoid: | ||
// | ||
// - Concurrent writes to the same part of the file. | ||
// - Reading and writing from the same part of the file. | ||
// | ||
// It's possible (likely?) that Node.js handles this deeper in the stack, | ||
// especially since it seems to use `pread()` and `pwrite()`. Removing this | ||
// queue system doesn't break any tests, but I'm not confident enough to | ||
// remove it until we confirm that Node.js handles concurrent positional | ||
// reads and writes without either of the concurrency problems above. | ||
// | ||
// This async queue system is made of four parts: | ||
// | ||
// - `busy`: A boolean semaphore for positional reads and writes to `fd`. | ||
// - `queue`: An array of functions that want to access `fd`. | ||
// - `todo(fn)`: Used to run or queue `fn`, which must call `release()`. | ||
// - `release()`: Called by functions passed to `todo()` after using `fd`. | ||
// If `busy === true` then another function is accessing `fd`. | ||
// If `busy === false` then you're all clear to access. | ||
let busy = false | ||
// Each item should be a function that accepts no arguments. | ||
// `release()` should be called as soon as `fd` access is complete. | ||
// Items are processed FIFO even though `Array.shift()` is slow | ||
const queue = [] | ||
// A function passed to `todo` will have exclusive access to positional | ||
// operations on `fd`, although append operations may still occur. | ||
// | ||
// Any function passed to `todo()` absolutely *must* call `release()` when | ||
// finished using `fd`, often as the first line in the `fs.foo()` callback. | ||
const todo = (fn) => { | ||
if (busy === true) { | ||
queue.push(fn) | ||
} else { | ||
busy = true | ||
fn() | ||
} | ||
} | ||
const release = () => { | ||
if (queue.length === 0) { | ||
busy = false | ||
} else { | ||
queue.shift()() | ||
} | ||
} | ||
mkdirp(path.dirname(file), function () { | ||
@@ -51,2 +92,3 @@ //r+ opens the file for reading and writing, but errors if file does not exist. | ||
fs.read(fd, buf, 0, block_size, i*block_size, function (err, bytes_read) { | ||
release() | ||
if(err) cb(err) | ||
@@ -68,4 +110,3 @@ else if( | ||
} | ||
if(!writing) onReady() | ||
else waitingForWrite.push(onReady) | ||
todo(onReady) | ||
}) | ||
@@ -77,11 +118,11 @@ }, | ||
if(appending++) throw new Error('already appending to this file') | ||
offset.once(function (_offset) { | ||
fs.write(fd, buf, 0, buf.length, _offset, function (err, written) { | ||
appending = 0 | ||
if(err) return cb(err) | ||
if(written !== buf.length) return cb(new Error('wrote less bytes than expected:'+written+', but wanted:'+buf.length)) | ||
offset.set(_offset+written) | ||
cb(null, _offset+written) | ||
}) | ||
offset.once(function (_offset) { | ||
fs.write(fd, buf, 0, buf.length, _offset, function (err, written) { | ||
appending = 0 | ||
if(err) return cb(err) | ||
if(written !== buf.length) return cb(new Error('wrote less bytes than expected:'+written+', but wanted:'+buf.length)) | ||
offset.set(_offset+written) | ||
cb(null, _offset+written) | ||
}) | ||
}) | ||
}, | ||
@@ -107,6 +148,5 @@ /** | ||
function onReady (_writing) { | ||
writing = true | ||
function onReady () { | ||
fs.write(fd, buf, 0, buf.length, pos, (err, written) => { | ||
readyToWrite() | ||
release() | ||
if (err == null && written !== buf.length) { | ||
@@ -120,4 +160,3 @@ cb(new Error('wrote less bytes than expected:'+written+', but wanted:'+buf.length)) | ||
if(!writing) onReady() | ||
else waitingForWrite.push(onReady) | ||
todo(onReady) | ||
}) | ||
@@ -124,0 +163,0 @@ }, |
{ | ||
"name": "aligned-block-file", | ||
"description": "", | ||
"version": "1.2.0", | ||
"version": "1.2.1", | ||
"homepage": "https://github.com/flumedb/aligned-block-file", | ||
@@ -6,0 +6,0 @@ "repository": { |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
30322
833
1