From a4dfc220ab96ef339a20f347bf74ba3a9f0ef601 Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Sun, 19 May 2024 01:58:28 +0300 Subject: [PATCH] Implement basic node.js binding (not published on npm yet) --- node-binding/addon.cc | 80 ++++ node-binding/addon.h | 20 + node-binding/binding.gyp | 20 + node-binding/client.cc | 853 ++++++++++++++++++++++++++++++++++++++ node-binding/client.h | 142 +++++++ node-binding/package.json | 24 ++ src/client/vitastor_c.cpp | 22 + src/client/vitastor_c.h | 3 + src/kv/kv_cli.cpp | 6 +- src/kv/kv_db.cpp | 26 +- src/kv/kv_stress.cpp | 4 +- src/kv/vitastor_kv.h | 6 +- src/nfs/nfs_kv.cpp | 2 +- src/nfs/nfs_proxy.h | 2 +- 14 files changed, 1187 insertions(+), 23 deletions(-) create mode 100644 node-binding/addon.cc create mode 100644 node-binding/addon.h create mode 100644 node-binding/binding.gyp create mode 100644 node-binding/client.cc create mode 100644 node-binding/client.h create mode 100644 node-binding/package.json diff --git a/node-binding/addon.cc b/node-binding/addon.cc new file mode 100644 index 00000000..e5a30c0d --- /dev/null +++ b/node-binding/addon.cc @@ -0,0 +1,80 @@ +// Copyright (c) Vitaliy Filippov, 2019+ +// License: VNPL-1.1 (see README.md for details) + +#include "addon.h" + +// Initialize the node addon +NAN_MODULE_INIT(InitAddon) +{ + // vitastor.Client + + v8::Local tpl = Nan::New(NodeVitastor::Create); + tpl->SetClassName(Nan::New("Client").ToLocalChecked()); + tpl->InstanceTemplate()->SetInternalFieldCount(1); + + Nan::SetPrototypeMethod(tpl, "read", NodeVitastor::Read); + Nan::SetPrototypeMethod(tpl, "write", NodeVitastor::Write); + Nan::SetPrototypeMethod(tpl, "sync", NodeVitastor::Sync); + Nan::SetPrototypeMethod(tpl, "read_bitmap", NodeVitastor::ReadBitmap); + //Nan::SetPrototypeMethod(tpl, "destroy", NodeVitastor::Destroy); + + Nan::Set(target, Nan::New("Client").ToLocalChecked(), Nan::GetFunction(tpl).ToLocalChecked()); + + // vitastor.Image (opened image) + + tpl = Nan::New(NodeVitastorImage::Create); + tpl->SetClassName(Nan::New("Image").ToLocalChecked()); + tpl->InstanceTemplate()->SetInternalFieldCount(2); + + Nan::SetPrototypeMethod(tpl, "read", NodeVitastorImage::Read); + Nan::SetPrototypeMethod(tpl, "write", NodeVitastorImage::Write); + Nan::SetPrototypeMethod(tpl, "sync", NodeVitastorImage::Sync); + Nan::SetPrototypeMethod(tpl, "get_info", NodeVitastorImage::GetInfo); + Nan::SetPrototypeMethod(tpl, "read_bitmap", NodeVitastorImage::ReadBitmap); + + Nan::Set(target, Nan::New("Image").ToLocalChecked(), Nan::GetFunction(tpl).ToLocalChecked()); + + // vitastor.KV + + tpl = Nan::New(NodeVitastorKV::Create); + tpl->SetClassName(Nan::New("KV").ToLocalChecked()); + tpl->InstanceTemplate()->SetInternalFieldCount(1); + + Nan::SetPrototypeMethod(tpl, "open", NodeVitastorKV::Open); + Nan::SetPrototypeMethod(tpl, "set_config", NodeVitastorKV::SetConfig); + Nan::SetPrototypeMethod(tpl, "close", NodeVitastorKV::Close); + Nan::SetPrototypeMethod(tpl, "get_size", NodeVitastorKV::GetSize); + Nan::SetPrototypeMethod(tpl, "get", NodeVitastorKV::Get); + Nan::SetPrototypeMethod(tpl, "get_cached", NodeVitastorKV::GetCached); + Nan::SetPrototypeMethod(tpl, "set", NodeVitastorKV::Set); + Nan::SetPrototypeMethod(tpl, "del", NodeVitastorKV::Del); + Nan::SetPrototypeMethod(tpl, "list", NodeVitastorKV::List); + + Nan::Set(target, Nan::New("KV").ToLocalChecked(), Nan::GetFunction(tpl).ToLocalChecked()); + + Nan::Set(target, Nan::New("ENOENT").ToLocalChecked(), Nan::New(-ENOENT)); + Nan::Set(target, Nan::New("EIO").ToLocalChecked(), Nan::New(-EIO)); + Nan::Set(target, Nan::New("EINVAL").ToLocalChecked(), Nan::New(-EINVAL)); + Nan::Set(target, Nan::New("EROFS").ToLocalChecked(), Nan::New(-EROFS)); + Nan::Set(target, Nan::New("ENOSPC").ToLocalChecked(), Nan::New(-ENOSPC)); + Nan::Set(target, Nan::New("EINTR").ToLocalChecked(), Nan::New(-EINTR)); + Nan::Set(target, Nan::New("EILSEQ").ToLocalChecked(), Nan::New(-EILSEQ)); + Nan::Set(target, Nan::New("ENOTBLK").ToLocalChecked(), Nan::New(-ENOTBLK)); + Nan::Set(target, Nan::New("ENOSYS").ToLocalChecked(), Nan::New(-ENOSYS)); + Nan::Set(target, Nan::New("EAGAIN").ToLocalChecked(), Nan::New(-EAGAIN)); + + // Listing handle + + tpl = Nan::New(NodeVitastorKVListing::Create); + tpl->SetClassName(Nan::New("KVListing").ToLocalChecked()); + tpl->InstanceTemplate()->SetInternalFieldCount(2); + + Nan::SetPrototypeMethod(tpl, "next", NodeVitastorKVListing::Next); + Nan::SetPrototypeMethod(tpl, "close", NodeVitastorKVListing::Close); + + Nan::Set(target, Nan::New("KVListing").ToLocalChecked(), Nan::GetFunction(tpl).ToLocalChecked()); + + NodeVitastorKV::listing_class.Reset(Nan::GetFunction(tpl).ToLocalChecked()); +} + +NODE_MODULE(addon, (void*)InitAddon) diff --git a/node-binding/addon.h b/node-binding/addon.h new file mode 100644 index 00000000..dd728a37 --- /dev/null +++ b/node-binding/addon.h @@ -0,0 +1,20 @@ +// Copyright (c) Vitaliy Filippov, 2019+ +// License: VNPL-1.1 (see README.md for details) + +#ifndef NODE_VITASTOR_ADDON_H +#define NODE_VITASTOR_ADDON_H + +#include +#include + +#include "client.h" + +#define ERRORF(format, ...) fprintf(stderr, format "\n", __VA_ARGS__); + +#define TRACEF(format, ...) fprintf(stderr, format "\n", __VA_ARGS__); +#define TRACE(msg) fprintf(stderr, "%s\n", msg); + +//#define TRACEF(format, arg) ; +//#define TRACE(msg) ; + +#endif diff --git a/node-binding/binding.gyp b/node-binding/binding.gyp new file mode 100644 index 00000000..4bbdb7d6 --- /dev/null +++ b/node-binding/binding.gyp @@ -0,0 +1,20 @@ +{ + 'targets': [ + { + 'target_name': 'addon', + 'sources': [ + 'client.cc', + 'addon.cc' + ], + 'include_dirs': [ + '> (64 - POOL_ID_BITS)) +#define INODE_NO_POOL(inode) (uint64_t)((inode) & (((uint64_t)1 << (64-POOL_ID_BITS)) - 1)) +#define INODE_WITH_POOL(pool_id, inode) (((uint64_t)(pool_id) << (64-POOL_ID_BITS)) | INODE_NO_POOL(inode)) +#endif + +class NodeVitastorRequest: public Nan::AsyncResource +{ +public: + NodeVitastorRequest(v8::Local cb): Nan::AsyncResource("NodeVitastorRequest") + { + callback.Reset(cb); + } + + iovec iov; + NodeVitastorImage *img = NULL; + int op = 0; + uint64_t offset = 0, len = 0, version = 0; + bool with_parents = false; + Nan::Persistent callback; +}; + +////////////////////////////////////////////////// +// NodeVitastor +////////////////////////////////////////////////// + +NodeVitastor::NodeVitastor(): Nan::ObjectWrap() +{ + TRACE("NodeVitastor: constructor"); + poll_watcher.data = this; +} + +NodeVitastor::~NodeVitastor() +{ + uv_poll_stop(&poll_watcher); + vitastor_c_destroy(c); + c = NULL; +} + +NAN_METHOD(NodeVitastor::Create) +{ + TRACE("NodeVitastor::Create"); + v8::Local jsParams = info[0].As(); + v8::Local keys = Nan::GetOwnPropertyNames(jsParams).ToLocalChecked(); + std::vector cfg; + for (uint32_t i = 0; i < keys->Length(); i++) + { + auto key = Nan::Get(keys, i).ToLocalChecked(); + cfg.push_back(std::string(*Nan::Utf8String(key))); + cfg.push_back(std::string(*Nan::Utf8String(Nan::Get(jsParams, key).ToLocalChecked()))); + } + + const char **c_cfg = new const char*[cfg.size()]; + for (size_t i = 0; i < cfg.size(); i++) + { + c_cfg[i] = cfg[i].c_str(); + } + NodeVitastor* cli = new NodeVitastor(); + cli->c = vitastor_c_create_uring_json(c_cfg, cfg.size()); + delete[] c_cfg; + + int res = vitastor_c_uring_register_eventfd(cli->c); + if (res >= 0) + { + cli->eventfd = res; + res = uv_poll_init_socket(uv_default_loop(), &cli->poll_watcher, cli->eventfd); + if (res >= 0) + res = uv_poll_start(&cli->poll_watcher, UV_READABLE, on_io_readable); + } + if (res < 0) + { + ERRORF("NodeVitastor: failed to create and register io_uring eventfd in libuv: %s", strerror(-cli->eventfd)); + vitastor_c_destroy(cli->c); + cli->c = NULL; + Nan::ThrowError("failed to create and register io_uring eventfd"); + return; + } + + cli->Wrap(info.This()); + info.GetReturnValue().Set(info.This()); +} + +void NodeVitastor::on_io_readable(uv_poll_t* handle, int status, int revents) +{ + TRACEF("NodeVitastor::on_io_readable status/revents %d %d", status, revents); + if (revents & UV_READABLE) + { + NodeVitastor* self = (NodeVitastor*)handle->data; + std::unique_lock lock(self->mu); + vitastor_c_uring_handle_events(self->c); + } +} + +static NodeVitastorRequest* getReadRequest(const Nan::FunctionCallbackInfo & info, int argpos) +{ + uint64_t offset = Nan::To(info[argpos+0]).FromJust(); + uint64_t len = Nan::To(info[argpos+1]).FromJust(); + uint8_t *buf = (uint8_t*)malloc(len); + if (!buf) + { + Nan::ThrowError("failed to allocate memory"); + return NULL; + } + v8::Local callback = info[argpos+2].As(); + auto req = new NodeVitastorRequest(callback); + + req->offset = offset; + req->len = len; + req->iov = { .iov_base = buf, .iov_len = len }; + + return req; +} + +// read(pool, inode, offset, len, callback(err, buffer, version)) +NAN_METHOD(NodeVitastor::Read) +{ + TRACE("NodeVitastor::Read"); + + NodeVitastor* self = Nan::ObjectWrap::Unwrap(info.This()); + + uint64_t pool = Nan::To(info[0]).FromJust(); + uint64_t inode = Nan::To(info[1]).FromJust(); + + auto req = getReadRequest(info, 2); + + std::unique_lock lock(self->mu); + 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 & info, int argpos) +{ + uint64_t offset = Nan::To(info[argpos+0]).FromJust(); + char *buf = node::Buffer::Data(info[argpos+1]); + uint64_t len = node::Buffer::Length(info[argpos+1]); + uint64_t version = 0; + + if (!info[argpos+2].IsEmpty() && info[argpos+2]->IsObject()) + { + auto key = Nan::New("version").ToLocalChecked(); + auto params = info[argpos+2].As(); + auto versionObj = Nan::Get(params, key).ToLocalChecked(); + if (!versionObj.IsEmpty()) + version = Nan::To(versionObj).FromJust(); + argpos++; + } + + v8::Local callback = info[argpos+2].As(); + auto req = new NodeVitastorRequest(callback); + + req->offset = offset; + req->len = len; + req->version = version; + req->iov = { .iov_base = buf, .iov_len = req->len }; + + return req; +} + +// write(pool, inode, offset, buffer, { version }?, callback(err)) +NAN_METHOD(NodeVitastor::Write) +{ + TRACE("NodeVitastor::Write"); + + NodeVitastor* self = Nan::ObjectWrap::Unwrap(info.This()); + + uint64_t pool = Nan::To(info[0]).FromJust(); + uint64_t inode = Nan::To(info[1]).FromJust(); + + auto req = getWriteRequest(info, 2); + + std::unique_lock lock(self->mu); + vitastor_c_write(self->c, ((pool << (64-POOL_ID_BITS)) | inode), req->offset, req->len, req->version, &req->iov, 1, on_write_finish, req); +} + +// sync(callback(err)) +NAN_METHOD(NodeVitastor::Sync) +{ + TRACE("NodeVitastor::Sync"); + + NodeVitastor* self = Nan::ObjectWrap::Unwrap(info.This()); + + v8::Local callback = info[0].As(); + auto req = new NodeVitastorRequest(callback); + + std::unique_lock lock(self->mu); + vitastor_c_sync(self->c, on_write_finish, req); +} + +// read_bitmap(pool, inode, offset, len, with_parents, callback(err, bitmap_buffer)) +NAN_METHOD(NodeVitastor::ReadBitmap) +{ + TRACE("NodeVitastor::ReadBitmap"); + + NodeVitastor* self = Nan::ObjectWrap::Unwrap(info.This()); + + uint64_t pool = Nan::To(info[0]).FromJust(); + uint64_t inode = Nan::To(info[1]).FromJust(); + uint64_t offset = Nan::To(info[2]).FromJust(); + uint64_t len = Nan::To(info[3]).FromJust(); + bool with_parents = Nan::To(info[4]).FromJust(); + v8::Local callback = info[5].As(); + + auto req = new NodeVitastorRequest(callback); + vitastor_c_read_bitmap(self->c, ((pool << (64-POOL_ID_BITS)) | inode), offset, len, with_parents, on_read_bitmap_finish, req); +} + +static void on_error(NodeVitastorRequest *req, Nan::Callback & nanCallback, long retval) +{ + // Legal errors: EINVAL, EIO, EROFS, ENOSPC, EINTR, ENOENT + v8::Local args[1]; + if (!retval) + args[0] = Nan::Null(); + else + args[0] = Nan::New((int32_t)retval); + nanCallback.Call(1, args, req); +} + +void NodeVitastor::on_read_finish(void *opaque, long retval, uint64_t version) +{ + Nan::HandleScope scope; + NodeVitastorRequest *req = (NodeVitastorRequest *)opaque; + Nan::Callback nanCallback(Nan::New(req->callback)); + if (retval == -ENOENT) + { + free(req->iov.iov_base); + nanCallback.Call(0, NULL, req); + } + else if (retval < 0) + { + free(req->iov.iov_base); + on_error(req, nanCallback, retval); + } + else + { + v8::Local args[3]; + args[0] = Nan::Null(); + args[1] = Nan::NewBuffer((char*)req->iov.iov_base, req->iov.iov_len).ToLocalChecked(); + args[2] = v8::BigInt::NewFromUnsigned(v8::Isolate::GetCurrent(), version); + nanCallback.Call(3, args, req); + } + delete req; +} + +void NodeVitastor::on_write_finish(void *opaque, long retval) +{ + Nan::HandleScope scope; + NodeVitastorRequest *req = (NodeVitastorRequest *)opaque; + Nan::Callback nanCallback(Nan::New(req->callback)); + on_error(req, nanCallback, retval); + delete req; +} + +void NodeVitastor::on_read_bitmap_finish(void *opaque, long retval, uint8_t *bitmap) +{ + Nan::HandleScope scope; + NodeVitastorRequest *req = (NodeVitastorRequest *)opaque; + Nan::Callback nanCallback(Nan::New(req->callback)); + if (retval == -ENOENT) + nanCallback.Call(0, NULL, req); + else if (retval < 0) + on_error(req, nanCallback, retval); + else + { + v8::Local args[2]; + args[0] = Nan::Null(); + args[1] = Nan::NewBuffer((char*)bitmap, (retval+7)/8).ToLocalChecked(); + nanCallback.Call(2, args, req); + } + delete req; +} + +//NAN_METHOD(NodeVitastor::Destroy) +//{ +// TRACE("NodeVitastor::Destroy"); +//} + +////////////////////////////////////////////////// +// NodeVitastorImage +////////////////////////////////////////////////// + +NAN_METHOD(NodeVitastorImage::Create) +{ + TRACE("NodeVitastorImage::Create"); + + v8::Local parent = info[0].As(); + std::string name = std::string(*Nan::Utf8String(info[1].As())); + NodeVitastor *cli = Nan::ObjectWrap::Unwrap(parent); + + NodeVitastorImage *img = new NodeVitastorImage(); + img->cli = cli; + img->name = name; + + img->Ref(); + cli->Ref(); + std::unique_lock lock(cli->mu); + vitastor_c_watch_inode(cli->c, (char*)img->name.c_str(), on_watch_start, img); + + img->Wrap(info.This()); + info.GetReturnValue().Set(info.This()); +} + +NodeVitastorImage::~NodeVitastorImage() +{ + if (watch) + { + vitastor_c_close_watch(cli->c, watch); + watch = NULL; + } + cli->Unref(); +} + +// read(offset, len, callback(err, buffer, version)) +NAN_METHOD(NodeVitastorImage::Read) +{ + TRACE("NodeVitastorImage::Read"); + + NodeVitastorImage* img = Nan::ObjectWrap::Unwrap(info.This()); + + auto req = getReadRequest(info, 0); + req->img = img; + req->op = NODE_VITASTOR_READ; + + img->exec_or_wait(req); +} + +// write(offset, buffer, { version }?, callback(err)) +NAN_METHOD(NodeVitastorImage::Write) +{ + TRACE("NodeVitastorImage::Write"); + + NodeVitastorImage* img = Nan::ObjectWrap::Unwrap(info.This()); + + auto req = getWriteRequest(info, 0); + req->img = img; + req->op = NODE_VITASTOR_WRITE; + + img->exec_or_wait(req); +} + +NAN_METHOD(NodeVitastorImage::Sync) +{ + TRACE("NodeVitastorImage::Sync"); + + NodeVitastorImage* img = Nan::ObjectWrap::Unwrap(info.This()); + + v8::Local callback = info[0].As(); + auto req = new NodeVitastorRequest(callback); + req->img = img; + req->op = NODE_VITASTOR_SYNC; + + img->exec_or_wait(req); +} + +// read_bitmap(offset, len, with_parents, callback(err, bitmap_buffer)) +NAN_METHOD(NodeVitastorImage::ReadBitmap) +{ + TRACE("NodeVitastorImage::ReadBitmap"); + + NodeVitastorImage* img = Nan::ObjectWrap::Unwrap(info.This()); + + uint64_t offset = Nan::To(info[0]).FromJust(); + uint64_t len = Nan::To(info[1]).FromJust(); + bool with_parents = Nan::To(info[2]).FromJust(); + v8::Local callback = info[3].As(); + + auto req = new NodeVitastorRequest(callback); + req->img = img; + req->op = NODE_VITASTOR_READ_BITMAP; + req->offset = offset; + req->len = len; + req->with_parents = with_parents; + + img->exec_or_wait(req); +} + +NAN_METHOD(NodeVitastorImage::GetInfo) +{ + TRACE("NodeVitastorImage::Sync"); + + NodeVitastorImage* img = Nan::ObjectWrap::Unwrap(info.This()); + + v8::Local callback = info[0].As(); + auto req = new NodeVitastorRequest(callback); + req->img = img; + req->op = NODE_VITASTOR_GET_INFO; + + img->exec_or_wait(req); +} + +void NodeVitastorImage::exec_or_wait(NodeVitastorRequest *req) +{ + if (!watch) + { + // Need to wait for initialisation + on_init.push_back(req); + } + else + { + exec_request(req); + } +} + +void NodeVitastorImage::exec_request(NodeVitastorRequest *req) +{ + std::unique_lock lock(cli->mu); + if (req->op == NODE_VITASTOR_READ) + { + uint64_t ino = vitastor_c_inode_get_num(watch); + 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) + { + uint64_t ino = vitastor_c_inode_get_num(watch); + vitastor_c_write(cli->c, ino, req->offset, req->len, req->version, &req->iov, 1, NodeVitastor::on_write_finish, req); + } + else if (req->op == NODE_VITASTOR_SYNC) + { + uint64_t ino = vitastor_c_inode_get_num(watch); + uint32_t imm = vitastor_c_inode_get_immediate_commit(cli->c, ino); + if (imm != IMMEDIATE_ALL) + { + vitastor_c_sync(cli->c, NodeVitastor::on_write_finish, req); + } + else + { + NodeVitastor::on_write_finish(req, 0); + } + } + else if (req->op == NODE_VITASTOR_READ_BITMAP) + { + uint64_t ino = vitastor_c_inode_get_num(watch); + 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) + { + uint64_t size = vitastor_c_inode_get_size(watch); + uint64_t num = vitastor_c_inode_get_num(watch); + uint32_t block_size = vitastor_c_inode_get_block_size(cli->c, num); + uint32_t bitmap_granularity = vitastor_c_inode_get_bitmap_granularity(cli->c, num); + int readonly = vitastor_c_inode_get_readonly(watch); + uint32_t immediate_commit = vitastor_c_inode_get_immediate_commit(cli->c, num); + uint64_t parent_id = vitastor_c_inode_get_parent_id(watch); + char *meta = vitastor_c_inode_get_meta(watch); + uint64_t mod_revision = vitastor_c_inode_get_mod_revision(watch); + + Nan::HandleScope scope; + + v8::Local res = Nan::New(); + Nan::Set(res, Nan::New("pool_id").ToLocalChecked(), Nan::New(INODE_POOL(num))); + Nan::Set(res, Nan::New("inode_num").ToLocalChecked(), Nan::New(INODE_NO_POOL(num))); + if (size < ((uint64_t)1<<53)) + Nan::Set(res, Nan::New("size").ToLocalChecked(), Nan::New(size)); + else + Nan::Set(res, Nan::New("size").ToLocalChecked(), v8::BigInt::NewFromUnsigned(v8::Isolate::GetCurrent(), size)); + if (parent_id) + { + Nan::Set(res, Nan::New("parent_pool_id").ToLocalChecked(), Nan::New(INODE_POOL(parent_id))); + Nan::Set(res, Nan::New("parent_inode_num").ToLocalChecked(), Nan::New(INODE_NO_POOL(parent_id))); + } + Nan::Set(res, Nan::New("readonly").ToLocalChecked(), Nan::New((bool)readonly)); + if (meta) + { + Nan::JSON nanJSON; + Nan::Set(res, Nan::New("meta").ToLocalChecked(), nanJSON.Parse(Nan::New(meta).ToLocalChecked()).ToLocalChecked()); + } + if (mod_revision < ((uint64_t)1<<53)) + Nan::Set(res, Nan::New("mod_revision").ToLocalChecked(), Nan::New(mod_revision)); + else + Nan::Set(res, Nan::New("mod_revision").ToLocalChecked(), v8::BigInt::NewFromUnsigned(v8::Isolate::GetCurrent(), mod_revision)); + Nan::Set(res, Nan::New("block_size").ToLocalChecked(), Nan::New(block_size)); + Nan::Set(res, Nan::New("bitmap_granularity").ToLocalChecked(), Nan::New(bitmap_granularity)); + Nan::Set(res, Nan::New("immediate_commit").ToLocalChecked(), Nan::New(immediate_commit)); + + Nan::Callback nanCallback(Nan::New(req->callback)); + v8::Local args[1]; + args[0] = res; + nanCallback.Call(1, args, req); + + delete req; + } +} + +void NodeVitastorImage::on_watch_start(void *opaque, long retval) +{ + NodeVitastorImage *img = (NodeVitastorImage *)opaque; + { + img->watch = (void*)retval; + auto on_init = std::move(img->on_init); + for (auto req: on_init) + { + img->exec_request(req); + } + } + img->Unref(); +} + +////////////////////////////////////////////////// +// NodeVitastorKV +////////////////////////////////////////////////// + +// constructor(node_vitastor) +NAN_METHOD(NodeVitastorKV::Create) +{ + TRACE("NodeVitastorKV::Create"); + + v8::Local parent = info[0].As(); + NodeVitastor *cli = Nan::ObjectWrap::Unwrap(parent); + + NodeVitastorKV *kv = new NodeVitastorKV(); + kv->cli = cli; + { + std::unique_lock lock(cli->mu); + kv->dbw = new vitastorkv_dbw_t((cluster_client_t*)vitastor_c_get_internal_client(cli->c)); + } + + kv->Wrap(info.This()); + info.GetReturnValue().Set(info.This()); +} + +NodeVitastorKV::~NodeVitastorKV() +{ + delete dbw; +} + +// open(inode_id, { ...config }, callback(err)) +NAN_METHOD(NodeVitastorKV::Open) +{ + TRACE("NodeVitastorKV::Open"); + + NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap(info.This()); + + uint64_t inode_id = Nan::To(info[0]).FromJust(); + + v8::Local jsParams = info[1].As(); + v8::Local keys = Nan::GetOwnPropertyNames(jsParams).ToLocalChecked(); + std::map cfg; + for (uint32_t i = 0; i < keys->Length(); i++) + { + auto key = Nan::Get(keys, i).ToLocalChecked(); + cfg[std::string(*Nan::Utf8String(key))] = std::string(*Nan::Utf8String(Nan::Get(jsParams, key).ToLocalChecked())); + } + + v8::Local callback = info[2].As(); + auto req = new NodeVitastorRequest(callback); + + kv->Ref(); + kv->dbw->open(inode_id, cfg, [kv, req](int res) + { + Nan::HandleScope scope; + Nan::Callback nanCallback(Nan::New(req->callback)); + v8::Local args[1]; + args[0] = !res ? v8::Local(Nan::Null()) : v8::Local(Nan::New(res)); + nanCallback.Call(1, args, req); + delete req; + kv->Unref(); + }); +} + +// close(callback(err)) +NAN_METHOD(NodeVitastorKV::Close) +{ + TRACE("NodeVitastorKV::Close"); + + NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap(info.This()); + + v8::Local callback = info[0].As(); + auto req = new NodeVitastorRequest(callback); + + kv->Ref(); + kv->dbw->close([kv, req]() + { + Nan::HandleScope scope; + Nan::Callback nanCallback(Nan::New(req->callback)); + nanCallback.Call(0, NULL, req); + delete req; + kv->Unref(); + }); +} + +// set_config({ ...config }) +NAN_METHOD(NodeVitastorKV::SetConfig) +{ + TRACE("NodeVitastorKV::SetConfig"); + + NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap(info.This()); + + v8::Local jsParams = info[0].As(); + v8::Local keys = Nan::GetOwnPropertyNames(jsParams).ToLocalChecked(); + std::map cfg; + for (uint32_t i = 0; i < keys->Length(); i++) + { + auto key = Nan::Get(keys, i).ToLocalChecked(); + cfg[std::string(*Nan::Utf8String(key))] = std::string(*Nan::Utf8String(Nan::Get(jsParams, key).ToLocalChecked())); + } + + kv->dbw->set_config(cfg); +} + +// get_size() +NAN_METHOD(NodeVitastorKV::GetSize) +{ + TRACE("NodeVitastorKV::GetSize"); + + NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap(info.This()); + + auto size = kv->dbw->get_size(); + info.GetReturnValue().Set((size < ((uint64_t)1<<53)) + ? v8::Local(Nan::New(size)) + : v8::Local(v8::BigInt::NewFromUnsigned(info.GetIsolate(), size))); +} + +void NodeVitastorKV::get_impl(const Nan::FunctionCallbackInfo & info, bool allow_cache) +{ + NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap(info.This()); + + // FIXME: Handle Buffer too + std::string key(*Nan::Utf8String(info[0].As())); + + v8::Local callback = info[1].As(); + auto req = new NodeVitastorRequest(callback); + + kv->Ref(); + kv->dbw->get(key, [kv, req](int res, const std::string & value) + { + Nan::HandleScope scope; + Nan::Callback nanCallback(Nan::New(req->callback)); + v8::Local args[2]; + args[0] = !res ? v8::Local(Nan::Null()) : v8::Local(Nan::New(res)); + args[1] = !res ? v8::Local(Nan::New(value).ToLocalChecked()) : v8::Local(Nan::Null()); + nanCallback.Call(2, args, req); + delete req; + kv->Unref(); + }, allow_cache); +} + +// get(key, callback(err, value)) +NAN_METHOD(NodeVitastorKV::Get) +{ + TRACE("NodeVitastorKV::Get"); + get_impl(info, false); +} + +// get_cached(key, callback(err, value)) +NAN_METHOD(NodeVitastorKV::GetCached) +{ + TRACE("NodeVitastorKV::GetCached"); + get_impl(info, true); +} + +static std::function make_cas_callback(NodeVitastorRequest *cas_req) +{ + return [cas_req](int res, const std::string & value) + { + Nan::HandleScope scope; + Nan::Callback nanCallback(Nan::New(cas_req->callback)); + v8::Local args[1]; + args[0] = !res ? v8::Local(Nan::New(value).ToLocalChecked()) : v8::Local(Nan::Null()); + Nan::MaybeLocal ret = nanCallback.Call(1, args, cas_req); + if (ret.IsEmpty()) + return false; + return Nan::To(ret.ToLocalChecked()).FromJust(); + }; +} + +// set(key, value, callback(err), cas_compare(old_value)) +NAN_METHOD(NodeVitastorKV::Set) +{ + TRACE("NodeVitastorKV::Set"); + + NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap(info.This()); + + // FIXME: Handle Buffer too + std::string key(*Nan::Utf8String(info[0].As())); + std::string value(*Nan::Utf8String(info[1].As())); + + v8::Local callback = info[2].As(); + NodeVitastorRequest *req = new NodeVitastorRequest(callback), *cas_req = NULL; + + std::function cas_cb; + if (info.Length() > 3 && info[3]->IsObject()) + { + v8::Local cas_callback = info[3].As(); + cas_req = new NodeVitastorRequest(cas_callback); + cas_cb = make_cas_callback(cas_req); + } + + kv->Ref(); + kv->dbw->set(key, value, [kv, req, cas_req](int res) + { + Nan::HandleScope scope; + Nan::Callback nanCallback(Nan::New(req->callback)); + v8::Local args[1]; + args[0] = !res ? v8::Local(Nan::Null()) : v8::Local(Nan::New(res)); + nanCallback.Call(1, args, req); + delete req; + if (cas_req) + delete cas_req; + kv->Unref(); + }, cas_cb); +} + +// del(key, callback(err), cas_compare(old_value)) +NAN_METHOD(NodeVitastorKV::Del) +{ + TRACE("NodeVitastorKV::Del"); + + NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap(info.This()); + + // FIXME: Handle Buffer too + std::string key(*Nan::Utf8String(info[0].As())); + + v8::Local callback = info[1].As(); + NodeVitastorRequest *req = new NodeVitastorRequest(callback), *cas_req = NULL; + + std::function cas_cb; + if (info.Length() > 2 && info[2]->IsObject()) + { + v8::Local cas_callback = info[2].As(); + cas_req = new NodeVitastorRequest(cas_callback); + cas_cb = make_cas_callback(cas_req); + } + + kv->Ref(); + kv->dbw->del(key, [kv, req, cas_req](int res) + { + Nan::HandleScope scope; + Nan::Callback nanCallback(Nan::New(req->callback)); + v8::Local args[1]; + args[0] = !res ? v8::Local(Nan::Null()) : v8::Local(Nan::New(res)); + nanCallback.Call(1, args, req); + delete req; + if (cas_req) + delete cas_req; + kv->Unref(); + }, cas_cb); +} + +// list(start_key?) +NAN_METHOD(NodeVitastorKV::List) +{ + TRACE("NodeVitastorKV::List"); + + v8::Local cons = Nan::New(listing_class); + v8::Local args[2]; + args[0] = info.This(); + int narg = 1; + if (info.Length() > 1 && info[1]->IsString()) + { + args[1] = info[1]; + narg = 2; + } + info.GetReturnValue().Set(Nan::NewInstance(cons, narg, args).ToLocalChecked()); +} + +////////////////////////////////////////////////// +// NodeVitastorKVListing +////////////////////////////////////////////////// + +// constructor(node_vitastor_kv, start_key?) +NAN_METHOD(NodeVitastorKVListing::Create) +{ + TRACE("NodeVitastorKVListing::Create"); + + v8::Local parent = info[0].As(); + NodeVitastorKV *kv = Nan::ObjectWrap::Unwrap(parent); + + std::string start_key; + // FIXME: Handle Buffer too + if (info.Length() > 1 && info[1]->IsString()) + { + start_key = std::string(*Nan::Utf8String(info[1].As())); + } + + NodeVitastorKVListing *list = new NodeVitastorKVListing(); + list->kv = kv; + { + std::unique_lock lock(kv->cli->mu); + list->handle = list->kv->dbw->list_start(start_key); + } + + list->Wrap(info.This()); + info.GetReturnValue().Set(info.This()); +} + +NodeVitastorKVListing::~NodeVitastorKVListing() +{ + if (handle) + { + std::unique_lock lock(kv->cli->mu); + kv->dbw->list_close(handle); + handle = NULL; + } +} + +// next(callback(err, value)) +NAN_METHOD(NodeVitastorKVListing::Next) +{ + TRACE("NodeVitastorKVListing::Next"); + + NodeVitastorKVListing* list = Nan::ObjectWrap::Unwrap(info.This()); + + v8::Local callback = info[0].As(); + auto req = new NodeVitastorRequest(callback); + if (!list->handle) + { + // Already closed + Nan::Callback nanCallback(Nan::New(req->callback)); + v8::Local args[1]; + args[0] = Nan::New(-EINVAL); + nanCallback.Call(1, args, req); + delete req; + return; + } + + list->kv->Ref(); + list->kv->dbw->list_next(list->handle, [list, req](int res, const std::string & key, const std::string & value) + { + Nan::HandleScope scope; + Nan::Callback nanCallback(Nan::New(req->callback)); + v8::Local args[3]; + args[0] = Nan::New(res); + args[1] = !res ? v8::Local(Nan::New(key).ToLocalChecked()) : v8::Local(Nan::Null()); + args[2] = !res ? v8::Local(Nan::New(value).ToLocalChecked()) : v8::Local(Nan::Null()); + nanCallback.Call(3, args, req); + delete req; + list->kv->Unref(); + }); +} + +// close() +NAN_METHOD(NodeVitastorKVListing::Close) +{ + TRACE("NodeVitastorKVListing::Close"); + + NodeVitastorKVListing* list = Nan::ObjectWrap::Unwrap(info.This()); + + if (list->handle) + { + std::unique_lock lock(list->kv->cli->mu); + list->kv->dbw->list_close(list->handle); + list->handle = NULL; + } +} diff --git a/node-binding/client.h b/node-binding/client.h new file mode 100644 index 00000000..b18ec620 --- /dev/null +++ b/node-binding/client.h @@ -0,0 +1,142 @@ +// Copyright (c) Vitaliy Filippov, 2019+ +// License: VNPL-1.1 (see README.md for details) + +#ifndef NODE_VITASTOR_CLIENT_H +#define NODE_VITASTOR_CLIENT_H + +#include + +#include +#include +#include + +class NodeVitastorRequest; + +class NodeVitastor: public Nan::ObjectWrap +{ +public: + // constructor({ ...config }) + static NAN_METHOD(Create); + // read(pool, inode, offset, len, callback(err, buffer, version)) + static NAN_METHOD(Read); + // write(pool, inode, offset, buffer, { version }?, callback(err)) + static NAN_METHOD(Write); + // sync(callback(err)) + static NAN_METHOD(Sync); + // read_bitmap(pool, inode, offset, len, with_parents, callback(err, bitmap_buffer)) + static NAN_METHOD(ReadBitmap); +// // destroy() +// static NAN_METHOD(Destroy); + + ~NodeVitastor(); + +private: + vitastor_c *c = NULL; + int eventfd = -1; + uv_poll_t poll_watcher; + // FIXME: Is it really needed? + std::mutex mu; + + NodeVitastor(); + + static void on_io_readable(uv_poll_t* handle, int status, int revents); + static void on_read_finish(void *opaque, long retval, uint64_t version); + static void on_write_finish(void *opaque, long retval); + static void on_read_bitmap_finish(void *opaque, long retval, uint8_t *bitmap); + + friend class NodeVitastorImage; + friend class NodeVitastorKV; + friend class NodeVitastorKVListing; +}; + +class NodeVitastorImage: public Nan::ObjectWrap +{ +public: + // constructor(node_vitastor, name) + static NAN_METHOD(Create); + // read(offset, len, callback(err, buffer, version)) + static NAN_METHOD(Read); + // write(offset, buffer, { version }?, callback(err)) + static NAN_METHOD(Write); + // sync(callback(err)) + static NAN_METHOD(Sync); + // read_bitmap(offset, len, with_parents, callback(err, bitmap_buffer)) + static NAN_METHOD(ReadBitmap); + // get_info(callback({ num, name, size, parent_id?, readonly?, meta?, mod_revision, block_size, bitmap_granularity, immediate_commit })) + static NAN_METHOD(GetInfo); + + ~NodeVitastorImage(); + +private: + NodeVitastor *cli = NULL; + std::string name; + void *watch = NULL; + std::vector on_init; + Nan::Persistent cliObj; + + NodeVitastorImage(); + + static void on_watch_start(void *opaque, long retval); + void exec_request(NodeVitastorRequest *req); + void exec_or_wait(NodeVitastorRequest *req); +}; + +class NodeVitastorKV: public Nan::ObjectWrap +{ +public: + // constructor(node_vitastor) + static NAN_METHOD(Create); + // open(inode_id, { ...config }, callback(err)) + static NAN_METHOD(Open); + // set_config({ ...config }) + static NAN_METHOD(SetConfig); + // close(callback()) + static NAN_METHOD(Close); + // get_size() + static NAN_METHOD(GetSize); + // get(key, callback(err, value)) + static NAN_METHOD(Get); + // get_cached(key, callback(err, value)) + static NAN_METHOD(GetCached); + // set(key, value, callback(err), cas_compare(old_value)) + static NAN_METHOD(Set); + // del(key, callback(err), cas_compare(old_value)) + static NAN_METHOD(Del); + // list(start_key?) + static NAN_METHOD(List); + + ~NodeVitastorKV(); + + static Nan::Persistent listing_class; + +private: + NodeVitastor *cli = NULL; + vitastorkv_dbw_t *dbw = NULL; + + NodeVitastorKV(); + + static void get_impl(const Nan::FunctionCallbackInfo & info, bool allow_cache); + + friend class NodeVitastorKVListing; +}; + +class NodeVitastorKVListing: public Nan::ObjectWrap +{ +public: + // constructor(node_vitastor_kv, start_key?) + static NAN_METHOD(Create); + // next(callback(err, value)) + static NAN_METHOD(Next); + // close() + static NAN_METHOD(Close); + + ~NodeVitastorKVListing(); + +private: + NodeVitastorKV *kv = NULL; + void *handle = NULL; + + NodeVitastorKVListing(); +}; + +#endif diff --git a/node-binding/package.json b/node-binding/package.json new file mode 100644 index 00000000..ec2fb106 --- /dev/null +++ b/node-binding/package.json @@ -0,0 +1,24 @@ +{ + "name": "vitastor", + "version": "1.7.0", + "description": "Low-level native bindings to Vitastor client library", + "main": "index.js", + "keywords": [ + "storage", + "sds", + "vitastor" + ], + "repository": { + "type": "git", + "url": "git://git.yourcmc.ru/vitalif/vitastor.git" + }, + "scripts": { + "build": "node-gyp rebuild" + }, + "author": "Vitaliy Filippov", + "license": "VNPL-2.0", + "dependencies": { + "bindings": "1.5.0", + "nan": "^2.19.0" + } +} diff --git a/src/client/vitastor_c.cpp b/src/client/vitastor_c.cpp index bdb46b26..c91e9476 100644 --- a/src/client/vitastor_c.cpp +++ b/src/client/vitastor_c.cpp @@ -384,6 +384,28 @@ int vitastor_c_inode_get_readonly(void *handle) return watch->cfg.readonly; } +uint64_t vitastor_c_inode_get_parent_id(void *handle) +{ + inode_watch_t *watch = (inode_watch_t*)handle; + return watch->cfg.parent_id; +} + +char* vitastor_c_inode_get_meta(void *handle) +{ + inode_watch_t *watch = (inode_watch_t*)handle; + if (watch->cfg.meta.is_null()) + { + return NULL; + } + return strdup(watch->cfg.meta.dump().c_str()); +} + +uint64_t vitastor_c_inode_get_mod_revision(void *handle) +{ + inode_watch_t *watch = (inode_watch_t*)handle; + return watch->cfg.mod_revision; +} + uint32_t vitastor_c_inode_get_immediate_commit(vitastor_c *client, uint64_t inode_num) { auto pool_it = client->cli->st_cli.pool_config.find(INODE_POOL(inode_num)); diff --git a/src/client/vitastor_c.h b/src/client/vitastor_c.h index 7c37f0e3..613a7bd8 100644 --- a/src/client/vitastor_c.h +++ b/src/client/vitastor_c.h @@ -69,6 +69,9 @@ void vitastor_c_watch_inode(vitastor_c *client, char *image, VitastorIOHandler c void vitastor_c_close_watch(vitastor_c *client, void *handle); uint64_t vitastor_c_inode_get_size(void *handle); uint64_t vitastor_c_inode_get_num(void *handle); +uint64_t vitastor_c_inode_get_parent_id(void *handle); +char* vitastor_c_inode_get_meta(void *handle); +uint64_t vitastor_c_inode_get_mod_revision(void *handle); uint32_t vitastor_c_inode_get_block_size(vitastor_c *client, uint64_t inode_num); uint32_t vitastor_c_inode_get_bitmap_granularity(vitastor_c *client, uint64_t inode_num); int vitastor_c_inode_get_readonly(void *handle); diff --git a/src/kv/kv_cli.cpp b/src/kv/kv_cli.cpp index fd3d7d0a..ab4d3c91 100644 --- a/src/kv/kv_cli.cpp +++ b/src/kv/kv_cli.cpp @@ -25,7 +25,7 @@ public: std::map cfg; std::vector cli_cmd; - kv_dbw_t *db = NULL; + vitastorkv_dbw_t *db = NULL; ring_loop_t *ringloop = NULL; epoll_manager_t *epmgr = NULL; cluster_client_t *cli = NULL; @@ -144,7 +144,7 @@ void kv_cli_t::run() ringloop = new ring_loop_t(512); epmgr = new epoll_manager_t(ringloop); cli = new cluster_client_t(ringloop, epmgr->tfd, cfg); - db = new kv_dbw_t(cli); + db = new vitastorkv_dbw_t(cli); // Load image metadata while (!cli->is_ready()) { @@ -289,7 +289,7 @@ void kv_cli_t::next_cmd() struct kv_cli_list_t { - kv_dbw_t *db = NULL; + vitastorkv_dbw_t *db = NULL; void *handle = NULL; int format = 0; int n = 0; diff --git a/src/kv/kv_db.cpp b/src/kv/kv_db.cpp index 7b0bb7db..b2cf8691 100644 --- a/src/kv/kv_db.cpp +++ b/src/kv/kv_db.cpp @@ -501,7 +501,7 @@ void kv_block_t::dump(int base_level) void kv_db_t::open(inode_t inode_id, json11::Json cfg, std::function cb) { - if (block_cache.size() > 0) + if (block_cache.size() > 0 || inode_id) { cb(-EINVAL); return; @@ -1958,38 +1958,38 @@ void kv_op_t::next_go_up() } } -kv_dbw_t::kv_dbw_t(cluster_client_t *cli) +vitastorkv_dbw_t::vitastorkv_dbw_t(cluster_client_t *cli) { db = new kv_db_t(); db->cli = cli; } -kv_dbw_t::~kv_dbw_t() +vitastorkv_dbw_t::~vitastorkv_dbw_t() { delete db; } -void kv_dbw_t::open(uint64_t inode_id, std::map cfg, std::function cb) +void vitastorkv_dbw_t::open(uint64_t inode_id, std::map cfg, std::function cb) { db->open(inode_id, cfg, cb); } -void kv_dbw_t::set_config(std::map cfg) +void vitastorkv_dbw_t::set_config(std::map cfg) { db->set_config(cfg); } -uint64_t kv_dbw_t::get_size() +uint64_t vitastorkv_dbw_t::get_size() { return db->next_free; } -void kv_dbw_t::close(std::function cb) +void vitastorkv_dbw_t::close(std::function cb) { db->close(cb); } -void kv_dbw_t::get(const std::string & key, std::function cb, bool cached) +void vitastorkv_dbw_t::get(const std::string & key, std::function cb, bool cached) { auto *op = new kv_op_t; op->db = db; @@ -2003,7 +2003,7 @@ void kv_dbw_t::get(const std::string & key, std::functionexec(); } -void kv_dbw_t::set(const std::string & key, const std::string & value, std::function cb, +void vitastorkv_dbw_t::set(const std::string & key, const std::string & value, std::function cb, std::function cas_compare) { auto *op = new kv_op_t; @@ -2023,7 +2023,7 @@ void kv_dbw_t::set(const std::string & key, const std::string & value, std::func op->exec(); } -void kv_dbw_t::del(const std::string & key, std::function cb, +void vitastorkv_dbw_t::del(const std::string & key, std::function cb, std::function cas_compare) { auto *op = new kv_op_t; @@ -2042,7 +2042,7 @@ void kv_dbw_t::del(const std::string & key, std::function cb, op->exec(); } -void* kv_dbw_t::list_start(const std::string & start) +void* vitastorkv_dbw_t::list_start(const std::string & start) { if (!db->inode_id || db->closing) return NULL; @@ -2055,7 +2055,7 @@ void* kv_dbw_t::list_start(const std::string & start) return op; } -void kv_dbw_t::list_next(void *handle, std::function cb) +void vitastorkv_dbw_t::list_next(void *handle, std::function cb) { kv_op_t *op = (kv_op_t*)handle; if (cb) @@ -2068,7 +2068,7 @@ void kv_dbw_t::list_next(void *handle, std::functionnext(); } -void kv_dbw_t::list_close(void *handle) +void vitastorkv_dbw_t::list_close(void *handle) { kv_op_t *op = (kv_op_t*)handle; delete op; diff --git a/src/kv/kv_stress.cpp b/src/kv/kv_stress.cpp index 4d5fa53d..c7dec789 100644 --- a/src/kv/kv_stress.cpp +++ b/src/kv/kv_stress.cpp @@ -73,7 +73,7 @@ public: timespec prev_stat_time, start_stat_time; // State - kv_dbw_t *db = NULL; + vitastorkv_dbw_t *db = NULL; ring_loop_t *ringloop = NULL; epoll_manager_t *epmgr = NULL; cluster_client_t *cli = NULL; @@ -272,7 +272,7 @@ void kv_test_t::run(json11::Json cfg) ringloop = new ring_loop_t(512); epmgr = new epoll_manager_t(ringloop); cli = new cluster_client_t(ringloop, epmgr->tfd, cfg); - db = new kv_dbw_t(cli); + db = new vitastorkv_dbw_t(cli); // Load image metadata while (!cli->is_ready()) { diff --git a/src/kv/vitastor_kv.h b/src/kv/vitastor_kv.h index 97b5f039..d7281a54 100644 --- a/src/kv/vitastor_kv.h +++ b/src/kv/vitastor_kv.h @@ -19,11 +19,11 @@ class cluster_client_t; struct kv_db_t; -struct kv_dbw_t +struct vitastorkv_dbw_t { // cli = vitastor_c_get_internal_client(client) - kv_dbw_t(cluster_client_t *cli); - ~kv_dbw_t(); + vitastorkv_dbw_t(cluster_client_t *cli); + ~vitastorkv_dbw_t(); void open(uint64_t inode_id, std::map cfg, std::function cb); void set_config(std::map cfg); diff --git a/src/nfs/nfs_kv.cpp b/src/nfs/nfs_kv.cpp index 5dbb28ba..2e64f444 100644 --- a/src/nfs/nfs_kv.cpp +++ b/src/nfs/nfs_kv.cpp @@ -303,7 +303,7 @@ void kv_fs_state_t::init(nfs_proxy_t *proxy, json11::Json cfg) // Open DB and wait int open_res = 0; bool open_done = false; - proxy->db = new kv_dbw_t(proxy->cli); + proxy->db = new vitastorkv_dbw_t(proxy->cli); std::map kv_cfg; for (auto & kv: cfg.object_items()) { diff --git a/src/nfs/nfs_proxy.h b/src/nfs/nfs_proxy.h index 10e58736..f6aa9f3b 100644 --- a/src/nfs/nfs_proxy.h +++ b/src/nfs/nfs_proxy.h @@ -51,7 +51,7 @@ public: epoll_manager_t *epmgr = NULL; cluster_client_t *cli = NULL; cli_tool_t *cmd = NULL; - kv_dbw_t *db = NULL; + vitastorkv_dbw_t *db = NULL; kv_fs_state_t *kvfs = NULL; block_fs_state_t *blockfs = NULL;