static inline int si_nodeclose(sinode *n, sr *r, int gc) { int rcret = 0; int rc = ss_vfsmunmap(r->vfs, &n->map); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "db file '%s' munmap error: %s", ss_pathof(&n->file.path), strerror(errno)); rcret = -1; } rc = ss_fileclose(&n->file); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "db file '%s' close error: %s", ss_pathof(&n->file.path), strerror(errno)); rcret = -1; } if (gc) { si_nodegc_index(r, &n->i0); si_nodegc_index(r, &n->i1); } else { sv_indexfree(&n->i0, r); sv_indexfree(&n->i1, r); } return rcret; }
int si_nodeseal(sinode *n, sr *r, sischeme *scheme) { int rc; if (scheme->sync) { rc = ss_filesync(&n->file); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "db file '%s' sync error: %s", ss_pathof(&n->file.path), strerror(errno)); return -1; } } sspath path; ss_pathcompound(&path, scheme->path, n->self.id.parent, n->self.id.id, ".db.seal"); rc = ss_filerename(&n->file, path.path); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "db file '%s' rename error: %s", ss_pathof(&n->file.path), strerror(errno)); return -1; } return 0; }
int si_nodeopen(sinode *n, sr *r, sischeme *scheme, sspath *path, sdsnapshotnode *sn) { int rc = ss_fileopen(&n->file, path->path); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "db file '%s' open error: %s", ss_pathof(&n->file.path), strerror(errno)); return -1; } rc = ss_fileseek(&n->file, n->file.size); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "db file '%s' seek error: %s", ss_pathof(&n->file.path), strerror(errno)); goto error; } int in_memory = 0; if (scheme->storage == SI_SIN_MEMORY) in_memory = 1; rc = si_noderecover(n, r, sn, in_memory); if (ssunlikely(rc == -1)) goto error; if (scheme->mmap) { rc = si_nodemap(n, r); if (ssunlikely(rc == -1)) goto error; } return 0; error: si_nodeclose(n, r, 0); return -1; }
int si_nodeopen(sinode *n, sr *r, sischeme *scheme, sspath *path) { int rc = ss_fileopen(&n->file, path->path); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "db file '%s' open error: %s", ss_pathof(&n->file.path), strerror(errno)); return -1; } rc = ss_fileseek(&n->file, n->file.size); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "db file '%s' seek error: %s", ss_pathof(&n->file.path), strerror(errno)); goto error; } rc = si_noderecover(n, r, scheme->in_memory); if (ssunlikely(rc == -1)) goto error; if (scheme->mmap) { rc = si_nodemap(n, r); if (ssunlikely(rc == -1)) goto error; } return 0; error: si_nodeclose(n, r); return -1; }
int si_nodemap(sinode *n, sr *r) { int rc = ss_vfsmmap(r->vfs, &n->map, n->file.fd, n->file.size, 1); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "db file '%s' mmap error: %s", ss_pathof(&n->file.path), strerror(errno)); return -1; } return 0; }
int si_nodecomplete(sinode *n, sr *r, sischeme *scheme) { sspath path; ss_path(&path, scheme->path, n->self.id.id, ".db"); int rc = ss_filerename(&n->file, path.path); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "db file '%s' rename error: %s", ss_pathof(&n->file.path), strerror(errno)); } return rc; }
int si_nodefree(sinode *n, sr *r, int gc) { int rcret = 0; int rc; if (gc && ss_pathis_set(&n->file.path)) { ss_fileadvise(&n->file, 0, 0, n->file.size); rc = ss_vfsunlink(r->vfs, ss_pathof(&n->file.path)); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "db file '%s' unlink error: %s", ss_pathof(&n->file.path), strerror(errno)); rcret = -1; } } si_nodefree_branches(n, r); rc = si_nodeclose(n, r, gc); if (ssunlikely(rc == -1)) rcret = -1; ss_free(r->a, n); return rcret; }
static inline int si_nodeclose(sinode *n, sr *r) { int rcret = 0; int rc = ss_munmap(&n->map); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "db file '%s' munmap error: %s", ss_pathof(&n->file.path), strerror(errno)); rcret = -1; } rc = ss_fileclose(&n->file); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "db file '%s' close error: %s", ss_pathof(&n->file.path), strerror(errno)); rcret = -1; } sv_indexfree(&n->i0, r); sv_indexfree(&n->i1, r); return rcret; }
int si_noderead(sinode *n, sr *r, ssbuf *dest) { int rc = ss_bufensure(dest, r->a, n->file.size); if (ssunlikely(rc == -1)) return sr_oom_malfunction(r->e); rc = ss_filepread(&n->file, 0, dest->s, n->file.size); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "db file '%s' read error: %s", ss_pathof(&n->file.path), strerror(errno)); return -1; } ss_bufadvance(dest, n->file.size); return 0; }
static inline int si_split(si *index, sdc *c, ssbuf *result, sinode *parent, ssiter *i, uint64_t size_node, uint64_t size_stream, uint32_t stream, uint64_t vlsn) { sr *r = &index->r; uint32_t timestamp = ss_timestamp(); int rc; sdmergeconf mergeconf = { .stream = stream, .size_stream = size_stream, .size_node = size_node, .size_page = index->scheme.compaction.node_page_size, .checksum = index->scheme.compaction.node_page_checksum, .expire = index->scheme.expire, .timestamp = timestamp, .compression = index->scheme.compression, .compression_if = index->scheme.compression_if, .direct_io = index->scheme.direct_io, .direct_io_page_size = index->scheme.direct_io_page_size, .vlsn = vlsn }; sinode *n = NULL; sdmerge merge; rc = sd_mergeinit(&merge, r, i, &c->build, &c->build_index, &c->upsert, &mergeconf); if (ssunlikely(rc == -1)) return -1; while ((rc = sd_merge(&merge)) > 0) { /* create new node */ uint64_t id = sr_seq(index->r.seq, SR_NSNNEXT); n = si_nodenew(r, id, parent->id); if (ssunlikely(n == NULL)) goto error; rc = si_nodecreate(n, r, &index->scheme); if (ssunlikely(rc == -1)) goto error; /* write pages */ uint64_t offset; offset = sd_iosize(&c->io, &n->file); while ((rc = sd_mergepage(&merge, offset)) == 1) { rc = sd_writepage(r, &n->file, &c->io, merge.build); if (ssunlikely(rc == -1)) goto error; offset = sd_iosize(&c->io, &n->file); } if (ssunlikely(rc == -1)) goto error; offset = sd_iosize(&c->io, &n->file); rc = sd_mergeend(&merge, offset); if (ssunlikely(rc == -1)) goto error; /* write index */ rc = sd_writeindex(r, &n->file, &c->io, &merge.index); if (ssunlikely(rc == -1)) goto error; /* mmap mode */ if (index->scheme.mmap) { rc = si_nodemap(n, r); if (ssunlikely(rc == -1)) goto error; } /* add node to the list */ rc = ss_bufadd(result, index->r.a, &n, sizeof(sinode*)); if (ssunlikely(rc == -1)) { sr_oom_malfunction(index->r.e); goto error; } n->index = merge.index; } if (ssunlikely(rc == -1)) goto error; return 0; error: if (n) si_nodefree(n, r, 0); sd_mergefree(&merge); si_splitfree(result, r); return -1; } static int si_merge(si *index, sdc *c, sinode *node, uint64_t vlsn, ssiter *stream, uint64_t size_stream, uint32_t n_stream) { sr *r = &index->r; ssbuf *result = &c->a; ssiter i; /* begin compaction. * * Split merge stream into a number of * a new nodes. */ int rc; rc = si_split(index, c, result, node, stream, index->scheme.compaction.node_size, size_stream, n_stream, vlsn); if (ssunlikely(rc == -1)) return -1; SS_INJECTION(r->i, SS_INJECTION_SI_COMPACTION_0, si_splitfree(result, r); sr_malfunction(r->e, "%s", "error injection"); return -1); /* mask removal of a single node as a * single node update */ int count = ss_bufused(result) / sizeof(sinode*); int count_index; si_lock(index); count_index = index->n; si_unlock(index); sinode *n; if (ssunlikely(count == 0 && count_index == 1)) { n = si_bootstrap(index, node->id); if (ssunlikely(n == NULL)) return -1; rc = ss_bufadd(result, r->a, &n, sizeof(sinode*)); if (ssunlikely(rc == -1)) { sr_oom_malfunction(r->e); si_nodefree(n, r, 1); return -1; } count++; } /* commit compaction changes */ si_lock(index); svindex *j = si_nodeindex(node); si_plannerremove(&index->p, node); si_nodesplit(node); switch (count) { case 0: /* delete */ si_remove(index, node); si_redistribute_index(index, r, c, node); break; case 1: /* self update */ n = *(sinode**)result->s; n->i0 = *j; n->used = j->used; si_nodelock(n); si_replace(index, node, n); si_plannerupdate(&index->p, n); break; default: /* split */ rc = si_redistribute(index, r, c, node, result); if (ssunlikely(rc == -1)) { si_unlock(index); si_splitfree(result, r); return -1; } ss_iterinit(ss_bufiterref, &i); ss_iteropen(ss_bufiterref, &i, result, sizeof(sinode*)); n = ss_iterof(ss_bufiterref, &i); n->used = n->i0.used; si_nodelock(n); si_replace(index, node, n); si_plannerupdate(&index->p, n); for (ss_iternext(ss_bufiterref, &i); ss_iterhas(ss_bufiterref, &i); ss_iternext(ss_bufiterref, &i)) { n = ss_iterof(ss_bufiterref, &i); n->used = n->i0.used; si_nodelock(n); si_insert(index, n); si_plannerupdate(&index->p, n); } break; } sv_indexinit(j); si_unlock(index); /* compaction completion */ /* seal nodes */ ss_iterinit(ss_bufiterref, &i); ss_iteropen(ss_bufiterref, &i, result, sizeof(sinode*)); while (ss_iterhas(ss_bufiterref, &i)) { n = ss_iterof(ss_bufiterref, &i); if (index->scheme.sync) { rc = ss_filesync(&n->file); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "db file '%s' sync error: %s", ss_pathof(&n->file.path), strerror(errno)); return -1; } } rc = si_noderename_seal(n, r, &index->scheme); if (ssunlikely(rc == -1)) { si_nodefree(node, r, 0); return -1; } SS_INJECTION(r->i, SS_INJECTION_SI_COMPACTION_3, si_nodefree(node, r, 0); sr_malfunction(r->e, "%s", "error injection"); return -1); ss_iternext(ss_bufiterref, &i); } SS_INJECTION(r->i, SS_INJECTION_SI_COMPACTION_1, si_nodefree(node, r, 0); sr_malfunction(r->e, "%s", "error injection"); return -1); /* gc node */ uint16_t refs = si_noderefof(node); if (sslikely(refs == 0)) { rc = si_nodefree(node, r, 1); if (ssunlikely(rc == -1)) return -1; } else { /* node concurrently being read, schedule for * delayed removal */ si_nodegc(node, r, &index->scheme); si_lock(index); ss_listappend(&index->gc, &node->gc); index->gc_count++; si_unlock(index); } SS_INJECTION(r->i, SS_INJECTION_SI_COMPACTION_2, sr_malfunction(r->e, "%s", "error injection"); return -1); /* complete new nodes */ ss_iterinit(ss_bufiterref, &i); ss_iteropen(ss_bufiterref, &i, result, sizeof(sinode*)); while (ss_iterhas(ss_bufiterref, &i)) { n = ss_iterof(ss_bufiterref, &i); rc = si_noderename_complete(n, r, &index->scheme); if (ssunlikely(rc == -1)) return -1; SS_INJECTION(r->i, SS_INJECTION_SI_COMPACTION_4, sr_malfunction(r->e, "%s", "error injection"); return -1); ss_iternext(ss_bufiterref, &i); } /* unlock */ si_lock(index); ss_iterinit(ss_bufiterref, &i); ss_iteropen(ss_bufiterref, &i, result, sizeof(sinode*)); while (ss_iterhas(ss_bufiterref, &i)) { n = ss_iterof(ss_bufiterref, &i); si_nodeunlock(n); ss_iternext(ss_bufiterref, &i); } si_unlock(index); return 0; }
int si_snapshot(si *index, siplan *plan) { sr *r = index->r; ssfile file; ss_fileinit(&file, r->vfs); /* prepare to take snapshot */ sdsnapshot snapshot; sd_snapshot_init(&snapshot); int rc = ss_bufensure(&snapshot.buf, r->a, 1 * 1024 * 1024); if (ssunlikely(rc == -1)) goto error_oom; rc = sd_snapshot_begin(&snapshot, r); if (ssunlikely(rc == -1)) goto error_oom; /* save node index image */ si_lock(index); ssrbnode *p = NULL; while ((p = ss_rbnext(&index->i, p))) { sinode *n = sscast(p, sinode, node); rc = sd_snapshot_add(&snapshot, r, n->self.id.id, n->file.size, n->branch_count, n->temperature_reads); if (ssunlikely(rc == -1)) { si_unlock(index); goto error_oom; } sibranch *b = &n->self; while (b) { rc = sd_snapshot_addbranch(&snapshot, r, b->index.h); if (ssunlikely(rc == -1)) { si_unlock(index); goto error_oom; } b = b->link; } } sd_snapshot_commit(&snapshot, r, index->lru_v, index->lru_steps, index->lru_intr_lsn, index->lru_intr_sum, index->read_disk, index->read_cache); si_unlock(index); /* create snapshot.inprogress */ char path[PATH_MAX]; snprintf(path, sizeof(path), "%s/index.incomplete", index->scheme->path); rc = ss_filenew(&file, path); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "index file '%s' create error: %s", path, strerror(errno)); goto error; } rc = ss_filewrite(&file, snapshot.buf.s, ss_bufused(&snapshot.buf)); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "index file '%s' write error: %s", path, strerror(errno)); goto error; } SS_INJECTION(r->i, SS_INJECTION_SI_SNAPSHOT_0, ss_fileclose(&file); sd_snapshot_free(&snapshot, r); sr_malfunction(r->e, "%s", "error injection"); return -1); /* sync snapshot file */ if (index->scheme->sync) { rc = ss_filesync(&file); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "index file '%s' sync error: %s", path, strerror(errno)); goto error; } } /* remove old snapshot file (if exists) */ snprintf(path, sizeof(path), "%s/index", index->scheme->path); ss_vfsunlink(r->vfs, path); SS_INJECTION(r->i, SS_INJECTION_SI_SNAPSHOT_1, ss_fileclose(&file); sd_snapshot_free(&snapshot, r); sr_malfunction(r->e, "%s", "error injection"); return -1); /* rename snapshot.incomplete to snapshot */ rc = ss_filerename(&file, path); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "index file '%s' rename error: %s", ss_pathof(&file.path), strerror(errno)); goto error; } SS_INJECTION(r->i, SS_INJECTION_SI_SNAPSHOT_2, ss_fileclose(&file); sd_snapshot_free(&snapshot, r); sr_malfunction(r->e, "%s", "error injection"); return -1); /* close snapshot file */ rc = ss_fileclose(&file); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "index file '%s' close error: %s", path, strerror(errno)); goto error; } sd_snapshot_free(&snapshot, r); /* finish index snapshot */ si_lock(index); index->snapshot = plan->a; index->snapshot_run = 0; si_unlock(index); return 0; error_oom: sr_oom(r->e); error: ss_fileclose(&file); sd_snapshot_free(&snapshot, r); return -1; }
static inline sibranch* si_branchcreate(si *index, sdc *c, sinode *parent, svindex *vindex, uint64_t vlsn) { sr *r = index->r; sibranch *branch = NULL; /* in-memory mode blob */ int rc; ssblob copy, *blob = NULL; if (parent->in_memory) { ss_blobinit(©, r->vfs); rc = ss_blobensure(©, 10ULL * 1024 * 1024); if (ssunlikely(rc == -1)) { sr_oom_malfunction(r->e); return NULL; } blob = © } svmerge vmerge; sv_mergeinit(&vmerge); rc = sv_mergeprepare(&vmerge, r, 1); if (ssunlikely(rc == -1)) return NULL; svmergesrc *s = sv_mergeadd(&vmerge, NULL); ss_iterinit(sv_indexiter, &s->src); ss_iteropen(sv_indexiter, &s->src, r, vindex, SS_GTE, NULL, 0); ssiter i; ss_iterinit(sv_mergeiter, &i); ss_iteropen(sv_mergeiter, &i, r, &vmerge, SS_GTE); /* merge iter is not used */ sdmergeconf mergeconf = { .size_stream = UINT32_MAX, .size_node = UINT64_MAX, .size_page = index->scheme->node_page_size, .checksum = index->scheme->node_page_checksum, .compression_key = index->scheme->compression_key, .compression = index->scheme->compression_branch, .compression_if = index->scheme->compression_branch_if, .vlsn = vlsn, .vlsn_lru = 0, .save_delete = 1, .save_upsert = 1 }; sdmerge merge; sd_mergeinit(&merge, r, &i, &c->build, &c->upsert, &mergeconf); while ((rc = sd_merge(&merge)) > 0) { assert(branch == NULL); /* write open seal */ uint64_t seal = parent->file.size; rc = sd_writeseal(r, &parent->file, blob); if (ssunlikely(rc == -1)) goto e0; /* write pages */ uint64_t offset = parent->file.size; while ((rc = sd_mergepage(&merge, offset)) == 1) { rc = sd_writepage(r, &parent->file, blob, merge.build); if (ssunlikely(rc == -1)) goto e0; offset = parent->file.size; } if (ssunlikely(rc == -1)) goto e0; sdid id = { .parent = parent->self.id.id, .flags = SD_IDBRANCH, .id = sr_seq(r->seq, SR_NSNNEXT) }; rc = sd_mergecommit(&merge, &id, parent->file.size); if (ssunlikely(rc == -1)) goto e0; /* write index */ rc = sd_writeindex(r, &parent->file, blob, &merge.index); if (ssunlikely(rc == -1)) goto e0; if (index->scheme->sync) { rc = ss_filesync(&parent->file); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "file '%s' sync error: %s", ss_pathof(&parent->file.path), strerror(errno)); goto e0; } } SS_INJECTION(r->i, SS_INJECTION_SI_BRANCH_0, sd_mergefree(&merge); sr_malfunction(r->e, "%s", "error injection"); return NULL); /* seal the branch */ rc = sd_seal(r, &parent->file, blob, &merge.index, seal); if (ssunlikely(rc == -1)) goto e0; if (index->scheme->sync == 2) { rc = ss_filesync(&parent->file); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "file '%s' sync error: %s", ss_pathof(&parent->file.path), strerror(errno)); goto e0; } } /* create new branch object */ branch = si_branchnew(r); if (ssunlikely(branch == NULL)) goto e0; si_branchset(branch, &merge.index); } sv_mergefree(&vmerge, r->a); if (ssunlikely(rc == -1)) { sr_oom_malfunction(r->e); goto e0; } assert(branch != NULL); /* in-memory mode support */ if (blob) { rc = ss_blobfit(blob); if (ssunlikely(rc == -1)) { ss_blobfree(blob); goto e1; } branch->copy = copy; } /* mmap support */ if (index->scheme->mmap) { ss_mmapinit(&parent->map_swap); rc = ss_vfsmmap(r->vfs, &parent->map_swap, parent->file.fd, parent->file.size, 1); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "db file '%s' mmap error: %s", ss_pathof(&parent->file.path), strerror(errno)); goto e1; } } return branch; e0: sd_mergefree(&merge); if (blob) ss_blobfree(blob); return NULL; e1: si_branchfree(branch, r); return NULL; } int si_branch(si *index, sdc *c, siplan *plan, uint64_t vlsn) { sr *r = index->r; sinode *n = plan->node; assert(n->flags & SI_LOCK); si_lock(index); if (ssunlikely(n->used == 0)) { si_nodeunlock(n); si_unlock(index); return 0; } svindex *i; i = si_noderotate(n); si_unlock(index); sibranch *branch = si_branchcreate(index, c, n, i, vlsn); if (ssunlikely(branch == NULL)) return -1; /* commit */ si_lock(index); branch->next = n->branch; n->branch->link = branch; n->branch = branch; n->branch_count++; uint32_t used = sv_indexused(i); n->used -= used; ss_quota(r->quota, SS_QREMOVE, used); index->size += sd_indexsize(branch->index.h) + sd_indextotal(&branch->index); svindex swap = *i; si_nodeunrotate(n); si_nodeunlock(n); si_plannerupdate(&index->p, SI_BRANCH|SI_COMPACT, n); ssmmap swap_map = n->map; n->map = n->map_swap; memset(&n->map_swap, 0, sizeof(n->map_swap)); si_unlock(index); /* gc */ if (index->scheme->mmap) { int rc = ss_vfsmunmap(r->vfs, &swap_map); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "db file '%s' munmap error: %s", ss_pathof(&n->file.path), strerror(errno)); return -1; } } si_nodegc_index(r, &swap); return 1; } int si_compact(si *index, sdc *c, siplan *plan, uint64_t vlsn, uint64_t vlsn_lru, ssiter *vindex, uint64_t vindex_used) { sr *r = index->r; sinode *node = plan->node; assert(node->flags & SI_LOCK); /* prepare for compaction */ int rc; rc = sd_censure(c, r, node->branch_count); if (ssunlikely(rc == -1)) return sr_oom_malfunction(r->e); svmerge merge; sv_mergeinit(&merge); rc = sv_mergeprepare(&merge, r, node->branch_count + 1); if (ssunlikely(rc == -1)) return -1; /* read node file into memory */ int use_mmap = index->scheme->mmap; ssmmap *map = &node->map; ssmmap preload; if (index->scheme->node_compact_load) { rc = si_noderead(node, r, &c->c); if (ssunlikely(rc == -1)) return -1; preload.p = c->c.s; preload.size = ss_bufused(&c->c); map = &preload; use_mmap = 1; } /* include vindex into merge process */ svmergesrc *s; uint64_t size_stream = 0; if (vindex) { s = sv_mergeadd(&merge, vindex); size_stream = vindex_used; } sdcbuf *cbuf = c->head; sibranch *b = node->branch; while (b) { s = sv_mergeadd(&merge, NULL); /* choose compression type */ int compression; ssfilterif *compression_if; if (! si_branchis_root(b)) { compression = index->scheme->compression_branch; compression_if = index->scheme->compression_branch_if; } else { compression = index->scheme->compression; compression_if = index->scheme->compression_if; } sdreadarg arg = { .index = &b->index, .buf = &cbuf->a, .buf_xf = &cbuf->b, .buf_read = &c->d, .index_iter = &cbuf->index_iter, .page_iter = &cbuf->page_iter, .use_memory = node->in_memory, .use_mmap = use_mmap, .use_mmap_copy = 0, .use_compression = compression, .compression_if = compression_if, .has = 0, .has_vlsn = 0, .o = SS_GTE, .memory = &b->copy, .mmap = map, .file = &node->file, .r = r }; ss_iterinit(sd_read, &s->src); int rc = ss_iteropen(sd_read, &s->src, &arg, NULL, 0); if (ssunlikely(rc == -1)) return sr_oom_malfunction(r->e); size_stream += sd_indextotal(&b->index); cbuf = cbuf->next; b = b->next; } ssiter i; ss_iterinit(sv_mergeiter, &i); ss_iteropen(sv_mergeiter, &i, r, &merge, SS_GTE); rc = si_merge(index, c, node, vlsn, vlsn_lru, &i, size_stream); sv_mergefree(&merge, r->a); return rc; } int si_compact_index(si *index, sdc *c, siplan *plan, uint64_t vlsn, uint64_t vlsn_lru) { sinode *node = plan->node; si_lock(index); if (ssunlikely(node->used == 0)) { si_nodeunlock(node); si_unlock(index); return 0; } svindex *vindex; vindex = si_noderotate(node); si_unlock(index); uint64_t size_stream = sv_indexused(vindex); ssiter i; ss_iterinit(sv_indexiter, &i); ss_iteropen(sv_indexiter, &i, index->r, vindex, SS_GTE, NULL, 0); return si_compact(index, c, plan, vlsn, vlsn_lru, &i, size_stream); }