Compare commits

...
Author SHA1 Message Date
Vitaliy Filippov ce359c5a69 Release 1.8.0
Bugfix release, would be 1.7.2, but etcd layout changes mandate it to be 1.8.0. :-)

- Change etcd layout: /config/pgs is now /pg/config, /pg/stats/* is now /pgstats/*.
  This is required to fix a rare PG history tracking issue caused by non-atomic
  delivery of etcd events sometimes resulting in `incomplete` objects in EC pools
  after mass OSD restarts. Upgrading can be performed freely, downgrade requires
  additional action: [1.8.0 to 1.7.1](https://git.yourcmc.ru/vitalif/vitastor/src/branch/master/docs/usage/admin.en.md#1-8-0-to-1-7-1)
- Fix a rare client hang on PG primary OSD switch
- Fix vitastor-nfs started using mount command sometimes not stopping automatically after unmount
- Fix vitastor-nfs mounts started using mount command sometimes hanging after daemonizing
- Fix merge/flatten into a pool with different object size (image migration between pools case)
- Do not print extra "PG disappeared after reload" verbose log messages for non-existing PGs
- Fix clustered Antietcd support and persistence filter
- Do not try to purge the same OSD multiple times if its multiple devices are passed to purge
- Various node.js binding fixes
2024-08-11 14:28:31 +03:00
Vitaliy Filippov 521e867b10 Run check_exit also on deferred stop. Now vitastor-nfs should finally always stop on umount 2024-08-11 00:05:20 +03:00
Vitaliy Filippov 333c54ebbf Cleanup clients correctly during stop(). Was also affecting #67, but could also reproduce during normal operation 2024-08-11 00:00:13 +03:00
Vitaliy Filippov 58d3da95c8 Fix github issue #67 by closing active NFS sockets before daemonize() 2024-08-10 20:13:37 +03:00
Vitaliy Filippov 4e90e752eb Fix merge/flatten into a pool with different object size 2024-08-10 19:23:26 +03:00
Vitaliy Filippov 09342d7189 node.js binding fixes 2024-08-05 00:10:37 +03:00
21 changed files with 228 additions and 109 deletions
+1 -1
View File
@@ -2,6 +2,6 @@ cmake_minimum_required(VERSION 2.8.12)
project(vitastor) project(vitastor)
set(VITASTOR_VERSION "1.7.1") set(VITASTOR_VERSION "1.8.0")
add_subdirectory(src) add_subdirectory(src)
+1 -1
View File
@@ -1,4 +1,4 @@
VITASTOR_VERSION ?= v1.7.1 VITASTOR_VERSION ?= v1.8.0
all: build push all: build push
+1 -1
View File
@@ -49,7 +49,7 @@ spec:
capabilities: capabilities:
add: ["SYS_ADMIN"] add: ["SYS_ADMIN"]
allowPrivilegeEscalation: true allowPrivilegeEscalation: true
image: vitalif/vitastor-csi:v1.7.1 image: vitalif/vitastor-csi:v1.8.0
args: args:
- "--node=$(NODE_ID)" - "--node=$(NODE_ID)"
- "--endpoint=$(CSI_ENDPOINT)" - "--endpoint=$(CSI_ENDPOINT)"
+1 -1
View File
@@ -121,7 +121,7 @@ spec:
privileged: true privileged: true
capabilities: capabilities:
add: ["SYS_ADMIN"] add: ["SYS_ADMIN"]
image: vitalif/vitastor-csi:v1.7.1 image: vitalif/vitastor-csi:v1.8.0
args: args:
- "--node=$(NODE_ID)" - "--node=$(NODE_ID)"
- "--endpoint=$(CSI_ENDPOINT)" - "--endpoint=$(CSI_ENDPOINT)"
+1 -1
View File
@@ -5,7 +5,7 @@ package vitastor
const ( const (
vitastorCSIDriverName = "csi.vitastor.io" vitastorCSIDriverName = "csi.vitastor.io"
vitastorCSIDriverVersion = "1.7.1" vitastorCSIDriverVersion = "1.8.0"
) )
// Config struct fills the parameters of request or user input // Config struct fills the parameters of request or user input
+1 -1
View File
@@ -1,4 +1,4 @@
vitastor (1.7.1-1) unstable; urgency=medium vitastor (1.8.0-1) unstable; urgency=medium
* Bugfixes * Bugfixes
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "vitastor-mon", "name": "vitastor-mon",
"version": "1.7.1", "version": "1.8.0",
"description": "Vitastor SDS monitor service", "description": "Vitastor SDS monitor service",
"main": "mon-main.js", "main": "mon-main.js",
"scripts": { "scripts": {
+2 -2
View File
@@ -24,7 +24,7 @@ NAN_MODULE_INIT(InitAddon)
tpl = Nan::New<v8::FunctionTemplate>(NodeVitastorImage::Create); tpl = Nan::New<v8::FunctionTemplate>(NodeVitastorImage::Create);
tpl->SetClassName(Nan::New("Image").ToLocalChecked()); tpl->SetClassName(Nan::New("Image").ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(2); tpl->InstanceTemplate()->SetInternalFieldCount(1);
Nan::SetPrototypeMethod(tpl, "read", NodeVitastorImage::Read); Nan::SetPrototypeMethod(tpl, "read", NodeVitastorImage::Read);
Nan::SetPrototypeMethod(tpl, "write", NodeVitastorImage::Write); Nan::SetPrototypeMethod(tpl, "write", NodeVitastorImage::Write);
@@ -67,7 +67,7 @@ NAN_MODULE_INIT(InitAddon)
tpl = Nan::New<v8::FunctionTemplate>(NodeVitastorKVListing::Create); tpl = Nan::New<v8::FunctionTemplate>(NodeVitastorKVListing::Create);
tpl->SetClassName(Nan::New("KVListing").ToLocalChecked()); tpl->SetClassName(Nan::New("KVListing").ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(2); tpl->InstanceTemplate()->SetInternalFieldCount(1);
Nan::SetPrototypeMethod(tpl, "next", NodeVitastorKVListing::Next); Nan::SetPrototypeMethod(tpl, "next", NodeVitastorKVListing::Next);
Nan::SetPrototypeMethod(tpl, "close", NodeVitastorKVListing::Close); Nan::SetPrototypeMethod(tpl, "close", NodeVitastorKVListing::Close);
+2 -1
View File
@@ -13,7 +13,8 @@
'<!(pkg-config --cflags vitastor)' '<!(pkg-config --cflags vitastor)'
], ],
'libraries': [ 'libraries': [
'<!(pkg-config --libs vitastor)' '<!(pkg-config --libs vitastor)',
'-lvitastor_kv'
] ]
} }
] ]
+175 -71
View File
@@ -18,13 +18,15 @@
class NodeVitastorRequest: public Nan::AsyncResource class NodeVitastorRequest: public Nan::AsyncResource
{ {
public: public:
NodeVitastorRequest(v8::Local<v8::Function> cb): Nan::AsyncResource("NodeVitastorRequest") NodeVitastorRequest(NodeVitastor *cli, v8::Local<v8::Function> cb): Nan::AsyncResource("NodeVitastorRequest")
{ {
this->cli = cli;
callback.Reset(cb); callback.Reset(cb);
} }
iovec iov; iovec iov;
std::vector<iovec> iov_list; std::vector<iovec> iov_list;
NodeVitastor *cli = NULL;
NodeVitastorImage *img = NULL; NodeVitastorImage *img = NULL;
int op = 0; int op = 0;
uint64_t offset = 0, len = 0, version = 0; uint64_t offset = 0, len = 0, version = 0;
@@ -32,6 +34,13 @@ public:
Nan::Persistent<v8::Function> callback; Nan::Persistent<v8::Function> callback;
}; };
static uint64_t get_ui64(const v8::Local<v8::Value> & val)
{
if (val->IsBigInt())
return val->ToBigInt(Nan::GetCurrentContext()).ToLocalChecked()->Uint64Value();
return Nan::To<int64_t>(val).FromJust();
}
////////////////////////////////////////////////// //////////////////////////////////////////////////
// NodeVitastor // NodeVitastor
////////////////////////////////////////////////// //////////////////////////////////////////////////
@@ -44,6 +53,7 @@ NodeVitastor::NodeVitastor(): Nan::ObjectWrap()
NodeVitastor::~NodeVitastor() NodeVitastor::~NodeVitastor()
{ {
TRACE("NodeVitastor: destructor");
uv_poll_stop(&poll_watcher); uv_poll_stop(&poll_watcher);
vitastor_c_destroy(c); vitastor_c_destroy(c);
c = NULL; c = NULL;
@@ -75,9 +85,10 @@ NAN_METHOD(NodeVitastor::Create)
if (res >= 0) if (res >= 0)
{ {
cli->eventfd = res; cli->eventfd = res;
res = uv_poll_init_socket(uv_default_loop(), &cli->poll_watcher, cli->eventfd); res = uv_poll_init(uv_default_loop(), &cli->poll_watcher, cli->eventfd);
if (res >= 0) if (res >= 0)
res = uv_poll_start(&cli->poll_watcher, UV_READABLE, on_io_readable); res = uv_poll_start(&cli->poll_watcher, UV_READABLE, on_io_readable);
on_io_readable(&cli->poll_watcher, 0, UV_READABLE);
} }
if (res < 0) if (res < 0)
{ {
@@ -98,15 +109,14 @@ void NodeVitastor::on_io_readable(uv_poll_t* handle, int status, int revents)
if (revents & UV_READABLE) if (revents & UV_READABLE)
{ {
NodeVitastor* self = (NodeVitastor*)handle->data; NodeVitastor* self = (NodeVitastor*)handle->data;
std::unique_lock<std::mutex> lock(self->mu);
vitastor_c_uring_handle_events(self->c); vitastor_c_uring_handle_events(self->c);
} }
} }
static NodeVitastorRequest* getReadRequest(const Nan::FunctionCallbackInfo<v8::Value> & info, int argpos) NodeVitastorRequest* NodeVitastor::get_read_request(const Nan::FunctionCallbackInfo<v8::Value> & info, int argpos)
{ {
uint64_t offset = Nan::To<int64_t>(info[argpos+0]).FromJust(); uint64_t offset = get_ui64(info[argpos+0]);
uint64_t len = Nan::To<int64_t>(info[argpos+1]).FromJust(); uint64_t len = get_ui64(info[argpos+1]);
uint8_t *buf = (uint8_t*)malloc(len); uint8_t *buf = (uint8_t*)malloc(len);
if (!buf) if (!buf)
{ {
@@ -114,7 +124,7 @@ static NodeVitastorRequest* getReadRequest(const Nan::FunctionCallbackInfo<v8::V
return NULL; return NULL;
} }
v8::Local<v8::Function> callback = info[argpos+2].As<v8::Function>(); v8::Local<v8::Function> callback = info[argpos+2].As<v8::Function>();
auto req = new NodeVitastorRequest(callback); auto req = new NodeVitastorRequest(this, callback);
req->offset = offset; req->offset = offset;
req->len = len; req->len = len;
@@ -127,35 +137,39 @@ static NodeVitastorRequest* getReadRequest(const Nan::FunctionCallbackInfo<v8::V
NAN_METHOD(NodeVitastor::Read) NAN_METHOD(NodeVitastor::Read)
{ {
TRACE("NodeVitastor::Read"); TRACE("NodeVitastor::Read");
if (info.Length() < 5)
Nan::ThrowError("Not enough arguments to read(pool, inode, offset, len, callback(err, buffer, version))");
NodeVitastor* self = Nan::ObjectWrap::Unwrap<NodeVitastor>(info.This()); NodeVitastor* self = Nan::ObjectWrap::Unwrap<NodeVitastor>(info.This());
uint64_t pool = Nan::To<int64_t>(info[0]).FromJust(); uint64_t pool = get_ui64(info[0]);
uint64_t inode = Nan::To<int64_t>(info[1]).FromJust(); uint64_t inode = get_ui64(info[1]);
auto req = getReadRequest(info, 2); auto req = self->get_read_request(info, 2);
std::unique_lock<std::mutex> lock(self->mu); self->Ref();
vitastor_c_read(self->c, ((pool << (64-POOL_ID_BITS)) | inode), req->offset, req->len, &req->iov, 1, on_read_finish, req); vitastor_c_read(self->c, ((pool << (64-POOL_ID_BITS)) | inode), req->offset, req->len, &req->iov, 1, on_read_finish, req);
} }
static NodeVitastorRequest* getWriteRequest(const Nan::FunctionCallbackInfo<v8::Value> & info, int argpos) NodeVitastorRequest* NodeVitastor::get_write_request(const Nan::FunctionCallbackInfo<v8::Value> & info, int argpos)
{ {
uint64_t offset = Nan::To<int64_t>(info[argpos+0]).FromJust(); uint64_t offset = get_ui64(info[argpos+0]);
const auto & bufarg = info[argpos+1]; const auto & bufarg = info[argpos+1];
uint64_t version = 0; uint64_t version = 0;
if (!info[argpos+2].IsEmpty() && info[argpos+2]->IsObject()) if (!info[argpos+2].IsEmpty() &&
!info[argpos+2]->IsFunction() &&
info[argpos+2]->IsObject())
{ {
auto key = Nan::New<v8::String>("version").ToLocalChecked(); auto key = Nan::New<v8::String>("version").ToLocalChecked();
auto params = info[argpos+2].As<v8::Object>(); auto params = info[argpos+2].As<v8::Object>();
auto versionObj = Nan::Get(params, key).ToLocalChecked(); auto versionObj = Nan::Get(params, key).ToLocalChecked();
if (!versionObj.IsEmpty()) if (!versionObj.IsEmpty())
version = Nan::To<int64_t>(versionObj).FromJust(); version = get_ui64(versionObj);
argpos++; argpos++;
} }
v8::Local<v8::Function> callback = info[argpos+2].As<v8::Function>(); v8::Local<v8::Function> callback = info[argpos+2].As<v8::Function>();
auto req = new NodeVitastorRequest(callback); auto req = new NodeVitastorRequest(this, callback);
req->offset = offset; req->offset = offset;
req->version = version; req->version = version;
@@ -177,7 +191,7 @@ static NodeVitastorRequest* getWriteRequest(const Nan::FunctionCallbackInfo<v8::
{ {
char *buf = node::Buffer::Data(bufarg); char *buf = node::Buffer::Data(bufarg);
uint64_t len = node::Buffer::Length(bufarg); uint64_t len = node::Buffer::Length(bufarg);
req->iov = { .iov_base = buf, .iov_len = req->len }; req->iov = { .iov_base = buf, .iov_len = len };
req->len = len; req->len = len;
} }
@@ -188,15 +202,17 @@ static NodeVitastorRequest* getWriteRequest(const Nan::FunctionCallbackInfo<v8::
NAN_METHOD(NodeVitastor::Write) NAN_METHOD(NodeVitastor::Write)
{ {
TRACE("NodeVitastor::Write"); TRACE("NodeVitastor::Write");
if (info.Length() < 5)
Nan::ThrowError("Not enough arguments to write(pool, inode, offset, buf: Buffer | Buffer[], { version }?, callback(err))");
NodeVitastor* self = Nan::ObjectWrap::Unwrap<NodeVitastor>(info.This()); NodeVitastor* self = Nan::ObjectWrap::Unwrap<NodeVitastor>(info.This());
uint64_t pool = Nan::To<int64_t>(info[0]).FromJust(); uint64_t pool = get_ui64(info[0]);
uint64_t inode = Nan::To<int64_t>(info[1]).FromJust(); uint64_t inode = get_ui64(info[1]);
auto req = getWriteRequest(info, 2); auto req = self->get_write_request(info, 2);
std::unique_lock<std::mutex> lock(self->mu); self->Ref();
vitastor_c_write(self->c, ((pool << (64-POOL_ID_BITS)) | inode), req->offset, req->len, req->version, vitastor_c_write(self->c, ((pool << (64-POOL_ID_BITS)) | inode), req->offset, req->len, req->version,
req->iov_list.size() ? req->iov_list.data() : &req->iov, req->iov_list.size() ? req->iov_list.data() : &req->iov,
req->iov_list.size() ? req->iov_list.size() : 1, req->iov_list.size() ? req->iov_list.size() : 1,
@@ -207,13 +223,15 @@ NAN_METHOD(NodeVitastor::Write)
NAN_METHOD(NodeVitastor::Sync) NAN_METHOD(NodeVitastor::Sync)
{ {
TRACE("NodeVitastor::Sync"); TRACE("NodeVitastor::Sync");
if (info.Length() < 1)
Nan::ThrowError("Not enough arguments to sync(callback(err))");
NodeVitastor* self = Nan::ObjectWrap::Unwrap<NodeVitastor>(info.This()); NodeVitastor* self = Nan::ObjectWrap::Unwrap<NodeVitastor>(info.This());
v8::Local<v8::Function> callback = info[0].As<v8::Function>(); v8::Local<v8::Function> callback = info[0].As<v8::Function>();
auto req = new NodeVitastorRequest(callback); auto req = new NodeVitastorRequest(self, callback);
std::unique_lock<std::mutex> lock(self->mu); self->Ref();
vitastor_c_sync(self->c, on_write_finish, req); vitastor_c_sync(self->c, on_write_finish, req);
} }
@@ -221,17 +239,20 @@ NAN_METHOD(NodeVitastor::Sync)
NAN_METHOD(NodeVitastor::ReadBitmap) NAN_METHOD(NodeVitastor::ReadBitmap)
{ {
TRACE("NodeVitastor::ReadBitmap"); TRACE("NodeVitastor::ReadBitmap");
if (info.Length() < 6)
Nan::ThrowError("Not enough arguments to read_bitmap(pool, inode, offset, len, with_parents, callback(err, bitmap_buffer))");
NodeVitastor* self = Nan::ObjectWrap::Unwrap<NodeVitastor>(info.This()); NodeVitastor* self = Nan::ObjectWrap::Unwrap<NodeVitastor>(info.This());
uint64_t pool = Nan::To<int64_t>(info[0]).FromJust(); uint64_t pool = get_ui64(info[0]);
uint64_t inode = Nan::To<int64_t>(info[1]).FromJust(); uint64_t inode = get_ui64(info[1]);
uint64_t offset = Nan::To<int64_t>(info[2]).FromJust(); uint64_t offset = get_ui64(info[2]);
uint64_t len = Nan::To<int64_t>(info[3]).FromJust(); uint64_t len = get_ui64(info[3]);
bool with_parents = Nan::To<bool>(info[4]).FromJust(); bool with_parents = Nan::To<bool>(info[4]).FromJust();
v8::Local<v8::Function> callback = info[5].As<v8::Function>(); v8::Local<v8::Function> callback = info[5].As<v8::Function>();
auto req = new NodeVitastorRequest(callback); auto req = new NodeVitastorRequest(self, callback);
self->Ref();
vitastor_c_read_bitmap(self->c, ((pool << (64-POOL_ID_BITS)) | inode), offset, len, with_parents, on_read_bitmap_finish, req); vitastor_c_read_bitmap(self->c, ((pool << (64-POOL_ID_BITS)) | inode), offset, len, with_parents, on_read_bitmap_finish, req);
} }
@@ -248,6 +269,7 @@ static void on_error(NodeVitastorRequest *req, Nan::Callback & nanCallback, long
void NodeVitastor::on_read_finish(void *opaque, long retval, uint64_t version) void NodeVitastor::on_read_finish(void *opaque, long retval, uint64_t version)
{ {
TRACE("NodeVitastor::on_read_finish");
Nan::HandleScope scope; Nan::HandleScope scope;
NodeVitastorRequest *req = (NodeVitastorRequest *)opaque; NodeVitastorRequest *req = (NodeVitastorRequest *)opaque;
Nan::Callback nanCallback(Nan::New(req->callback)); Nan::Callback nanCallback(Nan::New(req->callback));
@@ -256,7 +278,7 @@ void NodeVitastor::on_read_finish(void *opaque, long retval, uint64_t version)
free(req->iov.iov_base); free(req->iov.iov_base);
nanCallback.Call(0, NULL, req); nanCallback.Call(0, NULL, req);
} }
else if (retval < 0) else if (retval < 0 || (uint64_t)retval != req->len)
{ {
free(req->iov.iov_base); free(req->iov.iov_base);
on_error(req, nanCallback, retval); on_error(req, nanCallback, retval);
@@ -269,20 +291,33 @@ void NodeVitastor::on_read_finish(void *opaque, long retval, uint64_t version)
args[2] = v8::BigInt::NewFromUnsigned(v8::Isolate::GetCurrent(), version); args[2] = v8::BigInt::NewFromUnsigned(v8::Isolate::GetCurrent(), version);
nanCallback.Call(3, args, req); nanCallback.Call(3, args, req);
} }
req->cli->Unref();
delete req; delete req;
} }
void NodeVitastor::on_write_finish(void *opaque, long retval) void NodeVitastor::on_write_finish(void *opaque, long retval)
{ {
TRACE("NodeVitastor::on_write_finish");
Nan::HandleScope scope; Nan::HandleScope scope;
NodeVitastorRequest *req = (NodeVitastorRequest *)opaque; NodeVitastorRequest *req = (NodeVitastorRequest *)opaque;
Nan::Callback nanCallback(Nan::New(req->callback)); Nan::Callback nanCallback(Nan::New(req->callback));
on_error(req, nanCallback, retval); if (retval < 0 || (uint64_t)retval != req->len)
{
on_error(req, nanCallback, retval);
}
else
{
v8::Local<v8::Value> args[1];
args[0] = Nan::Null();
nanCallback.Call(1, args, req);
}
req->cli->Unref();
delete req; delete req;
} }
void NodeVitastor::on_read_bitmap_finish(void *opaque, long retval, uint8_t *bitmap) void NodeVitastor::on_read_bitmap_finish(void *opaque, long retval, uint8_t *bitmap)
{ {
TRACE("NodeVitastor::on_read_bitmap_finish");
Nan::HandleScope scope; Nan::HandleScope scope;
NodeVitastorRequest *req = (NodeVitastorRequest *)opaque; NodeVitastorRequest *req = (NodeVitastorRequest *)opaque;
Nan::Callback nanCallback(Nan::New(req->callback)); Nan::Callback nanCallback(Nan::New(req->callback));
@@ -297,6 +332,7 @@ void NodeVitastor::on_read_bitmap_finish(void *opaque, long retval, uint8_t *bit
args[1] = Nan::NewBuffer((char*)bitmap, (retval+7)/8).ToLocalChecked(); args[1] = Nan::NewBuffer((char*)bitmap, (retval+7)/8).ToLocalChecked();
nanCallback.Call(2, args, req); nanCallback.Call(2, args, req);
} }
req->cli->Unref();
delete req; delete req;
} }
@@ -312,21 +348,23 @@ void NodeVitastor::on_read_bitmap_finish(void *opaque, long retval, uint8_t *bit
NAN_METHOD(NodeVitastorImage::Create) NAN_METHOD(NodeVitastorImage::Create)
{ {
TRACE("NodeVitastorImage::Create"); TRACE("NodeVitastorImage::Create");
if (info.Length() < 2)
Nan::ThrowError("Not enough arguments to Image(client, name)");
v8::Local<v8::Object> parent = info[0].As<v8::Object>(); v8::Local<v8::Object> parent = info[0].As<v8::Object>();
std::string name = std::string(*Nan::Utf8String(info[1].As<v8::String>())); std::string name = std::string(*Nan::Utf8String(info[1].As<v8::String>()));
NodeVitastor *cli = Nan::ObjectWrap::Unwrap<NodeVitastor>(parent); NodeVitastor *cli = Nan::ObjectWrap::Unwrap<NodeVitastor>(parent);
NodeVitastorImage *img = new NodeVitastorImage(); NodeVitastorImage *img = new NodeVitastorImage();
img->Wrap(info.This());
img->cli = cli; img->cli = cli;
img->name = name; img->name = name;
img->Ref(); img->Ref();
cli->Ref(); cli->Ref();
std::unique_lock<std::mutex> lock(cli->mu);
vitastor_c_watch_inode(cli->c, (char*)img->name.c_str(), on_watch_start, img); vitastor_c_watch_inode(cli->c, (char*)img->name.c_str(), on_watch_start, img);
img->Wrap(info.This());
info.GetReturnValue().Set(info.This()); info.GetReturnValue().Set(info.This());
} }
@@ -344,10 +382,12 @@ NodeVitastorImage::~NodeVitastorImage()
NAN_METHOD(NodeVitastorImage::Read) NAN_METHOD(NodeVitastorImage::Read)
{ {
TRACE("NodeVitastorImage::Read"); TRACE("NodeVitastorImage::Read");
if (info.Length() < 3)
Nan::ThrowError("Not enough arguments to read(offset, len, callback(err, buffer, version))");
NodeVitastorImage* img = Nan::ObjectWrap::Unwrap<NodeVitastorImage>(info.This()); NodeVitastorImage* img = Nan::ObjectWrap::Unwrap<NodeVitastorImage>(info.This());
auto req = getReadRequest(info, 0); auto req = img->cli->get_read_request(info, 0);
req->img = img; req->img = img;
req->op = NODE_VITASTOR_READ; req->op = NODE_VITASTOR_READ;
@@ -358,24 +398,29 @@ NAN_METHOD(NodeVitastorImage::Read)
NAN_METHOD(NodeVitastorImage::Write) NAN_METHOD(NodeVitastorImage::Write)
{ {
TRACE("NodeVitastorImage::Write"); TRACE("NodeVitastorImage::Write");
if (info.Length() < 3)
Nan::ThrowError("Not enough arguments to write(offset, buffer, { version }?, callback(err))");
NodeVitastorImage* img = Nan::ObjectWrap::Unwrap<NodeVitastorImage>(info.This()); NodeVitastorImage* img = Nan::ObjectWrap::Unwrap<NodeVitastorImage>(info.This());
auto req = getWriteRequest(info, 0); auto req = img->cli->get_write_request(info, 0);
req->img = img; req->img = img;
req->op = NODE_VITASTOR_WRITE; req->op = NODE_VITASTOR_WRITE;
img->exec_or_wait(req); img->exec_or_wait(req);
} }
// sync(callback(err))
NAN_METHOD(NodeVitastorImage::Sync) NAN_METHOD(NodeVitastorImage::Sync)
{ {
TRACE("NodeVitastorImage::Sync"); TRACE("NodeVitastorImage::Sync");
if (info.Length() < 1)
Nan::ThrowError("Not enough arguments to sync(callback(err))");
NodeVitastorImage* img = Nan::ObjectWrap::Unwrap<NodeVitastorImage>(info.This()); NodeVitastorImage* img = Nan::ObjectWrap::Unwrap<NodeVitastorImage>(info.This());
v8::Local<v8::Function> callback = info[0].As<v8::Function>(); v8::Local<v8::Function> callback = info[0].As<v8::Function>();
auto req = new NodeVitastorRequest(callback); auto req = new NodeVitastorRequest(img->cli, callback);
req->img = img; req->img = img;
req->op = NODE_VITASTOR_SYNC; req->op = NODE_VITASTOR_SYNC;
@@ -386,15 +431,17 @@ NAN_METHOD(NodeVitastorImage::Sync)
NAN_METHOD(NodeVitastorImage::ReadBitmap) NAN_METHOD(NodeVitastorImage::ReadBitmap)
{ {
TRACE("NodeVitastorImage::ReadBitmap"); TRACE("NodeVitastorImage::ReadBitmap");
if (info.Length() < 4)
Nan::ThrowError("Not enough arguments to read_bitmap(offset, len, with_parents, callback(err, bitmap_buffer))");
NodeVitastorImage* img = Nan::ObjectWrap::Unwrap<NodeVitastorImage>(info.This()); NodeVitastorImage* img = Nan::ObjectWrap::Unwrap<NodeVitastorImage>(info.This());
uint64_t offset = Nan::To<int64_t>(info[0]).FromJust(); uint64_t offset = get_ui64(info[0]);
uint64_t len = Nan::To<int64_t>(info[1]).FromJust(); uint64_t len = get_ui64(info[1]);
bool with_parents = Nan::To<bool>(info[2]).FromJust(); bool with_parents = Nan::To<bool>(info[2]).FromJust();
v8::Local<v8::Function> callback = info[3].As<v8::Function>(); v8::Local<v8::Function> callback = info[3].As<v8::Function>();
auto req = new NodeVitastorRequest(callback); auto req = new NodeVitastorRequest(img->cli, callback);
req->img = img; req->img = img;
req->op = NODE_VITASTOR_READ_BITMAP; req->op = NODE_VITASTOR_READ_BITMAP;
req->offset = offset; req->offset = offset;
@@ -404,14 +451,17 @@ NAN_METHOD(NodeVitastorImage::ReadBitmap)
img->exec_or_wait(req); img->exec_or_wait(req);
} }
// get_info(callback({ num, name, size, parent_id?, readonly?, meta?, mod_revision, block_size, bitmap_granularity, immediate_commit }))
NAN_METHOD(NodeVitastorImage::GetInfo) NAN_METHOD(NodeVitastorImage::GetInfo)
{ {
TRACE("NodeVitastorImage::Sync"); TRACE("NodeVitastorImage::GetInfo");
if (info.Length() < 1)
Nan::ThrowError("Not enough arguments to get_info(callback({ num, name, size, parent_id?, readonly?, meta?, mod_revision, block_size, bitmap_granularity, immediate_commit }))");
NodeVitastorImage* img = Nan::ObjectWrap::Unwrap<NodeVitastorImage>(info.This()); NodeVitastorImage* img = Nan::ObjectWrap::Unwrap<NodeVitastorImage>(info.This());
v8::Local<v8::Function> callback = info[0].As<v8::Function>(); v8::Local<v8::Function> callback = info[0].As<v8::Function>();
auto req = new NodeVitastorRequest(callback); auto req = new NodeVitastorRequest(img->cli, callback);
req->img = img; req->img = img;
req->op = NODE_VITASTOR_GET_INFO; req->op = NODE_VITASTOR_GET_INFO;
@@ -433,15 +483,16 @@ void NodeVitastorImage::exec_or_wait(NodeVitastorRequest *req)
void NodeVitastorImage::exec_request(NodeVitastorRequest *req) void NodeVitastorImage::exec_request(NodeVitastorRequest *req)
{ {
std::unique_lock<std::mutex> lock(cli->mu);
if (req->op == NODE_VITASTOR_READ) if (req->op == NODE_VITASTOR_READ)
{ {
uint64_t ino = vitastor_c_inode_get_num(watch); uint64_t ino = vitastor_c_inode_get_num(watch);
cli->Ref();
vitastor_c_read(cli->c, ino, req->offset, req->len, &req->iov, 1, NodeVitastor::on_read_finish, req); vitastor_c_read(cli->c, ino, req->offset, req->len, &req->iov, 1, NodeVitastor::on_read_finish, req);
} }
else if (req->op == NODE_VITASTOR_WRITE) else if (req->op == NODE_VITASTOR_WRITE)
{ {
uint64_t ino = vitastor_c_inode_get_num(watch); uint64_t ino = vitastor_c_inode_get_num(watch);
cli->Ref();
vitastor_c_write(cli->c, ino, req->offset, req->len, req->version, vitastor_c_write(cli->c, ino, req->offset, req->len, req->version,
req->iov_list.size() ? req->iov_list.data() : &req->iov, req->iov_list.size() ? req->iov_list.data() : &req->iov,
req->iov_list.size() ? req->iov_list.size() : 1, req->iov_list.size() ? req->iov_list.size() : 1,
@@ -451,6 +502,7 @@ void NodeVitastorImage::exec_request(NodeVitastorRequest *req)
{ {
uint64_t ino = vitastor_c_inode_get_num(watch); uint64_t ino = vitastor_c_inode_get_num(watch);
uint32_t imm = vitastor_c_inode_get_immediate_commit(cli->c, ino); uint32_t imm = vitastor_c_inode_get_immediate_commit(cli->c, ino);
cli->Ref();
if (imm != IMMEDIATE_ALL) if (imm != IMMEDIATE_ALL)
{ {
vitastor_c_sync(cli->c, NodeVitastor::on_write_finish, req); vitastor_c_sync(cli->c, NodeVitastor::on_write_finish, req);
@@ -463,6 +515,7 @@ void NodeVitastorImage::exec_request(NodeVitastorRequest *req)
else if (req->op == NODE_VITASTOR_READ_BITMAP) else if (req->op == NODE_VITASTOR_READ_BITMAP)
{ {
uint64_t ino = vitastor_c_inode_get_num(watch); uint64_t ino = vitastor_c_inode_get_num(watch);
cli->Ref();
vitastor_c_read_bitmap(cli->c, ino, req->offset, req->len, req->with_parents, NodeVitastor::on_read_bitmap_finish, req); vitastor_c_read_bitmap(cli->c, ino, req->offset, req->len, req->with_parents, NodeVitastor::on_read_bitmap_finish, req);
} }
else if (req->op == NODE_VITASTOR_GET_INFO) else if (req->op == NODE_VITASTOR_GET_INFO)
@@ -532,10 +585,14 @@ void NodeVitastorImage::on_watch_start(void *opaque, long retval)
// NodeVitastorKV // NodeVitastorKV
////////////////////////////////////////////////// //////////////////////////////////////////////////
Nan::Persistent<v8::Function> NodeVitastorKV::listing_class;
// constructor(node_vitastor) // constructor(node_vitastor)
NAN_METHOD(NodeVitastorKV::Create) NAN_METHOD(NodeVitastorKV::Create)
{ {
TRACE("NodeVitastorKV::Create"); TRACE("NodeVitastorKV::Create");
if (info.Length() < 1)
Nan::ThrowError("Not enough arguments to new KV(client)");
v8::Local<v8::Object> parent = info[0].As<v8::Object>(); v8::Local<v8::Object> parent = info[0].As<v8::Object>();
NodeVitastor *cli = Nan::ObjectWrap::Unwrap<NodeVitastor>(parent); NodeVitastor *cli = Nan::ObjectWrap::Unwrap<NodeVitastor>(parent);
@@ -543,29 +600,32 @@ NAN_METHOD(NodeVitastorKV::Create)
NodeVitastorKV *kv = new NodeVitastorKV(); NodeVitastorKV *kv = new NodeVitastorKV();
kv->cli = cli; kv->cli = cli;
{ {
std::unique_lock<std::mutex> lock(cli->mu);
kv->dbw = new vitastorkv_dbw_t((cluster_client_t*)vitastor_c_get_internal_client(cli->c)); kv->dbw = new vitastorkv_dbw_t((cluster_client_t*)vitastor_c_get_internal_client(cli->c));
} }
kv->Wrap(info.This()); kv->Wrap(info.This());
cli->Ref();
info.GetReturnValue().Set(info.This()); info.GetReturnValue().Set(info.This());
} }
NodeVitastorKV::~NodeVitastorKV() NodeVitastorKV::~NodeVitastorKV()
{ {
delete dbw; delete dbw;
cli->Unref();
} }
// open(inode_id, { ...config }, callback(err)) // open(pool_id, inode_num, { ...config }, callback(err))
NAN_METHOD(NodeVitastorKV::Open) NAN_METHOD(NodeVitastorKV::Open)
{ {
TRACE("NodeVitastorKV::Open"); TRACE("NodeVitastorKV::Open");
if (info.Length() < 4)
Nan::ThrowError("Not enough arguments to open(pool_id, inode_num, { ...config }, callback(err))");
NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap<NodeVitastorKV>(info.This()); NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap<NodeVitastorKV>(info.This());
uint64_t inode_id = Nan::To<int64_t>(info[0]).FromJust(); uint64_t inode_id = INODE_WITH_POOL(get_ui64(info[0]), get_ui64(info[1]));
v8::Local<v8::Object> jsParams = info[1].As<v8::Object>(); v8::Local<v8::Object> jsParams = info[2].As<v8::Object>();
v8::Local<v8::Array> keys = Nan::GetOwnPropertyNames(jsParams).ToLocalChecked(); v8::Local<v8::Array> keys = Nan::GetOwnPropertyNames(jsParams).ToLocalChecked();
std::map<std::string, std::string> cfg; std::map<std::string, std::string> cfg;
for (uint32_t i = 0; i < keys->Length(); i++) for (uint32_t i = 0; i < keys->Length(); i++)
@@ -574,8 +634,8 @@ NAN_METHOD(NodeVitastorKV::Open)
cfg[std::string(*Nan::Utf8String(key))] = std::string(*Nan::Utf8String(Nan::Get(jsParams, key).ToLocalChecked())); cfg[std::string(*Nan::Utf8String(key))] = std::string(*Nan::Utf8String(Nan::Get(jsParams, key).ToLocalChecked()));
} }
v8::Local<v8::Function> callback = info[2].As<v8::Function>(); v8::Local<v8::Function> callback = info[3].As<v8::Function>();
auto req = new NodeVitastorRequest(callback); auto req = new NodeVitastorRequest(kv->cli, callback);
kv->Ref(); kv->Ref();
kv->dbw->open(inode_id, cfg, [kv, req](int res) kv->dbw->open(inode_id, cfg, [kv, req](int res)
@@ -594,11 +654,13 @@ NAN_METHOD(NodeVitastorKV::Open)
NAN_METHOD(NodeVitastorKV::Close) NAN_METHOD(NodeVitastorKV::Close)
{ {
TRACE("NodeVitastorKV::Close"); TRACE("NodeVitastorKV::Close");
if (info.Length() < 1)
Nan::ThrowError("Not enough arguments to close(callback(err))");
NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap<NodeVitastorKV>(info.This()); NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap<NodeVitastorKV>(info.This());
v8::Local<v8::Function> callback = info[0].As<v8::Function>(); v8::Local<v8::Function> callback = info[0].As<v8::Function>();
auto req = new NodeVitastorRequest(callback); auto req = new NodeVitastorRequest(kv->cli, callback);
kv->Ref(); kv->Ref();
kv->dbw->close([kv, req]() kv->dbw->close([kv, req]()
@@ -615,6 +677,8 @@ NAN_METHOD(NodeVitastorKV::Close)
NAN_METHOD(NodeVitastorKV::SetConfig) NAN_METHOD(NodeVitastorKV::SetConfig)
{ {
TRACE("NodeVitastorKV::SetConfig"); TRACE("NodeVitastorKV::SetConfig");
if (info.Length() < 1)
Nan::ThrowError("Not enough arguments to set_config({ ...config })");
NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap<NodeVitastorKV>(info.This()); NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap<NodeVitastorKV>(info.This());
@@ -651,7 +715,7 @@ void NodeVitastorKV::get_impl(const Nan::FunctionCallbackInfo<v8::Value> & info,
std::string key(*Nan::Utf8String(info[0].As<v8::String>())); std::string key(*Nan::Utf8String(info[0].As<v8::String>()));
v8::Local<v8::Function> callback = info[1].As<v8::Function>(); v8::Local<v8::Function> callback = info[1].As<v8::Function>();
auto req = new NodeVitastorRequest(callback); auto req = new NodeVitastorRequest(kv->cli, callback);
kv->Ref(); kv->Ref();
kv->dbw->get(key, [kv, req](int res, const std::string & value) kv->dbw->get(key, [kv, req](int res, const std::string & value)
@@ -671,6 +735,8 @@ void NodeVitastorKV::get_impl(const Nan::FunctionCallbackInfo<v8::Value> & info,
NAN_METHOD(NodeVitastorKV::Get) NAN_METHOD(NodeVitastorKV::Get)
{ {
TRACE("NodeVitastorKV::Get"); TRACE("NodeVitastorKV::Get");
if (info.Length() < 2)
Nan::ThrowError("Not enough arguments to get(key, callback(err, value))");
get_impl(info, false); get_impl(info, false);
} }
@@ -678,6 +744,8 @@ NAN_METHOD(NodeVitastorKV::Get)
NAN_METHOD(NodeVitastorKV::GetCached) NAN_METHOD(NodeVitastorKV::GetCached)
{ {
TRACE("NodeVitastorKV::GetCached"); TRACE("NodeVitastorKV::GetCached");
if (info.Length() < 2)
Nan::ThrowError("Not enough arguments to get_cached(key, callback(err, value))");
get_impl(info, true); get_impl(info, true);
} }
@@ -696,10 +764,12 @@ static std::function<bool(int, const std::string &)> make_cas_callback(NodeVitas
}; };
} }
// set(key, value, callback(err), cas_compare(old_value)) // set(key, value, callback(err), cas_compare(old_value)?)
NAN_METHOD(NodeVitastorKV::Set) NAN_METHOD(NodeVitastorKV::Set)
{ {
TRACE("NodeVitastorKV::Set"); TRACE("NodeVitastorKV::Set");
if (info.Length() < 3)
Nan::ThrowError("Not enough arguments to set(key, value, callback(err), cas_compare(old_value)?)");
NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap<NodeVitastorKV>(info.This()); NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap<NodeVitastorKV>(info.This());
@@ -708,13 +778,13 @@ NAN_METHOD(NodeVitastorKV::Set)
std::string value(*Nan::Utf8String(info[1].As<v8::String>())); std::string value(*Nan::Utf8String(info[1].As<v8::String>()));
v8::Local<v8::Function> callback = info[2].As<v8::Function>(); v8::Local<v8::Function> callback = info[2].As<v8::Function>();
NodeVitastorRequest *req = new NodeVitastorRequest(callback), *cas_req = NULL; NodeVitastorRequest *req = new NodeVitastorRequest(kv->cli, callback), *cas_req = NULL;
std::function<bool(int, const std::string &)> cas_cb; std::function<bool(int, const std::string &)> cas_cb;
if (info.Length() > 3 && info[3]->IsObject()) if (info.Length() > 3 && info[3]->IsObject())
{ {
v8::Local<v8::Function> cas_callback = info[3].As<v8::Function>(); v8::Local<v8::Function> cas_callback = info[3].As<v8::Function>();
cas_req = new NodeVitastorRequest(cas_callback); cas_req = new NodeVitastorRequest(kv->cli, cas_callback);
cas_cb = make_cas_callback(cas_req); cas_cb = make_cas_callback(cas_req);
} }
@@ -733,10 +803,12 @@ NAN_METHOD(NodeVitastorKV::Set)
}, cas_cb); }, cas_cb);
} }
// del(key, callback(err), cas_compare(old_value)) // del(key, callback(err), cas_compare(old_value)?)
NAN_METHOD(NodeVitastorKV::Del) NAN_METHOD(NodeVitastorKV::Del)
{ {
TRACE("NodeVitastorKV::Del"); TRACE("NodeVitastorKV::Del");
if (info.Length() < 2)
Nan::ThrowError("Not enough arguments to del(key, callback(err), cas_compare(old_value)?)");
NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap<NodeVitastorKV>(info.This()); NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap<NodeVitastorKV>(info.This());
@@ -744,13 +816,13 @@ NAN_METHOD(NodeVitastorKV::Del)
std::string key(*Nan::Utf8String(info[0].As<v8::String>())); std::string key(*Nan::Utf8String(info[0].As<v8::String>()));
v8::Local<v8::Function> callback = info[1].As<v8::Function>(); v8::Local<v8::Function> callback = info[1].As<v8::Function>();
NodeVitastorRequest *req = new NodeVitastorRequest(callback), *cas_req = NULL; NodeVitastorRequest *req = new NodeVitastorRequest(kv->cli, callback), *cas_req = NULL;
std::function<bool(int, const std::string &)> cas_cb; std::function<bool(int, const std::string &)> cas_cb;
if (info.Length() > 2 && info[2]->IsObject()) if (info.Length() > 2 && info[2]->IsObject())
{ {
v8::Local<v8::Function> cas_callback = info[2].As<v8::Function>(); v8::Local<v8::Function> cas_callback = info[2].As<v8::Function>();
cas_req = new NodeVitastorRequest(cas_callback); cas_req = new NodeVitastorRequest(kv->cli, cas_callback);
cas_cb = make_cas_callback(cas_req); cas_cb = make_cas_callback(cas_req);
} }
@@ -786,6 +858,14 @@ NAN_METHOD(NodeVitastorKV::List)
info.GetReturnValue().Set(Nan::NewInstance(cons, narg, args).ToLocalChecked()); info.GetReturnValue().Set(Nan::NewInstance(cons, narg, args).ToLocalChecked());
} }
/*NAN_METHOD(NodeVitastorKV::Destroy)
{
TRACE("NodeVitastorKV::Destroy");
NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap<NodeVitastorKV>(info.This());
if (!kv->dead)
kv->Unref();
}*/
////////////////////////////////////////////////// //////////////////////////////////////////////////
// NodeVitastorKVListing // NodeVitastorKVListing
////////////////////////////////////////////////// //////////////////////////////////////////////////
@@ -807,12 +887,10 @@ NAN_METHOD(NodeVitastorKVListing::Create)
NodeVitastorKVListing *list = new NodeVitastorKVListing(); NodeVitastorKVListing *list = new NodeVitastorKVListing();
list->kv = kv; list->kv = kv;
{ list->handle = list->kv->dbw->list_start(start_key);
std::unique_lock<std::mutex> lock(kv->cli->mu);
list->handle = list->kv->dbw->list_start(start_key);
}
list->Wrap(info.This()); list->Wrap(info.This());
kv->Ref();
info.GetReturnValue().Set(info.This()); info.GetReturnValue().Set(info.This());
} }
@@ -820,35 +898,54 @@ NodeVitastorKVListing::~NodeVitastorKVListing()
{ {
if (handle) if (handle)
{ {
std::unique_lock<std::mutex> lock(kv->cli->mu);
kv->dbw->list_close(handle); kv->dbw->list_close(handle);
handle = NULL; handle = NULL;
} }
if (iter)
{
delete iter;
iter = NULL;
}
kv->Unref();
} }
// next(callback(err, value)) // next(callback(err, value)?)
NAN_METHOD(NodeVitastorKVListing::Next) NAN_METHOD(NodeVitastorKVListing::Next)
{ {
TRACE("NodeVitastorKVListing::Next"); TRACE("NodeVitastorKVListing::Next");
NodeVitastorKVListing* list = Nan::ObjectWrap::Unwrap<NodeVitastorKVListing>(info.This()); NodeVitastorKVListing* list = Nan::ObjectWrap::Unwrap<NodeVitastorKVListing>(info.This());
v8::Local<v8::Function> callback = info[0].As<v8::Function>(); if (info.Length() > 0)
auto req = new NodeVitastorRequest(callback); {
v8::Local<v8::Function> callback = info[0].As<v8::Function>();
if (list->iter)
{
delete list->iter;
}
list->iter = new NodeVitastorRequest(list->kv->cli, callback);
}
if (!list->handle) if (!list->handle)
{ {
// Already closed // Already closed
Nan::Callback nanCallback(Nan::New(req->callback)); if (list->iter)
v8::Local<v8::Value> args[1]; {
args[0] = Nan::New<v8::Int32>(-EINVAL); auto req = list->iter;
nanCallback.Call(1, args, req); list->iter = NULL;
delete req; Nan::Callback nanCallback(Nan::New(req->callback));
v8::Local<v8::Value> args[1];
args[0] = Nan::New<v8::Int32>(-EINVAL);
nanCallback.Call(1, args, req);
delete req;
}
return; return;
} }
list->kv->Ref(); list->kv->Ref();
list->kv->dbw->list_next(list->handle, [list, req](int res, const std::string & key, const std::string & value) list->kv->dbw->list_next(list->handle, [list](int res, const std::string & key, const std::string & value)
{ {
auto req = list->iter;
list->iter = NULL;
Nan::HandleScope scope; Nan::HandleScope scope;
Nan::Callback nanCallback(Nan::New(req->callback)); Nan::Callback nanCallback(Nan::New(req->callback));
v8::Local<v8::Value> args[3]; v8::Local<v8::Value> args[3];
@@ -856,7 +953,10 @@ NAN_METHOD(NodeVitastorKVListing::Next)
args[1] = !res ? v8::Local<v8::Value>(Nan::New<v8::String>(key).ToLocalChecked()) : v8::Local<v8::Value>(Nan::Null()); args[1] = !res ? v8::Local<v8::Value>(Nan::New<v8::String>(key).ToLocalChecked()) : v8::Local<v8::Value>(Nan::Null());
args[2] = !res ? v8::Local<v8::Value>(Nan::New<v8::String>(value).ToLocalChecked()) : v8::Local<v8::Value>(Nan::Null()); args[2] = !res ? v8::Local<v8::Value>(Nan::New<v8::String>(value).ToLocalChecked()) : v8::Local<v8::Value>(Nan::Null());
nanCallback.Call(3, args, req); nanCallback.Call(3, args, req);
delete req; if (list->iter)
delete req;
else
list->iter = req;
list->kv->Unref(); list->kv->Unref();
}); });
} }
@@ -870,8 +970,12 @@ NAN_METHOD(NodeVitastorKVListing::Close)
if (list->handle) if (list->handle)
{ {
std::unique_lock<std::mutex> lock(list->kv->cli->mu);
list->kv->dbw->list_close(list->handle); list->kv->dbw->list_close(list->handle);
list->handle = NULL; list->handle = NULL;
} }
if (list->iter)
{
delete list->iter;
list->iter = NULL;
}
} }
+8 -14
View File
@@ -4,8 +4,6 @@
#ifndef NODE_VITASTOR_CLIENT_H #ifndef NODE_VITASTOR_CLIENT_H
#define NODE_VITASTOR_CLIENT_H #define NODE_VITASTOR_CLIENT_H
#include <mutex>
#include <nan.h> #include <nan.h>
#include <vitastor_c.h> #include <vitastor_c.h>
#include <vitastor_kv.h> #include <vitastor_kv.h>
@@ -34,8 +32,6 @@ private:
vitastor_c *c = NULL; vitastor_c *c = NULL;
int eventfd = -1; int eventfd = -1;
uv_poll_t poll_watcher; uv_poll_t poll_watcher;
// FIXME: Is it really needed?
std::mutex mu;
NodeVitastor(); NodeVitastor();
@@ -44,6 +40,9 @@ private:
static void on_write_finish(void *opaque, long retval); static void on_write_finish(void *opaque, long retval);
static void on_read_bitmap_finish(void *opaque, long retval, uint8_t *bitmap); static void on_read_bitmap_finish(void *opaque, long retval, uint8_t *bitmap);
NodeVitastorRequest* get_read_request(const Nan::FunctionCallbackInfo<v8::Value> & info, int argpos);
NodeVitastorRequest* get_write_request(const Nan::FunctionCallbackInfo<v8::Value> & info, int argpos);
friend class NodeVitastorImage; friend class NodeVitastorImage;
friend class NodeVitastorKV; friend class NodeVitastorKV;
friend class NodeVitastorKVListing; friend class NodeVitastorKVListing;
@@ -74,8 +73,6 @@ private:
std::vector<NodeVitastorRequest*> on_init; std::vector<NodeVitastorRequest*> on_init;
Nan::Persistent<v8::Object> cliObj; Nan::Persistent<v8::Object> cliObj;
NodeVitastorImage();
static void on_watch_start(void *opaque, long retval); static void on_watch_start(void *opaque, long retval);
void exec_request(NodeVitastorRequest *req); void exec_request(NodeVitastorRequest *req);
void exec_or_wait(NodeVitastorRequest *req); void exec_or_wait(NodeVitastorRequest *req);
@@ -86,7 +83,7 @@ class NodeVitastorKV: public Nan::ObjectWrap
public: public:
// constructor(node_vitastor) // constructor(node_vitastor)
static NAN_METHOD(Create); static NAN_METHOD(Create);
// open(inode_id, { ...config }, callback(err)) // open(pool_id, inode_num, { ...config }, callback(err))
static NAN_METHOD(Open); static NAN_METHOD(Open);
// set_config({ ...config }) // set_config({ ...config })
static NAN_METHOD(SetConfig); static NAN_METHOD(SetConfig);
@@ -98,9 +95,9 @@ public:
static NAN_METHOD(Get); static NAN_METHOD(Get);
// get_cached(key, callback(err, value)) // get_cached(key, callback(err, value))
static NAN_METHOD(GetCached); static NAN_METHOD(GetCached);
// set(key, value, callback(err), cas_compare(old_value)) // set(key, value, callback(err), cas_compare(old_value)?)
static NAN_METHOD(Set); static NAN_METHOD(Set);
// del(key, callback(err), cas_compare(old_value)) // del(key, callback(err), cas_compare(old_value)?)
static NAN_METHOD(Del); static NAN_METHOD(Del);
// list(start_key?) // list(start_key?)
static NAN_METHOD(List); static NAN_METHOD(List);
@@ -113,8 +110,6 @@ private:
NodeVitastor *cli = NULL; NodeVitastor *cli = NULL;
vitastorkv_dbw_t *dbw = NULL; vitastorkv_dbw_t *dbw = NULL;
NodeVitastorKV();
static void get_impl(const Nan::FunctionCallbackInfo<v8::Value> & info, bool allow_cache); static void get_impl(const Nan::FunctionCallbackInfo<v8::Value> & info, bool allow_cache);
friend class NodeVitastorKVListing; friend class NodeVitastorKVListing;
@@ -125,7 +120,7 @@ class NodeVitastorKVListing: public Nan::ObjectWrap
public: public:
// constructor(node_vitastor_kv, start_key?) // constructor(node_vitastor_kv, start_key?)
static NAN_METHOD(Create); static NAN_METHOD(Create);
// next(callback(err, value)) // next(callback(err, value)?)
static NAN_METHOD(Next); static NAN_METHOD(Next);
// close() // close()
static NAN_METHOD(Close); static NAN_METHOD(Close);
@@ -135,8 +130,7 @@ public:
private: private:
NodeVitastorKV *kv = NULL; NodeVitastorKV *kv = NULL;
void *handle = NULL; void *handle = NULL;
NodeVitastorRequest *iter = NULL;
NodeVitastorKVListing();
}; };
#endif #endif
+1
View File
@@ -0,0 +1 @@
module.exports = require('bindings')('addon.node');
+1 -1
View File
@@ -50,7 +50,7 @@ from cinder.volume import configuration
from cinder.volume import driver from cinder.volume import driver
from cinder.volume import volume_utils from cinder.volume import volume_utils
VITASTOR_VERSION = '1.7.1' VITASTOR_VERSION = '1.8.0'
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
+2 -2
View File
@@ -1,11 +1,11 @@
Name: vitastor Name: vitastor
Version: 1.7.1 Version: 1.8.0
Release: 1%{?dist} Release: 1%{?dist}
Summary: Vitastor, a fast software-defined clustered block storage Summary: Vitastor, a fast software-defined clustered block storage
License: Vitastor Network Public License 1.1 License: Vitastor Network Public License 1.1
URL: https://vitastor.io/ URL: https://vitastor.io/
Source0: vitastor-1.7.1.el7.tar.gz Source0: vitastor-1.8.0.el7.tar.gz
BuildRequires: liburing-devel >= 0.6 BuildRequires: liburing-devel >= 0.6
BuildRequires: gperftools-devel BuildRequires: gperftools-devel
+2 -2
View File
@@ -1,11 +1,11 @@
Name: vitastor Name: vitastor
Version: 1.7.1 Version: 1.8.0
Release: 1%{?dist} Release: 1%{?dist}
Summary: Vitastor, a fast software-defined clustered block storage Summary: Vitastor, a fast software-defined clustered block storage
License: Vitastor Network Public License 1.1 License: Vitastor Network Public License 1.1
URL: https://vitastor.io/ URL: https://vitastor.io/
Source0: vitastor-1.7.1.el8.tar.gz Source0: vitastor-1.8.0.el8.tar.gz
BuildRequires: liburing-devel >= 0.6 BuildRequires: liburing-devel >= 0.6
BuildRequires: gperftools-devel BuildRequires: gperftools-devel
+2 -2
View File
@@ -1,11 +1,11 @@
Name: vitastor Name: vitastor
Version: 1.7.1 Version: 1.8.0
Release: 1%{?dist} Release: 1%{?dist}
Summary: Vitastor, a fast software-defined clustered block storage Summary: Vitastor, a fast software-defined clustered block storage
License: Vitastor Network Public License 1.1 License: Vitastor Network Public License 1.1
URL: https://vitastor.io/ URL: https://vitastor.io/
Source0: vitastor-1.7.1.el9.tar.gz Source0: vitastor-1.8.0.el9.tar.gz
BuildRequires: liburing-devel >= 0.6 BuildRequires: liburing-devel >= 0.6
BuildRequires: gperftools-devel BuildRequires: gperftools-devel
+1 -1
View File
@@ -19,7 +19,7 @@ if("${CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/local/?$")
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
endif() endif()
add_definitions(-DVITASTOR_VERSION="1.7.1") add_definitions(-DVITASTOR_VERSION="1.8.0")
add_definitions(-D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wall -Wno-sign-compare -Wno-comment -Wno-parentheses -Wno-pointer-arith -fdiagnostics-color=always -fno-omit-frame-pointer -I ${CMAKE_SOURCE_DIR}/src) add_definitions(-D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wall -Wno-sign-compare -Wno-comment -Wno-parentheses -Wno-pointer-arith -fdiagnostics-color=always -fno-omit-frame-pointer -I ${CMAKE_SOURCE_DIR}/src)
add_link_options(-fno-omit-frame-pointer) add_link_options(-fno-omit-frame-pointer)
if (${WITH_ASAN}) if (${WITH_ASAN})
+5 -1
View File
@@ -1286,7 +1286,11 @@ void cluster_client_t::handle_op_part(cluster_op_part_t *part)
if (op->opcode == OSD_OP_READ || op->opcode == OSD_OP_READ_BITMAP || op->opcode == OSD_OP_READ_CHAIN_BITMAP) if (op->opcode == OSD_OP_READ || op->opcode == OSD_OP_READ_BITMAP || op->opcode == OSD_OP_READ_CHAIN_BITMAP)
{ {
copy_part_bitmap(op, part); copy_part_bitmap(op, part);
op->version = op->parts.size() == 1 ? part->op.reply.rw.version : 0; if (op->inode == op->cur_inode)
{
// Read only returns the version of the uppermost layer
op->version = op->parts.size() == 1 ? part->op.reply.rw.version : 0;
}
} }
else if (op->opcode == OSD_OP_WRITE) else if (op->opcode == OSD_OP_WRITE)
{ {
+1 -1
View File
@@ -6,7 +6,7 @@ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
Name: Vitastor Name: Vitastor
Description: Vitastor client library Description: Vitastor client library
Version: 1.7.1 Version: 1.8.0
Libs: -L${libdir} -lvitastor_client Libs: -L${libdir} -lvitastor_client
Cflags: -I${includedir} Cflags: -I${includedir}
+17 -4
View File
@@ -522,17 +522,15 @@ void nfs_proxy_t::do_accept(int listen_fd)
{ {
cli->proc_table.insert(fn); cli->proc_table.insert(fn);
} }
rpc_clients[nfs_fd] = cli;
epmgr->tfd->set_fd_handler(nfs_fd, true, [cli](int nfs_fd, int epoll_events) epmgr->tfd->set_fd_handler(nfs_fd, true, [cli](int nfs_fd, int epoll_events)
{ {
// Handle incoming event // Handle incoming event
if (epoll_events & EPOLLRDHUP) if (epoll_events & EPOLLRDHUP)
{ {
auto parent = cli->parent; if (cli->parent->trace)
if (parent->trace)
fprintf(stderr, "Client %d disconnected\n", nfs_fd); fprintf(stderr, "Client %d disconnected\n", nfs_fd);
cli->stop(); cli->stop();
parent->active_connections--;
parent->check_exit();
return; return;
} }
cli->epoll_events |= epoll_events; cli->epoll_events |= epoll_events;
@@ -695,6 +693,8 @@ void nfs_client_t::handle_read(int result)
frag_num++; frag_num++;
} }
} }
// Increase client refcount while the RPC call is being processed
refs++;
// Handle full message // Handle full message
int referenced = handle_rpc_message(cur_buffer.buf, data+4, wanted-4*fragments); int referenced = handle_rpc_message(cur_buffer.buf, data+4, wanted-4*fragments);
cur_buffer.refs += referenced ? 1 : 0; cur_buffer.refs += referenced ? 1 : 0;
@@ -779,9 +779,13 @@ void nfs_client_t::stop()
stopped = true; stopped = true;
if (refs <= 0) if (refs <= 0)
{ {
auto parent = this->parent;
parent->rpc_clients.erase(nfs_fd);
parent->active_connections--;
parent->epmgr->tfd->set_fd_handler(nfs_fd, true, NULL); parent->epmgr->tfd->set_fd_handler(nfs_fd, true, NULL);
close(nfs_fd); close(nfs_fd);
delete this; delete this;
parent->check_exit();
} }
} }
@@ -834,6 +838,10 @@ void nfs_client_t::handle_send(int result)
} }
} }
free(rop); free(rop);
if (deref())
{
return;
}
} }
result -= iov.iov_len; result -= iov.iov_len;
done++; done++;
@@ -1056,6 +1064,11 @@ int nfs_client_t::handle_rpc_message(void *base_buf, void *msg_buf, uint32_t msg
void nfs_proxy_t::daemonize() void nfs_proxy_t::daemonize()
{ {
// Stop all clients because client I/O sometimes breaks during daemonize
// I.e. the new process stops receiving events on the old FD
// It doesn't happen if we call sleep(1) here, but we don't want to call sleep(1)...
for (auto & clp: rpc_clients)
clp.second->stop();
if (fork()) if (fork())
exit(0); exit(0);
setsid(); setsid();
+2
View File
@@ -21,6 +21,7 @@ class cli_tool_t;
struct kv_fs_state_t; struct kv_fs_state_t;
struct block_fs_state_t; struct block_fs_state_t;
class nfs_client_t;
class nfs_proxy_t class nfs_proxy_t
{ {
@@ -54,6 +55,7 @@ public:
vitastorkv_dbw_t *db = NULL; vitastorkv_dbw_t *db = NULL;
kv_fs_state_t *kvfs = NULL; kv_fs_state_t *kvfs = NULL;
block_fs_state_t *blockfs = NULL; block_fs_state_t *blockfs = NULL;
std::map<int, nfs_client_t*> rpc_clients;
std::vector<XDR*> xdr_pool; std::vector<XDR*> xdr_pool;