static int si_redistribute_index(si *index, sr *r, sdc *c, sinode *node) { svindex *vindex = si_nodeindex(node); ssiter i; ss_iterinit(sv_indexiter, &i); ss_iteropen(sv_indexiter, &i, r, vindex, SS_GTE, NULL, 0); while (ss_iterhas(sv_indexiter, &i)) { sv *v = ss_iterof(sv_indexiter, &i); int rc = ss_bufadd(&c->b, r->a, &v->v, sizeof(svv**)); if (ssunlikely(rc == -1)) return sr_oom_malfunction(r->e); ss_iternext(sv_indexiter, &i); } if (ssunlikely(ss_bufused(&c->b) == 0)) return 0; uint64_t now = ss_utime(); ss_iterinit(ss_bufiterref, &i); ss_iteropen(ss_bufiterref, &i, &c->b, sizeof(svv*)); while (ss_iterhas(ss_bufiterref, &i)) { svv *v = ss_iterof(ss_bufiterref, &i); si_redistribute_set(index, r, now, v); ss_iternext(ss_bufiterref, &i); } return 0; }
static inline int si_recovercomplete(sitrack *track, sr *r, si *index, ssbuf *buf) { /* prepare and build primary index */ ss_bufreset(buf); ssrbnode *p = ss_rbmin(&track->i); while (p) { sinode *n = sscast(p, sinode, node); int rc = ss_bufadd(buf, r->a, &n, sizeof(sinode*)); if (ssunlikely(rc == -1)) return sr_oom_malfunction(r->e); p = ss_rbnext(&track->i, p); } ssiter i; ss_iterinit(ss_bufiterref, &i); ss_iteropen(ss_bufiterref, &i, buf, sizeof(sinode*)); while (ss_iterhas(ss_bufiterref, &i)) { sinode *n = ss_iterof(ss_bufiterref, &i); if (n->recover & SI_RDB_REMOVE) { int rc = si_nodefree(n, r, 1); if (ssunlikely(rc == -1)) return -1; ss_iternext(ss_bufiterref, &i); continue; } n->recover = SI_RDB; si_insert(index, n); si_plannerupdate(&index->p, SI_COMPACT|SI_BRANCH|SI_TEMP, n); ss_iternext(ss_bufiterref, &i); } return 0; }
static int si_redistribute(si *index, sr *r, sdc *c, sinode *node, ssbuf *result) { (void)index; svindex *vindex = si_nodeindex(node); ssiter i; ss_iterinit(sv_indexiter, &i); ss_iteropen(sv_indexiter, &i, r, vindex, SS_GTE, NULL, 0); while (ss_iterhas(sv_indexiter, &i)) { sv *v = ss_iterof(sv_indexiter, &i); int rc = ss_bufadd(&c->b, r->a, &v->v, sizeof(svv**)); if (ssunlikely(rc == -1)) return sr_oom_malfunction(r->e); ss_iternext(sv_indexiter, &i); } if (ssunlikely(ss_bufused(&c->b) == 0)) return 0; ss_iterinit(ss_bufiterref, &i); ss_iteropen(ss_bufiterref, &i, &c->b, sizeof(svv*)); ssiter j; ss_iterinit(ss_bufiterref, &j); ss_iteropen(ss_bufiterref, &j, result, sizeof(sinode*)); sinode *prev = ss_iterof(ss_bufiterref, &j); ss_iternext(ss_bufiterref, &j); while (1) { sinode *p = ss_iterof(ss_bufiterref, &j); if (p == NULL) { assert(prev != NULL); while (ss_iterhas(ss_bufiterref, &i)) { svv *v = ss_iterof(ss_bufiterref, &i); v->next = NULL; sv_indexset(&prev->i0, r, v); ss_iternext(ss_bufiterref, &i); } break; } while (ss_iterhas(ss_bufiterref, &i)) { svv *v = ss_iterof(ss_bufiterref, &i); v->next = NULL; sdindexpage *page = sd_indexmin(&p->self.index); int rc = sr_compare(r->scheme, sv_vpointer(v), v->size, sd_indexpage_min(&p->self.index, page), page->sizemin); if (ssunlikely(rc >= 0)) break; sv_indexset(&prev->i0, r, v); ss_iternext(ss_bufiterref, &i); } if (ssunlikely(! ss_iterhas(ss_bufiterref, &i))) break; prev = p; ss_iternext(ss_bufiterref, &j); } assert(ss_iterof(ss_bufiterref, &i) == NULL); return 0; }
void *st_document_generate(stgenerator *g, sf fmt, stlist *l, void *db, uint32_t seed, uint32_t seed_value) { svv *v = st_svv_seed(g, seed, seed_value); if (ssunlikely(v == NULL)) return NULL; assert(l->svv == 1); int rc = ss_bufadd(&l->list, g->r->a, &v, sizeof(svv**)); if (ssunlikely(rc == -1)) { sv_vfree(g->r, v); return NULL; } void *o = sp_document(db); t( o != NULL ); switch (fmt) { case SF_KV: { int i = 0; while (i < g->r->scheme->count) { rc = sp_setstring(o, g->r->scheme->parts[i].name, sf_key(sv_vpointer(v), i), sf_keysize(sv_vpointer(v), i)); t( rc == 0 ); i++; } if ((g->value_start + g->value_end) > 0) { rc = sp_setstring(o, "value", sf_value(g->r->fmt, sv_vpointer(v), g->r->scheme->count), sf_valuesize(g->r->fmt, sv_vpointer(v), v->size, g->r->scheme->count)); t( rc == 0 ); } break; } case SF_DOCUMENT: { char *vpointer = sv_vpointer(v); int i = 0; while (i < g->r->scheme->count) { rc = sp_setstring(o, g->r->scheme->parts[i].name, sf_key(vpointer, i), sf_keysize(vpointer, i)); t( rc == 0 ); i++; } rc = sp_setstring(o, "value", vpointer, v->size); t( rc == 0 ); break; } } return o; }
static inline int si_split(si *index, sdc *c, ssbuf *result, sinode *parent, ssiter *i, uint64_t size_node, uint32_t size_stream, uint64_t vlsn) { sr *r = index->r; int count = 0; int rc; sdmergeconf mergeconf = { .size_stream = size_stream, .size_node = size_node, .size_page = index->scheme->node_page_size, .checksum = index->scheme->node_page_checksum, .compression = index->scheme->compression, .compression_key = index->scheme->compression_key, .offset = 0, .vlsn = vlsn, .save_delete = 0, .save_update = 0 }; sdmerge merge; sd_mergeinit(&merge, r, i, &c->build, &c->update, &mergeconf); while ((rc = sd_merge(&merge)) > 0) { sinode *n = si_nodenew(r); if (ssunlikely(n == NULL)) goto error; sdid id = { .parent = parent->self.id.id, .flags = 0, .id = sr_seq(index->r->seq, SR_NSNNEXT) }; rc = sd_mergecommit(&merge, &id); if (ssunlikely(rc == -1)) goto error; rc = si_nodecreate(n, r, index->scheme, &id, &merge.index, &c->build); if (ssunlikely(rc == -1)) goto error; rc = ss_bufadd(result, index->r->a, &n, sizeof(sinode*)); if (ssunlikely(rc == -1)) { sr_oom_malfunction(index->r->e); si_nodefree(n, r, 1); goto error; } sd_buildreset(&c->build); count++; } if (ssunlikely(rc == -1)) goto error; return 0; error: si_splitfree(result, r); sd_mergefree(&merge); return -1; } int si_compaction(si *index, sdc *c, uint64_t vlsn, sinode *node, ssiter *stream, uint32_t size_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->node_size, size_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->self.id.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, SI_COMPACT|SI_BRANCH, node); switch (count) { case 0: /* delete */ si_remove(index, node); si_redistribute_index(index, r, c, node); uint32_t used = sv_indexused(j); if (used) { ss_quota(r->quota, SS_QREMOVE, used); } break; case 1: /* self update */ n = *(sinode**)result->s; n->i0 = *j; n->used = sv_indexused(j); si_nodelock(n); si_replace(index, node, n); si_plannerupdate(&index->p, SI_COMPACT|SI_BRANCH, 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 = sv_indexused(&n->i0); si_nodelock(n); si_replace(index, node, n); si_plannerupdate(&index->p, SI_COMPACT|SI_BRANCH, 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 = sv_indexused(&n->i0); si_nodelock(n); si_insert(index, n); si_plannerupdate(&index->p, SI_COMPACT|SI_BRANCH, 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 = si_nodesync(n, r); if (ssunlikely(rc == -1)) return -1; } rc = si_nodeseal(n, r, index->scheme); if (ssunlikely(rc == -1)) 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 old node */ rc = si_nodefree(node, r, 1); if (ssunlikely(rc == -1)) return -1; 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_nodecomplete(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; }
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; }
static inline int si_rangebranch(siread *q, sinode *n, sibranch *b, svmerge *m) { sicachebranch *c = si_cachefollow(q->cache); assert(c->branch == b); /* iterate cache */ if (ss_iterhas(sd_read, &c->i)) { svmergesrc *s = sv_mergeadd(m, &c->i); si_readstat(q, 1, n, 1); s->ptr = c; return 1; } if (c->open) { return 1; } if (q->cache_only) { return 2; } c->open = 1; /* choose compression type */ int compression; ssfilterif *compression_if; if (! si_branchis_root(b)) { compression = q->index->scheme->compression_branch; compression_if = q->index->scheme->compression_branch_if; } else { compression = q->index->scheme->compression; compression_if = q->index->scheme->compression_if; } sdreadarg arg = { .index = &b->index, .buf = &c->buf_a, .buf_xf = &c->buf_b, .buf_read = &q->index->readbuf, .index_iter = &c->index_iter, .page_iter = &c->page_iter, .use_memory = n->in_memory, .use_mmap = q->index->scheme->mmap, .use_mmap_copy = 1, .use_compression = compression, .compression_if = compression_if, .has = 0, .has_vlsn = 0, .o = q->order, .memory = &b->copy, .mmap = &n->map, .file = &n->file, .r = q->r }; ss_iterinit(sd_read, &c->i); int rc = ss_iteropen(sd_read, &c->i, &arg, q->key, q->keysize); int reads = sd_read_stat(&c->i); si_readstat(q, 0, n, reads); if (ssunlikely(rc == -1)) return -1; if (ssunlikely(! ss_iterhas(sd_read, &c->i))) return 0; svmergesrc *s = sv_mergeadd(m, &c->i); s->ptr = c; return 1; } static inline int si_range(siread *q) { assert(q->has == 0); ssiter i; ss_iterinit(si_iter, &i); ss_iteropen(si_iter, &i, q->r, q->index, q->order, q->key, q->keysize); sinode *node; next_node: node = ss_iterof(si_iter, &i); if (ssunlikely(node == NULL)) return 0; si_txtrack(q->x, node); /* prepare sources */ svmerge *m = &q->merge; int count = node->branch_count + 2 + 1; int rc = sv_mergeprepare(m, q->r, count); if (ssunlikely(rc == -1)) { sr_errorreset(q->r->e); return -1; } /* external source (upsert) */ svmergesrc *s; sv upbuf_reserve; ssbuf upbuf; if (ssunlikely(q->upsert_v && q->upsert_v->v)) { ss_bufinit_reserve(&upbuf, &upbuf_reserve, sizeof(upbuf_reserve)); ss_bufadd(&upbuf, NULL, (void*)&q->upsert_v, sizeof(sv*)); s = sv_mergeadd(m, NULL); ss_iterinit(ss_bufiterref, &s->src); ss_iteropen(ss_bufiterref, &s->src, &upbuf, sizeof(sv*)); } /* in-memory indexes */ svindex *second; svindex *first = si_nodeindex_priority(node, &second); if (first->count) { s = sv_mergeadd(m, NULL); ss_iterinit(sv_indexiter, &s->src); ss_iteropen(sv_indexiter, &s->src, q->r, first, q->order, q->key, q->keysize); } if (ssunlikely(second && second->count)) { s = sv_mergeadd(m, NULL); ss_iterinit(sv_indexiter, &s->src); ss_iteropen(sv_indexiter, &s->src, q->r, second, q->order, q->key, q->keysize); } /* cache and branches */ rc = si_cachevalidate(q->cache, node); if (ssunlikely(rc == -1)) { sr_oom(q->r->e); return -1; } sibranch *b = node->branch; while (b) { rc = si_rangebranch(q, node, b, m); if (ssunlikely(rc == -1 || rc == 2)) return rc; b = b->next; } /* merge and filter data stream */ ssiter j; ss_iterinit(sv_mergeiter, &j); ss_iteropen(sv_mergeiter, &j, q->r, m, q->order); ssiter k; ss_iterinit(sv_readiter, &k); ss_iteropen(sv_readiter, &k, q->r, &j, &q->index->u, q->vlsn, 0); sv *v = ss_iterof(sv_readiter, &k); if (ssunlikely(v == NULL)) { sv_mergereset(&q->merge); ss_iternext(si_iter, &i); goto next_node; } rc = 1; /* convert upsert search to SS_EQ */ if (q->upsert_eq) { rc = sr_compare(q->r->scheme, sv_pointer(v), sv_size(v), q->key, q->keysize); rc = rc == 0; } /* do prefix search */ if (q->prefix && rc) { rc = sr_compareprefix(q->r->scheme, q->prefix, q->prefixsize, sv_pointer(v), sv_size(v)); } if (sslikely(rc == 1)) { if (ssunlikely(si_readdup(q, v) == -1)) return -1; } /* skip a possible duplicates from data sources */ ss_iternext(sv_readiter, &k); return rc; }
return sr_oom(r->e); sdschemeheader *h = (sdschemeheader*)c->buf.s; memset(h, 0, sizeof(sdschemeheader)); ss_bufadvance(&c->buf, sizeof(sdschemeheader)); return 0; } int sd_schemeadd(sdscheme *c, sr *r, uint8_t id, sstype type, void *value, uint32_t size) { sdschemeopt opt = { .type = type, .id = id, .size = size }; int rc = ss_bufadd(&c->buf, r->a, &opt, sizeof(opt)); if (ssunlikely(rc == -1)) goto error; rc = ss_bufadd(&c->buf, r->a, value, size); if (ssunlikely(rc == -1)) goto error; sdschemeheader *h = (sdschemeheader*)c->buf.s; h->count++; return 0; error: return sr_oom(r->e); } int sd_schemecommit(sdscheme *c, sr *r) { if (ssunlikely(ss_bufused(&c->buf) == 0))
static inline void si_qrangebranch(siquery *q, sinode *n, sibranch *b, svmerge *m) { sicachebranch *cb = si_cachefollow(q->cache); assert(cb->branch == b); /* iterate cache */ if (ss_iterhas(si_read, &cb->i)) { svmergesrc *s = sv_mergeadd(m, &cb->i); q->index->read_cache++; s->ptr = cb; return; } if (cb->open) { return; } cb->open = 1; sireadarg arg = { .scheme = q->index->scheme, .index = q->index, .n = n, .b = b, .buf = &cb->buf_a, .buf_xf = &cb->buf_b, .buf_read = &q->index->readbuf, .index_iter = &cb->index_iter, .page_iter = &cb->page_iter, .vlsn = q->vlsn, .has = 0, .mmap_copy = 1, .o = q->order, .r = q->r }; ss_iterinit(si_read, &cb->i); int rc = ss_iteropen(si_read, &cb->i, &arg, q->key, q->keysize); if (ssunlikely(rc == -1)) return; if (ssunlikely(! ss_iterhas(si_read, &cb->i))) return; svmergesrc *s = sv_mergeadd(m, &cb->i); s->ptr = cb; } static inline int si_qrange(siquery *q) { ssiter i; ss_iterinit(si_iter, &i); ss_iteropen(si_iter, &i, q->r, q->index, q->order, q->key, q->keysize); sinode *node; next_node: node = ss_iterof(si_iter, &i); if (ssunlikely(node == NULL)) return 0; /* prepare sources */ svmerge *m = &q->merge; int count = node->branch_count + 2 + 1; int rc = sv_mergeprepare(m, q->r, count); if (ssunlikely(rc == -1)) { sr_errorreset(q->r->e); return -1; } /* external source (update) */ svmergesrc *s; sv upbuf_reserve; ssbuf upbuf; if (ssunlikely(q->update_v && q->update_v->v)) { ss_bufinit_reserve(&upbuf, &upbuf_reserve, sizeof(upbuf_reserve)); ss_bufadd(&upbuf, NULL, (void*)&q->update_v, sizeof(sv*)); s = sv_mergeadd(m, NULL); ss_iterinit(ss_bufiterref, &s->src); ss_iteropen(ss_bufiterref, &s->src, &upbuf, sizeof(sv*)); } /* in-memory indexes */ svindex *second; svindex *first = si_nodeindex_priority(node, &second); if (first->count) { s = sv_mergeadd(m, NULL); ss_iterinit(sv_indexiter, &s->src); ss_iteropen(sv_indexiter, &s->src, q->r, first, q->order, q->key, q->keysize); } if (ssunlikely(second && second->count)) { s = sv_mergeadd(m, NULL); ss_iterinit(sv_indexiter, &s->src); ss_iteropen(sv_indexiter, &s->src, q->r, second, q->order, q->key, q->keysize); } /* cache and branches */ rc = si_cachevalidate(q->cache, node); if (ssunlikely(rc == -1)) { sr_oom(q->r->e); return -1; } sibranch *b = node->branch; while (b) { si_qrangebranch(q, node, b, m); b = b->next; } /* merge and filter data stream */ ssiter j; ss_iterinit(sv_mergeiter, &j); ss_iteropen(sv_mergeiter, &j, q->r, m, q->order); ssiter k; ss_iterinit(sv_readiter, &k); ss_iteropen(sv_readiter, &k, q->r, &j, &q->index->u, q->vlsn, 0); sv *v = ss_iterof(sv_readiter, &k); if (ssunlikely(v == NULL)) { sv_mergereset(&q->merge); ss_iternext(si_iter, &i); goto next_node; } rc = 1; /* convert update search to SS_EQ */ if (q->update_eq) { rc = sr_compare(q->r->scheme, sv_pointer(v), sv_size(v), q->key, q->keysize); rc = rc == 0; } /* do prefix search */ if (q->prefix && rc) { rc = sr_compareprefix(q->r->scheme, q->prefix, q->prefixsize, sv_pointer(v), sv_size(v)); } if (sslikely(rc == 1)) { if (ssunlikely(si_querydup(q, v) == -1)) return -1; } /* skip a possible duplicates from data sources */ ss_iternext(sv_readiter, &k); return rc; }