Skip to content

Commit

Permalink
Implement writeBuffers using writev and pwritev syscalls.
Browse files Browse the repository at this point in the history
Change-Type: patch
  • Loading branch information
zvin committed Apr 6, 2017
1 parent 81cd223 commit 5220d58
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 4 deletions.
19 changes: 16 additions & 3 deletions lib/binding.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function getCallback(req) {
}

function addNullTerminationIfNeeded(s) {
// If the s is a Buffer, we need to add a NULL termination byte.
// If s is a Buffer, we need to add a NULL termination byte.
if (Buffer.isBuffer(s)) {
const nullTerminated = Buffer.allocUnsafe(s.length + 1);
s.copy(nullTerminated);
Expand Down Expand Up @@ -193,8 +193,21 @@ exports.writeBuffer = function(fd, buffer, offset, length, position, req) {
}
}

exports.writeBuffers = function() {
throw new Error('Unimplemented');
exports.writeBuffers = function(fd, buffers, position, req) {
const callback = getCallback(req);
const iovecs = bindings.buffersToIoVecs(buffers);
if (typeof position === 'number' && position !== -1) {
return syscall.pwritev(
fd,
iovecs,
buffers.length,
position & 0xffffffff, // 32 lower bits
Math.floor(position / Math.pow(2, 32)), // high bits
callback
);
} else {
return syscall.writev(fd, iovecs, buffers.length, callback);
}
}

exports.writeString = function() {
Expand Down
4 changes: 3 additions & 1 deletion lib/syscall.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ module.exports = {
openat: syscall.bind(null, constants.SYS_openat),
pread64: syscall.bind(null, constants.SYS_pread64),
pwrite64: syscall.bind(null, constants.SYS_pwrite64),
pwritev: syscall.bind(null, constants.SYS_pwritev),
read: syscall.bind(null, constants.SYS_read),
readlinkat: syscall.bind(null, constants.SYS_readlinkat),
removexattr: syscall.bind(null, constants.SYS_removexattr),
Expand All @@ -56,7 +57,8 @@ module.exports = {
sync: syscall.bind(null, constants.SYS_sync),
truncate: syscall.bind(null, constants.SYS_truncate),
unlinkat: syscall.bind(null, constants.SYS_unlinkat),
write: syscall.bind(null, constants.SYS_write)
write: syscall.bind(null, constants.SYS_write),
writev: syscall.bind(null, constants.SYS_writev)
};

// Unimplemented syscalls
Expand Down
1 change: 1 addition & 0 deletions src/bindings.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ NAN_MODULE_INIT(InitAll) {
NAN_EXPORT(target, sizeOfStructLklStat);
NAN_EXPORT(target, parseLklStat);
NAN_EXPORT(target, millisecondsToTimespec);
NAN_EXPORT(target, buffersToIoVecs);
}

NODE_MODULE(bindings, InitAll)
16 changes: 16 additions & 0 deletions src/node_lkl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,19 @@ NAN_METHOD(millisecondsToTimespec) {
).ToLocalChecked();
info.GetReturnValue().Set(result);
}

NAN_METHOD(buffersToIoVecs) {
auto arr = info[0].As<v8::Array>();
auto len = arr->Length();
auto *iovecs = new struct iovec[len];
for (unsigned int i = 0; i < len; i++) {
auto buf = arr->Get(i);
iovecs[i].iov_base = reinterpret_cast<char*>(node::Buffer::Data(buf));
iovecs[i].iov_len = node::Buffer::Length(buf);
}
auto result = Nan::NewBuffer(
reinterpret_cast<char*>(iovecs),
sizeof *iovecs
).ToLocalChecked();
info.GetReturnValue().Set(result);
}
1 change: 1 addition & 0 deletions src/node_lkl.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ NAN_METHOD(parseDirent64);
NAN_METHOD(sizeOfStructLklStat);
NAN_METHOD(parseLklStat);
NAN_METHOD(millisecondsToTimespec);
NAN_METHOD(buffersToIoVecs);
26 changes: 26 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -432,5 +432,31 @@ describe('node-lkl', function() {
.then(done);
});
});

describe('writev', function() {
it('should write all buffers to file', function(done) {
const fpath = path.join(this.mountpoint, 'filename');
const stream = lkl.fs.WriteStream(fpath);
const chunks = [
{chunk: Buffer.from('1')},
{chunk: Buffer.from('2')},
{chunk: Buffer.from('3')},
]
// testing writev syscall
stream._writev(chunks, function(err) {
// testing pwritev syscall
stream.pos = 1;
stream._writev(chunks, function(err) {
stream.close(function(err){
lkl.fs.readFileAsync(fpath, 'utf8')
.then(function(content) {
assert.strictEqual(content, '1123', 'should read what it has written');
done();
})
})
});
});
});
});
});
});

0 comments on commit 5220d58

Please sign in to comment.