sxstate sx_rollback(sx *x) { sxmanager *m = x->manager; ssiter i; ss_iterinit(ss_bufiter, &i); ss_iteropen(ss_bufiter, &i, &x->log.buf, sizeof(svlogv)); /* support log free after commit and half-commit mode */ if (x->state == SXCOMMIT) { int gc = 0; for (; ss_iterhas(ss_bufiter, &i); ss_iternext(ss_bufiter, &i)) { svlogv *lv = ss_iterof(ss_bufiter, &i); svv *v = lv->v.v; int size = sv_vsize(v); if (sv_vunref(m->r, v)) gc += size; } ss_quota(m->r->quota, SS_QREMOVE, gc); sx_promote(x, SXROLLBACK); return SXROLLBACK; } sx_rollback_svp(x, &i, 1); sx_promote(x, SXROLLBACK); sx_end(x); return SXROLLBACK; }
void si_gcv(sr *r, svv *v) { sw *log = (sw*)v->log; if (sv_vunref(r, v)) { if (log) ss_gcsweep(&log->gc, 1); } }
static void addv(sdbuild *b, sr *r, uint64_t lsn, uint8_t flags, int *key) { sfv pv[2]; pv[0].pointer = (char*)key; pv[0].size = sizeof(uint32_t); pv[1].pointer = NULL; pv[1].size = 0; svv *v = sv_vbuild(r, pv, 0); v->lsn = lsn; v->flags = flags; sv vv; sv_init(&vv, &sv_vif, v, NULL); sd_buildadd(b, r, &vv, flags & SVDUP); sv_vunref(r, v); }
static inline void sx_rollback_svp(sx *x, ssiter *i, int free) { sxmanager *m = x->manager; for (; ss_iterhas(ss_bufiter, i); ss_iternext(ss_bufiter, i)) { svlogv *lv = ss_iterof(ss_bufiter, i); sxv *v = lv->ptr; /* remove from index and replace head with * a first waiter */ sx_untrack(v); lv->ptr = NULL; if (free) { sxindex *i = v->index; sv_vunref(i->r, v->v); } sx_vpool_push(&m->pool, v); } }
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; }
so *se_read(sedb *db, sedocument *o, sx *x, uint64_t vlsn, sicache *cache) { se *e = se_of(&db->o); uint64_t start = ss_utime(); /* prepare the key */ int auto_close = o->created <= 1; int rc = se_document_createkey(o); if (ssunlikely(rc == -1)) goto error; rc = se_document_validate_ro(o, &db->o); if (ssunlikely(rc == -1)) goto error; if (ssunlikely(! se_active(e))) goto error; sv vup; sv_init(&vup, &sv_vif, NULL, NULL); sedocument *ret = NULL; /* concurrent */ if (x && o->order == SS_EQ) { /* note: prefix is ignored during concurrent * index search */ int rc = sx_get(x, &db->coindex, &o->v, &vup); if (ssunlikely(rc == -1 || rc == 2 /* delete */)) goto error; if (rc == 1 && !sv_is(&vup, SVUPSERT)) { ret = (sedocument*)se_document_new(e, &db->o, &vup); if (sslikely(ret)) { ret->cold_only = o->cold_only; ret->created = 1; ret->orderset = 1; ret->flagset = 1; } else { sv_vunref(db->r, vup.v); } if (auto_close) so_destroy(&o->o); return &ret->o; } } else { sx_get_autocommit(&e->xm, &db->coindex); } /* prepare read cache */ int cachegc = 0; if (cache == NULL) { cachegc = 1; cache = si_cachepool_pop(&e->cachepool); if (ssunlikely(cache == NULL)) { if (vup.v) sv_vunref(db->r, vup.v); sr_oom(&e->error); goto error; } } sv_vref(o->v.v); /* do read */ siread rq; si_readopen(&rq, db->index, cache, o->order, vlsn, sv_pointer(&o->v), vup.v, o->prefix_copy, o->prefix_size, o->cold_only, 0, start); rc = si_read(&rq); si_readclose(&rq); /* prepare result */ if (rc == 1) { ret = (sedocument*)se_readresult(e, &rq); if (ret) o->prefix_copy = NULL; } /* cleanup */ if (o->v.v) sv_vunref(db->r, o->v.v); if (vup.v) sv_vunref(db->r, vup.v); if (ret == NULL && rq.result.v) sv_vunref(db->r, rq.result.v); if (cachegc && cache) si_cachepool_push(cache); if (auto_close) so_destroy(&o->o); return &ret->o; error: if (auto_close) so_destroy(&o->o); return NULL; }