diff --git a/src/nfs_kv.cpp b/src/nfs_kv.cpp index a2900a65..eccade10 100644 --- a/src/nfs_kv.cpp +++ b/src/nfs_kv.cpp @@ -194,7 +194,7 @@ void nfs_kv_procs(nfs_client_t *self) void kv_fs_state_t::init(nfs_proxy_t *proxy, json11::Json cfg) { - // Check if we're using VitastorFS + this->proxy = proxy; fs_kv_inode = cfg["fs"].uint64_value(); if (fs_kv_inode) { @@ -226,6 +226,9 @@ void kv_fs_state_t::init(nfs_proxy_t *proxy, json11::Json cfg) id_alloc_batch_size = cfg["id_alloc_batch_size"].uint64_value(); if (!id_alloc_batch_size) id_alloc_batch_size = 200; + touch_interval = cfg["touch_interval"].uint64_value(); + if (touch_interval < 100) // ms + touch_interval = 100; auto & pool_cfg = proxy->cli->st_cli.pool_config.at(proxy->default_pool_id); pool_block_size = pool_cfg.pg_stripe_size; pool_alignment = pool_cfg.bitmap_granularity; @@ -260,4 +263,50 @@ void kv_fs_state_t::init(nfs_proxy_t *proxy, json11::Json cfg) } zero_block.resize(pool_block_size < 1048576 ? 1048576 : pool_block_size); scrap_block.resize(pool_block_size < 1048576 ? 1048576 : pool_block_size); + touch_timer_id = proxy->epmgr->tfd->set_timer(touch_interval, true, [this](int){ touch_inodes(); }); +} + +kv_fs_state_t::~kv_fs_state_t() +{ + if (proxy && touch_timer_id >= 0) + { + proxy->epmgr->tfd->clear_timer(touch_timer_id); + touch_timer_id = -1; + } +} + +static void touch_inode(nfs_proxy_t *proxy, inode_t ino, bool allow_cache) +{ + kv_read_inode(proxy, ino, [proxy, ino](int res, const std::string & value, json11::Json attrs) + { + if (!res) + { + auto ientry = attrs.object_items(); + ientry["mtime"] = nfstime_now_str(); + // FIXME: Use "update" query + bool *found = new bool; + *found = true; + proxy->db->set(kv_inode_key(ino), json11::Json(ientry).dump(), [proxy, ino, found](int res) + { + if (!*found) + res = -ENOENT; + delete found; + if (res == -EAGAIN) + touch_inode(proxy, ino, false); + }, [value, found](int res, const std::string & old_value) + { + *found = res == 0; + return res == 0 && old_value == value; + }); + } + }, allow_cache); +} + +void kv_fs_state_t::touch_inodes() +{ + std::set q = std::move(touch_queue); + for (auto ino: q) + { + touch_inode(proxy, ino, true); + } } diff --git a/src/nfs_kv.h b/src/nfs_kv.h index d01c5e03..33fcf95e 100644 --- a/src/nfs_kv.h +++ b/src/nfs_kv.h @@ -44,6 +44,9 @@ struct kv_inode_extend_t struct kv_fs_state_t { + nfs_proxy_t *proxy = NULL; + int touch_timer_id = -1; + uint64_t fs_kv_inode = 0; uint64_t fs_base_inode = 0; uint64_t fs_inode_count = 0; @@ -51,6 +54,7 @@ struct kv_fs_state_t uint64_t pool_block_size = 0; uint64_t pool_alignment = 0; uint64_t shared_inode_threshold = 0; + uint64_t touch_interval = 1000; std::map list_cookies; uint64_t fs_next_id = 1, fs_allocated_id = 0; @@ -58,10 +62,14 @@ struct kv_fs_state_t std::vector allocating_shared; uint64_t cur_shared_inode = 0, cur_shared_offset = 0; std::map extends; + std::set touch_queue; + std::vector zero_block; std::vector scrap_block; void init(nfs_proxy_t *proxy, json11::Json cfg); + void touch_inodes(); + ~kv_fs_state_t(); }; struct shared_file_header_t @@ -84,7 +92,7 @@ std::string kv_fh(uint64_t ino); uint64_t kv_fh_inode(const std::string & fh); bool kv_fh_valid(const std::string & fh); void allocate_new_id(nfs_client_t *self, std::function cb); -void kv_read_inode(nfs_client_t *self, uint64_t ino, +void kv_read_inode(nfs_proxy_t *proxy, uint64_t ino, std::function cb, bool allow_cache = false); uint64_t align_shared_size(nfs_client_t *self, uint64_t size); diff --git a/src/nfs_kv_create.cpp b/src/nfs_kv_create.cpp index 9047cf62..cde45e70 100644 --- a/src/nfs_kv_create.cpp +++ b/src/nfs_kv_create.cpp @@ -205,6 +205,10 @@ resume_5: } st->res = st->dup_ino ? 0 : -EEXIST; } + if (!st->res) + { + st->self->parent->kvfs->touch_queue.insert(st->dir_ino); + } auto cb = std::move(st->cb); cb(st->res); } diff --git a/src/nfs_kv_getattr.cpp b/src/nfs_kv_getattr.cpp index 2ebf22fa..7355594b 100644 --- a/src/nfs_kv_getattr.cpp +++ b/src/nfs_kv_getattr.cpp @@ -9,12 +9,12 @@ #include "nfs_kv.h" // Attributes are always stored in the inode -void kv_read_inode(nfs_client_t *self, uint64_t ino, +void kv_read_inode(nfs_proxy_t *proxy, uint64_t ino, std::function cb, bool allow_cache) { auto key = kv_inode_key(ino); - self->parent->db->get(key, [=](int res, const std::string & value) + proxy->db->get(key, [=](int res, const std::string & value) { if (ino == KV_ROOT_INODE && res == -ENOENT) { @@ -55,7 +55,7 @@ int kv_nfs3_getattr_proc(void *opaque, rpc_op_t *rop) rpc_queue_reply(rop); return 0; } - kv_read_inode(self, ino, [=](int res, const std::string & value, json11::Json attrs) + kv_read_inode(self->parent, ino, [=](int res, const std::string & value, json11::Json attrs) { if (self->parent->trace) fprintf(stderr, "[%d] GETATTR %ju -> %s\n", self->nfs_fd, ino, value.c_str()); diff --git a/src/nfs_kv_link.cpp b/src/nfs_kv_link.cpp index a19f4a88..1b7efec5 100644 --- a/src/nfs_kv_link.cpp +++ b/src/nfs_kv_link.cpp @@ -47,7 +47,7 @@ resume_0: // Check that the source inode exists and is not a directory st->wait = st->retrying ? 1 : 2; st->res2 = 0; - kv_read_inode(st->self, st->ino, [st](int res, const std::string & value, json11::Json attrs) + kv_read_inode(st->self->parent, st->ino, [st](int res, const std::string & value, json11::Json attrs) { st->res = res == 0 ? (attrs["type"].string_value() == "dir" ? -EISDIR : 0) : res; st->ientry_text = value; @@ -58,7 +58,7 @@ resume_0: if (!st->retrying) { // Check that the new directory exists - kv_read_inode(st->self, st->dir_ino, [st](int res, const std::string & value, json11::Json attrs) + kv_read_inode(st->self->parent, st->dir_ino, [st](int res, const std::string & value, json11::Json attrs) { st->res2 = res == 0 ? (attrs["type"].string_value() == "dir" ? 0 : -ENOTDIR) : res; if (!--st->wait) @@ -138,6 +138,10 @@ resume_4: st->dir_ino, st->filename.c_str(), strerror(-st->res2), st->res2); } } + if (!st->res) + { + st->self->parent->kvfs->touch_queue.insert(st->dir_ino); + } auto cb = std::move(st->cb); cb(st->res); } diff --git a/src/nfs_kv_lookup.cpp b/src/nfs_kv_lookup.cpp index 866a5aa6..fab097e8 100644 --- a/src/nfs_kv_lookup.cpp +++ b/src/nfs_kv_lookup.cpp @@ -41,7 +41,7 @@ int kv_nfs3_lookup_proc(void *opaque, rpc_op_t *rop) return; } uint64_t ino = direntry["ino"].uint64_value(); - kv_read_inode(self, ino, [=](int res, const std::string & value, json11::Json ientry) + kv_read_inode(self->parent, ino, [=](int res, const std::string & value, json11::Json ientry) { if (res < 0) { @@ -79,7 +79,7 @@ int kv_nfs3_readlink_proc(void *opaque, rpc_op_t *rop) rpc_queue_reply(rop); return 0; } - kv_read_inode(self, kv_fh_inode(args->symlink), [=](int res, const std::string & value, json11::Json attrs) + kv_read_inode(self->parent, kv_fh_inode(args->symlink), [=](int res, const std::string & value, json11::Json attrs) { if (res < 0) { diff --git a/src/nfs_kv_read.cpp b/src/nfs_kv_read.cpp index af969ad5..ccc9be9d 100644 --- a/src/nfs_kv_read.cpp +++ b/src/nfs_kv_read.cpp @@ -43,7 +43,7 @@ static void nfs_kv_continue_read(nfs_kv_read_state *st, int state) resume_0: if (st->offset + sizeof(shared_file_header_t) < st->self->parent->kvfs->shared_inode_threshold) { - kv_read_inode(st->self, st->ino, [st](int res, const std::string & value, json11::Json attrs) + kv_read_inode(st->self->parent, st->ino, [st](int res, const std::string & value, json11::Json attrs) { st->res = res; st->ientry = attrs; diff --git a/src/nfs_kv_readdir.cpp b/src/nfs_kv_readdir.cpp index 28e91428..28c57c22 100644 --- a/src/nfs_kv_readdir.cpp +++ b/src/nfs_kv_readdir.cpp @@ -50,7 +50,7 @@ static void kv_getattr_next(nfs_kv_readdir_state *st) { auto idx = st->getattr_cur++; st->getattr_running++; - kv_read_inode(st->self, st->entries[idx].fileid, [st, idx](int res, const std::string & value, json11::Json ientry) + kv_read_inode(st->self->parent, st->entries[idx].fileid, [st, idx](int res, const std::string & value, json11::Json ientry) { if (res == 0) { @@ -96,7 +96,7 @@ static void nfs_kv_continue_readdir(nfs_kv_readdir_state *st, int state) // Add . and .. if (st->cookie <= 1) { - kv_read_inode(st->self, st->dir_ino, [st](int res, const std::string & value, json11::Json ientry) + kv_read_inode(st->self->parent, st->dir_ino, [st](int res, const std::string & value, json11::Json ientry) { st->res = res; st->ientry_text = value; @@ -138,7 +138,7 @@ resume_1: st->parent_ino = st->ientry["parent_ino"].uint64_value(); if (st->parent_ino) { - kv_read_inode(st->self, st->ientry["parent_ino"].uint64_value(), [st](int res, const std::string & value, json11::Json ientry) + kv_read_inode(st->self->parent, st->ientry["parent_ino"].uint64_value(), [st](int res, const std::string & value, json11::Json ientry) { st->res = res; st->parent_ientry_text = value; diff --git a/src/nfs_kv_remove.cpp b/src/nfs_kv_remove.cpp index e99ec223..6ba5c5e9 100644 --- a/src/nfs_kv_remove.cpp +++ b/src/nfs_kv_remove.cpp @@ -207,6 +207,7 @@ resume_5: } else { + st->self->parent->kvfs->touch_queue.erase(st->ino); st->self->parent->db->del(kv_inode_key(st->ino), [st](int res) { st->res = res; @@ -249,6 +250,10 @@ resume_7: cb(st->res); return; } + if (!st->res) + { + st->self->parent->kvfs->touch_queue.insert(st->dir_ino); + } auto cb = std::move(st->cb); cb(0); } diff --git a/src/nfs_kv_rename.cpp b/src/nfs_kv_rename.cpp index d6d018a6..1430e718 100644 --- a/src/nfs_kv_rename.cpp +++ b/src/nfs_kv_rename.cpp @@ -157,7 +157,7 @@ resume_3: else { // Check that the new directory is actually a directory - kv_read_inode(st->self, st->new_dir_ino, [st](int res, const std::string & value, json11::Json attrs) + kv_read_inode(st->self->parent, st->new_dir_ino, [st](int res, const std::string & value, json11::Json attrs) { st->res = res == 0 ? (attrs["type"].string_value() == "dir" ? 0 : -ENOTDIR) : res; nfs_kv_continue_rename(st, 4); @@ -222,7 +222,7 @@ resume_7again: if (st->new_exists && st->new_direntry["type"].string_value() != "dir") { // (Maybe) delete old destination file data - kv_read_inode(st->self, st->new_direntry["ino"].uint64_value(), [st](int res, const std::string & value, json11::Json attrs) + kv_read_inode(st->self->parent, st->new_direntry["ino"].uint64_value(), [st](int res, const std::string & value, json11::Json attrs) { st->res = res; st->new_ientry_text = value; @@ -306,7 +306,7 @@ resume_9: // Change parent_ino in old ientry st->allow_cache = true; resume_10: - kv_read_inode(st->self, st->old_direntry["ino"].uint64_value(), [st](int res, const std::string & value, json11::Json ientry) + kv_read_inode(st->self->parent, st->old_direntry["ino"].uint64_value(), [st](int res, const std::string & value, json11::Json ientry) { st->res = res; st->old_ientry_text = value; @@ -348,6 +348,11 @@ resume_12: return; } } + if (!st->res) + { + st->self->parent->kvfs->touch_queue.insert(st->old_dir_ino); + st->self->parent->kvfs->touch_queue.insert(st->new_dir_ino); + } auto cb = std::move(st->cb); cb(st->res); } diff --git a/src/nfs_kv_setattr.cpp b/src/nfs_kv_setattr.cpp index 5dbf1537..8dc88260 100644 --- a/src/nfs_kv_setattr.cpp +++ b/src/nfs_kv_setattr.cpp @@ -35,8 +35,9 @@ static void nfs_kv_continue_setattr(nfs_kv_setattr_state *st, int state) fprintf(stderr, "BUG: invalid state in nfs_kv_continue_setattr()"); abort(); } + st->self->parent->kvfs->touch_queue.erase(st->ino); resume_0: - kv_read_inode(st->self, st->ino, [st](int res, const std::string & value, json11::Json attrs) + kv_read_inode(st->self->parent, st->ino, [st](int res, const std::string & value, json11::Json attrs) { st->res = res; st->ientry_text = value; diff --git a/src/nfs_kv_write.cpp b/src/nfs_kv_write.cpp index 7a9cbdbe..0d9f71f0 100644 --- a/src/nfs_kv_write.cpp +++ b/src/nfs_kv_write.cpp @@ -745,7 +745,7 @@ resume_0: cb(0); return; } - kv_read_inode(st->self, st->ino, [st](int res, const std::string & value, json11::Json attrs) + kv_read_inode(st->self->parent, st->ino, [st](int res, const std::string & value, json11::Json attrs) { st->res = res; st->ientry_text = value; @@ -961,6 +961,10 @@ resume_16: st->self->parent->kvfs->extends.erase(st->ino); } } + else + { + st->self->parent->kvfs->touch_queue.insert(st->ino); + } if (st->res == -EAGAIN) { // Restart