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 sx_gc(sx *t, sr *r) { sxmanager *m = t->manager; ssiter i; ss_iterinit(ss_bufiter, &i); ss_iteropen(ss_bufiter, &i, &t->log.buf, sizeof(svlogv)); if (sslikely(t->s == SXCOMMIT)) { for (; ss_iterhas(ss_bufiter, &i); ss_iternext(ss_bufiter, &i)) { svlogv *lv = ss_iterof(ss_bufiter, &i); sxv *v = lv->vgc; ss_free(m->asxv, v); } } else if (t->s == SXROLLBACK) { int gc = 0; for (; ss_iterhas(ss_bufiter, &i); ss_iternext(ss_bufiter, &i)) { svlogv *lv = ss_iterof(ss_bufiter, &i); sxv *v = lv->v.v; gc += sv_vsize((svv*)v->v); sx_vfree(m->a, m->asxv, v); } ss_quota(r->quota, SS_QREMOVE, gc); } sv_logfree(&t->log, m->a); t->s = SXUNDEF; }
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 inline int se_txwrite(setx *t, sedocument *o, uint8_t flags) { se *e = se_of(&t->o); sedb *db = se_cast(o->o.parent, sedb*, SEDB); /* validate req */ if (ssunlikely(t->t.state == SXPREPARE)) { sr_error(&e->error, "%s", "transaction is in 'prepare' state (read-only)"); goto error; } /* validate database status */ int status = se_status(&db->status); switch (status) { case SE_SHUTDOWN: if (ssunlikely(! se_dbvisible(db, t->t.id))) { sr_error(&e->error, "%s", "database is invisible for the transaction"); goto error; } break; case SE_RECOVER: case SE_ONLINE: break; default: goto error; } if (flags == SVUPSERT && !sf_upserthas(&db->scheme.fmt_upsert)) flags = 0; /* prepare document */ svv *v; int rc = se_dbv(db, o, 0, &v); if (ssunlikely(rc == -1)) goto error; v->flags = flags; v->log = o->log; sv vp; sv_init(&vp, &sv_vif, v, NULL); so_destroy(&o->o); /* ensure quota */ int size = sv_vsize(v); ss_quota(&e->quota, SS_QADD, size); /* concurrent index only */ rc = sx_set(&t->t, &db->coindex, v); if (ssunlikely(rc == -1)) { ss_quota(&e->quota, SS_QREMOVE, size); return -1; } return 0; error: so_destroy(&o->o); return -1; }
uint32_t si_gcv(ssa *a, svv *gc) { uint32_t used = 0; svv *v = gc; while (v) { used += sv_vsize(v); svv *n = v->next; sl *log = (sl*)v->log; if (log) ss_gcsweep(&log->gc, 1); sv_vfree(a, v); v = n; } return used; }
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 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); }
static inline void sx_rollback_svp(sx *x, ssiter *i, int free) { sxmanager *m = x->manager; int gc = 0; for (; ss_iterhas(ss_bufiter, i); ss_iternext(ss_bufiter, i)) { svlogv *lv = ss_iterof(ss_bufiter, i); sxv *v = lv->v.v; /* remove from index and replace head with * a first waiter */ sx_untrack(v); /* translate log version from sxv to svv */ sv_init(&lv->v, &sv_vif, v->v, NULL); if (free) { if (sslikely(! (v->v->flags & SVGET))) gc += sv_vsize((svv*)v->v); sx_vfree(m->r, m->asxv, v); } } ss_quota(m->r->quota, SS_QREMOVE, gc); }
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; }