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; }
int se_document_create(sedocument *o, uint8_t flags) { sedb *db = (sedb*)o->o.parent; se *e = se_of(&db->o); assert(o->created == 0); assert(o->v == NULL); /* create document from raw data */ if (o->raw) { o->v = sv_vbuildraw(db->r, o->raw); if (ssunlikely(o->v == NULL)) return sr_oom(&e->error); o->created = 1; return 0; } /* ensure all keys are set */ if (ssunlikely(o->fields_count_keys != db->scheme->scheme.keys_count)) return sr_error(&e->error, "%s", "incomplete key"); /* set auto fields */ uint32_t timestamp = UINT32_MAX; if (db->scheme->scheme.has_timestamp) { timestamp = ss_timestamp(); sf_autoset(&db->scheme->scheme, o->fields, ×tamp); } o->v = sv_vbuild(db->r, o->fields); if (ssunlikely(o->v == NULL)) return sr_oom(&e->error); sf_flagsset(db->r->scheme, sv_vpointer(o->v), flags); o->created = 1; return 0; }
void st_document_eq(stgenerator *g, sf fmt, void *o, uint32_t seed, uint32_t seed_value) { svv *v = st_svv_seed(g, seed, seed_value); if (ssunlikely(v == NULL)) { t(0); return; } switch (fmt) { case SF_KV: { int i = 0; int size = 0; while (i < g->r->scheme->count) { void *ptr = sp_getstring(o, g->r->scheme->parts[i].name, &size); t( ptr != NULL ); t( size == sf_keysize(sv_vpointer(v), i) ); t( memcmp(ptr, sf_key(sv_vpointer(v), i), size) == 0 ); i++; } void *ptr = sp_getstring(o, "value", &size); if ((g->value_start + g->value_end) > 0) { t( ptr != NULL ); t( size == sf_valuesize(g->r->fmt, sv_vpointer(v), v->size, g->r->scheme->count) ); t( memcmp(ptr, sf_value(g->r->fmt, sv_vpointer(v), g->r->scheme->count), size) == 0 ); } else { t( ptr == NULL ); } break; } case SF_DOCUMENT: { int i = 0; int size = 0; while (i < g->r->scheme->count) { void *ptr = sp_getstring(o, g->r->scheme->parts[i].name, &size); t( ptr != NULL ); t( size == sf_keysize(sv_vpointer(v), i) ); t( memcmp(ptr, sf_key(sv_vpointer(v), i), size) == 0 ); i++; } void *ptr = sp_getstring(o, "value", &size); t( ptr != NULL ); if ((g->value_start + g->value_end) > 0) { int vsize = sf_valuesize(g->r->fmt, ptr, size, g->r->scheme->count); t( vsize == sf_valuesize(g->r->fmt, sv_vpointer(v), v->size, g->r->scheme->count) ); ptr = sf_value(g->r->fmt, ptr, g->r->scheme->count); t( memcmp(ptr, sf_value(g->r->fmt, sv_vpointer(v), g->r->scheme->count), vsize) == 0 ); } break; } } sv_vfree(g->r, v); }
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; }
static inline svv* getv(svindex *i, sr *r, uint64_t vlsn, svv *key) { ssrbnode *n = NULL; int rc = sv_indexmatch(&i->i, r->scheme, sv_vpointer(key), sv_vsize(key), &n); if (rc == 0 && n) { return sv_visible(sscast(n, svv, node), vlsn); } return NULL; }
static void sv_indexiter_lt_eq(void) { svindex i; t( sv_indexinit(&i) == 0 ); int keya = 7; int keyb = 5; int keyc = 2; svv *va = st_svv(&st_r.g, NULL, 0, 0, keya); t( sv_indexset(&i, &st_r.r, va) == 0 ); svv *vb = st_svv(&st_r.g, NULL, 0, 0, keyb); t( sv_indexset(&i, &st_r.r, vb) == 0 ); svv *vc = st_svv(&st_r.g, NULL, 0, 0, keyc); t( sv_indexset(&i, &st_r.r, vc) == 0 ); ssiter it; ss_iterinit(sv_indexiter, &it); ss_iteropen(sv_indexiter, &it, &st_r.r, &i, SS_LT, sv_vpointer(va), va->size); t( ss_iteratorhas(&it) != 0 ); sv *v = ss_iteratorof(&it); t( v->v == vb ); ss_iterinit(sv_indexiter, &it); ss_iteropen(sv_indexiter, &it, &st_r.r, &i, SS_LT, sv_vpointer(vb), vb->size); t( ss_iteratorhas(&it) != 0 ); v = ss_iteratorof(&it); t( v->v == vc ); ss_iterinit(sv_indexiter, &it); ss_iteropen(sv_indexiter, &it, &st_r.r, &i, SS_LT, sv_vpointer(vc), vc->size); t( ss_iteratorhas(&it) == 0 ); v = ss_iteratorof(&it); t( v == NULL ); sv_indexfree(&i, &st_r.r); }
int sx_get(sx *x, sxindex *index, svv *key, svv **result) { ssrbnode *n = NULL; int rc; rc = sx_match(&index->i, index->r->scheme, sv_vpointer(key), 0, &n); if (! (rc == 0 && n)) goto add; sxv *head = sscast(n, sxv, node); sxv *v = sx_vmatch(head, x->id); if (v == NULL) goto add; if (ssunlikely(sv_vflags(v->v, index->r) & SVGET)) return 0; if (ssunlikely(sv_vflags(v->v, index->r) & SVDELETE)) return 2; *result = sv_vbuildraw(index->r, sv_vpointer(v->v)); if (ssunlikely(*result == NULL)) { sr_oom(index->r->e); rc = -1; } else { rc = 1; } return rc; add: /* track a start of the latest read sequence in the * transactional log */ if (x->log_read == -1) x->log_read = sv_logcount(x->log); rc = sx_set(x, index, key); if (ssunlikely(rc == -1)) return -1; sv_vref(key); return 0; }
static inline void si_redistribute_set(si *index, sr *r, svv *v) { /* match node */ ssiter i; ss_iterinit(si_iter, &i); ss_iteropen(si_iter, &i, r, index, SS_GTE, sv_vpointer(v)); sinode *node = ss_iterof(si_iter, &i); assert(node != NULL); /* update node */ svindex *vindex = si_nodeindex(node); sv_indexset(vindex, r, v); node->used += sv_vsize(v, &index->r); /* schedule node */ si_plannerupdate(&index->p, node); }
static void sv_indexiter_gte_empty(void) { svindex i; t( sv_indexinit(&i) == 0 ); svv *key = st_svv(&st_r.g, &st_r.gc, 0, 0, 7); ssiter it; ss_iterinit(sv_indexiter, &it); ss_iteropen(sv_indexiter, &it, &st_r.r, &i, SS_GTE, sv_vpointer(key), key->size); t( ss_iteratorhas(&it) == 0 ); sv *v = ss_iteratorof(&it); t( v == NULL ); sv_indexfree(&i, &st_r.r); }
int se_reqread(sereq *r) { sereqarg *arg = &r->arg; sedb *db = (sedb*)r->db; uint32_t keysize; void *key; if (sslikely(arg->v.v)) { keysize = sv_size(&arg->v); key = sv_pointer(&arg->v); } else { keysize = 0; key = NULL; } char *prefix; uint32_t prefixsize; if (arg->vprefix.v) { void *vptr = sv_vpointer(arg->vprefix.v); prefix = sf_key(vptr, 0); prefixsize = sf_keysize(vptr, 0); } else { prefix = NULL; prefixsize = 0; } if (sslikely(arg->vlsn_generate)) arg->vlsn = sr_seq(db->r.seq, SR_LSN); sitx x; si_begin(&x, &db->index, 1); siread q; si_readopen(&q, &x, arg->cache, arg->order, arg->vlsn, prefix, prefixsize, key, keysize); if (arg->update) si_readupdate(&q, &arg->vup, arg->update_eq); if (arg->cache_only) si_readcache_only(&q); if (arg->has) si_readhas(&q); r->rc = si_read(&q); r->read_disk = q.read_disk; r->read_cache = q.read_cache; r->v = q.result.v; si_readclose(&q); si_commit(&x); return r->rc; }
static inline void si_redistribute_set(si *index, sr *r, uint64_t now, svv *v) { index->update_time = now; /* match node */ ssiter i; ss_iterinit(si_iter, &i); ss_iteropen(si_iter, &i, r, index, SS_ROUTE, sv_vpointer(v), v->size); sinode *node = ss_iterof(si_iter, &i); assert(node != NULL); /* update node */ svindex *vindex = si_nodeindex(node); sv_indexset(vindex, r, v); node->update_time = index->update_time; node->used += sv_vsize(v); /* schedule node */ si_plannerupdate(&index->p, SI_BRANCH, node); }
int se_document_createkey(sedocument *o) { sedb *db = (sedb*)o->o.parent; se *e = se_of(&db->o); if (o->created) return 0; assert(o->v == NULL); /* set prefix */ if (o->prefix) { if (db->scheme->scheme.keys[0]->type != SS_STRING) return sr_error(&e->error, "%s", "prefix search is only " "supported for a string key"); void *copy = ss_malloc(&e->a, o->prefix_size); if (ssunlikely(copy == NULL)) return sr_oom(&e->error); memcpy(copy, o->prefix, o->prefix_size); o->prefix_copy = copy; } /* set unspecified min/max keys, depending on * iteration order */ if (ssunlikely(o->fields_count_keys != db->scheme->scheme.keys_count)) { if (o->prefix && o->fields_count_keys == 0) { memset(o->fields, 0, sizeof(o->fields)); o->fields[0].pointer = o->prefix; o->fields[0].size = o->prefix_size; } sf_limitapply(&db->limit, &db->scheme->scheme, o->fields, o->order); o->fields_count = db->scheme->scheme.fields_count; o->fields_count_keys = db->scheme->scheme.keys_count; } o->v = sv_vbuild(db->r, o->fields); if (ssunlikely(o->v == NULL)) return sr_oom(&e->error); sf_flagsset(db->r->scheme, sv_vpointer(o->v), SVGET); o->created = 1; return 0; }
int sx_set(sx *x, sxindex *index, svv *version) { sxmanager *m = x->manager; sr *r = m->r; if (! (version->flags & SVGET)) { x->log_read = -1; } /* allocate mvcc container */ sxv *v = sx_valloc(m->asxv, version); if (ssunlikely(v == NULL)) { ss_quota(r->quota, SS_QREMOVE, sv_vsize(version)); sv_vfree(r, version); return -1; } v->id = x->id; v->index = index; svlogv lv; lv.id = index->dsn; lv.next = UINT32_MAX; sv_init(&lv.v, &sx_vif, v, NULL); /* update concurrent index */ ssrbnode *n = NULL; int rc = sx_match(&index->i, index->r->scheme, sv_vpointer(version), version->size, &n); if (ssunlikely(rc == 0 && n)) { /* exists */ } else { int pos = rc; /* unique */ v->lo = sv_logcount(&x->log); rc = sv_logadd(&x->log, r->a, &lv, index->ptr); if (ssunlikely(rc == -1)) { sr_oom(r->e); goto error; } ss_rbset(&index->i, n, pos, &v->node); return 0; } sxv *head = sscast(n, sxv, node); /* match previous update made by current * transaction */ sxv *own = sx_vmatch(head, x->id); if (ssunlikely(own)) { if (ssunlikely(version->flags & SVUPDATE)) { sr_error(r->e, "%s", "only one update statement is " "allowed per a transaction key"); goto error; } /* replace old document with the new one */ lv.next = sv_logat(&x->log, own->lo)->next; v->lo = own->lo; if (ssunlikely(sx_vaborted(own))) sx_vabort(v); sx_vreplace(own, v); if (sslikely(head == own)) ss_rbreplace(&index->i, &own->node, &v->node); /* update log */ sv_logreplace(&x->log, v->lo, &lv); ss_quota(r->quota, SS_QREMOVE, sv_vsize(own->v)); sx_vfree(r, m->asxv, own); return 0; } /* update log */ v->lo = sv_logcount(&x->log); rc = sv_logadd(&x->log, r->a, &lv, index->ptr); if (ssunlikely(rc == -1)) { sr_oom(r->e); goto error; } /* add version */ sx_vlink(head, v); return 0; error: ss_quota(r->quota, SS_QREMOVE, sv_vsize(v->v)); sx_vfree(r, m->asxv, v); return -1; }
static char* sv_vifpointer(sv *v) { return sv_vpointer(((svv*)v->v)); }
static char* sx_vifpointer(sv *v) { return sv_vpointer(((sxv*)v->v)->v); }
int sx_set(sx *t, sxindex *index, svv *version) { sxmanager *m = t->manager; /* allocate mvcc container */ sxv *v = sx_valloc(m->asxv, version); if (ssunlikely(v == NULL)) { sv_vfree(m->a, version); return -1; } v->id = t->id; v->index = index; svlogv lv; lv.id = index->dsn; lv.vgc = NULL; lv.next = UINT32_MAX; sv_init(&lv.v, &sx_vif, v, NULL); /* update concurrent index */ ssrbnode *n = NULL; int rc = sx_match(&index->i, index->scheme, sv_vpointer(version), version->size, &n); if (ssunlikely(rc == 0 && n)) { /* exists */ } else { /* unique */ v->lo = sv_logcount(&t->log); if (ssunlikely((sv_logadd(&t->log, m->a, &lv, index->ptr)) == -1)) { rc = sr_oom(index->r->e); } else { ss_rbset(&index->i, n, rc, &v->node); rc = 0; } return rc; } sxv *head = sscast(n, sxv, node); /* match previous update made by current * transaction */ sxv *own = sx_vmatch(head, t->id); if (ssunlikely(own)) { if (ssunlikely(version->flags & SVUPDATE)) { sr_error(index->r->e, "%s", "only one update statement is " "allowed per a transaction key"); sx_vfree(m->a, m->asxv, v); return -1; } /* replace old object with the new one */ lv.next = sv_logat(&t->log, own->lo)->next; v->lo = own->lo; sx_vreplace(own, v); if (sslikely(head == own)) ss_rbreplace(&index->i, &own->node, &v->node); /* update log */ sv_logreplace(&t->log, v->lo, &lv); sx_vfree(m->a, m->asxv, own); return 0; } /* update log */ rc = sv_logadd(&t->log, m->a, &lv, index->ptr); if (ssunlikely(rc == -1)) { sx_vfree(m->a, m->asxv, v); return sr_oom(index->r->e); } /* add version */ sx_vlink(head, v); return 0; }
int sx_set(sx *x, sxindex *index, svv *version) { sxmanager *m = x->manager; sr *r = index->r; svlogv lv; lv.index_id = index->dsn; lv.next = UINT32_MAX; lv.v = version; lv.ptr = NULL; /* allocate mvcc container */ sxv *v = sx_valloc(&m->pool, version); if (ssunlikely(v == NULL)) { sv_vunref(r, version); return -1; } v->id = x->id; v->index = index; lv.ptr = v; if (! (sv_vflags(version, index->r) & SVGET)) x->log_read = -1; /* update concurrent index */ ssrbnode *n = NULL; int rc; rc = sx_match(&index->i, index->r->scheme, sv_vpointer(version), 0, &n); if (ssunlikely(rc == 0 && n)) { /* exists */ } else { int pos = rc; /* unique */ v->lo = sv_logcount(x->log); rc = sv_logadd(x->log, r, &lv); if (ssunlikely(rc == -1)) { sr_oom(r->e); goto error; } ss_rbset(&index->i, n, pos, &v->node); return 0; } sxv *head = sscast(n, sxv, node); /* match previous update made by current * transaction */ sxv *own = sx_vmatch(head, x->id); if (ssunlikely(own)) { if (ssunlikely(sv_vflags(version, index->r) & SVUPSERT)) { sr_error(r->e, "%s", "only one upsert statement is " "allowed per a transaction key"); goto error; } /* replace old document with the new one */ lv.next = sv_logat(x->log, own->lo)->next; v->lo = own->lo; if (ssunlikely(sx_vaborted(own))) sx_vabort(v); sx_vreplace(own, v); if (sslikely(head == own)) ss_rbreplace(&index->i, &own->node, &v->node); /* update log */ sv_logreplace(x->log, r, v->lo, &lv); sx_vfree(&m->pool, r, own); return 0; } /* update log */ v->lo = sv_logcount(x->log); rc = sv_logadd(x->log, r, &lv); if (ssunlikely(rc == -1)) { sr_oom(r->e); goto error; } /* add version */ sx_vlink(head, v); return 0; error: sx_vfree(&m->pool, r, v); return -1; }
} else { sx_untrack(v); ss_free(m->asxv, v); } } /* rollback latest reads */ sx_rollback_svp(x, &i, 0); sx_promote(x, SXCOMMIT); sx_end(x); return SXCOMMIT; } ss_rbget(sx_match, sr_compare(scheme, sv_vpointer((sscast(n, sxv, node))->v), (sscast(n, sxv, node))->v->size, key, keysize)) int sx_set(sx *x, sxindex *index, svv *version) { sxmanager *m = x->manager; sr *r = m->r; if (! (version->flags & SVGET)) { x->log_read = -1; } /* allocate mvcc container */ sxv *v = sx_valloc(m->asxv, version); if (ssunlikely(v == NULL)) { ss_quota(r->quota, SS_QREMOVE, sv_vsize(version)); sv_vfree(r, version);