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; }
sxstate sx_begin(sxmanager *m, sx *x, sxtype type, uint64_t vlsn) { sx_promote(x, SXREADY); x->type = type; x->log_read = -1; sr_seqlock(m->r->seq); x->csn = m->csn; x->id = sr_seqdo(m->r->seq, SR_TSNNEXT); if (sslikely(vlsn == 0)) x->vlsn = sr_seqdo(m->r->seq, SR_LSN); else x->vlsn = vlsn; sr_sequnlock(m->r->seq); sx_init(m, x); ss_spinlock(&m->lock); ssrbnode *n = NULL; int rc = sx_matchtx(&m->i, NULL, (char*)&x->id, sizeof(x->id), &n); if (rc == 0 && n) { assert(0); } else { ss_rbset(&m->i, n, rc, &x->node); } if (type == SXRO) m->count_rd++; else m->count_rw++; ss_spinunlock(&m->lock); return SXREADY; }
sxstate sx_set_autocommit(sxmanager *m, sxindex *index, sx *x, svlog *log, svv *v) { if (sslikely(m->count_rw == 0)) { sx_init(m, x, log); svlogv lv; lv.index_id = index->dsn; lv.next = UINT32_MAX; lv.v = v; lv.ptr = NULL; sv_logadd(x->log, index->r, &lv); sr_seq(index->r->seq, SR_TSNNEXT); sx_promote(x, SX_COMMIT); return SX_COMMIT; } sx_begin(m, x, SX_RW, log, 0); int rc = sx_set(x, index, v); if (ssunlikely(rc == -1)) { sx_rollback(x); return SX_ROLLBACK; } sxstate s = sx_prepare(x, NULL, NULL); switch (s) { case SX_PREPARE: s = sx_commit(x); break; case SX_LOCK: s = sx_rollback(x); break; case SX_ROLLBACK: break; default: assert(0); } return s; }
void sx_init(sxmanager *m, sx *x, svlog *log) { x->manager = m; x->log = log; sx_promote(x, SX_UNDEF); ss_listinit(&x->deadlock); }
sxstate sx_set_autocommit(sxmanager *m, sxindex *index, sx *x, svv *v) { if (sslikely(m->count_rw == 0)) { sx_init(m, x); svlogv lv; lv.id = index->dsn; lv.next = UINT32_MAX; sv_init(&lv.v, &sv_vif, v, NULL); sv_logadd(&x->log, m->r->a, &lv, index->ptr); sr_seq(m->r->seq, SR_TSNNEXT); sx_promote(x, SXCOMMIT); return SXCOMMIT; } sx_begin(m, x, SXRW, 0); int rc = sx_set(x, index, v); if (ssunlikely(rc == -1)) { sx_rollback(x); return SXROLLBACK; } sxstate s = sx_prepare(x, NULL, NULL); if (sslikely(s == SXPREPARE)) sx_commit(x); else if (s == SXLOCK) sx_rollback(x); return s; }
void sx_gc(sx *x) { sxmanager *m = x->manager; sx_promote(x, SXUNDEF); sv_logfree(&x->log, m->r->a); if (m->count_gc == 0) return; sx_garbage_collect(m); }
void sx_gc(sx *x) { sxmanager *m = x->manager; sx_promote(x, SX_UNDEF); x->log = NULL; if (m->count_gc == 0) return; sx_garbage_collect(m); }
sxstate sx_rollback(sx *x) { assert(x->state != SX_COMMIT); ssiter i; ss_iterinit(ss_bufiter, &i); ss_iteropen(ss_bufiter, &i, &x->log->buf, sizeof(svlogv)); sx_rollback_svp(x, &i, 1); sx_promote(x, SX_ROLLBACK); sx_end(x); return SX_ROLLBACK; }
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 half-commit mode */ if (x->state == SXCOMMIT) { for (; ss_iterhas(ss_bufiter, &i); ss_iternext(ss_bufiter, &i)) { svlogv *lv = ss_iterof(ss_bufiter, &i); svv *v = lv->v.v; sv_vfree(m->r, v); } sx_promote(x, SXROLLBACK); return SXROLLBACK; } sx_rollback_svp(x, &i, 1); sx_promote(x, SXROLLBACK); sx_end(x); return SXROLLBACK; }
sxstate sx_commit(sx *x) { if (x->state == SX_COMMIT) return SX_COMMIT; assert(x->state == SX_PREPARE); sxmanager *m = x->manager; ssiter i; ss_iterinit(ss_bufiter, &i); ss_iteropen(ss_bufiter, &i, &x->log->buf, sizeof(svlogv)); uint64_t csn = ++m->csn; for (; ss_iterhas(ss_bufiter, &i); ss_iternext(ss_bufiter, &i)) { svlogv *lv = ss_iterof(ss_bufiter, &i); sxv *v = lv->ptr; if ((int)v->lo == x->log_read) break; /* abort conflict reader */ if (v->prev && !sx_vcommitted(v->prev)) { sxindex *i = v->prev->index; assert(sv_vflags(v->prev->v, i->r) & SVGET); sx_vabort(v->prev); } /* abort waiters */ sx_vabort_all(v->next); /* mark stmt as commited */ sx_vcommit(v, csn); lv->ptr = NULL; /* schedule read stmt for gc */ sxindex *i = v->index; if (sv_vflags(v->v, i->r) & SVGET) { sv_vref(v->v); v->gc = m->gc; m->gc = v; m->count_gc++; } else { sx_untrack(v); sx_vpool_push(&m->pool, v); } } /* rollback latest reads */ sx_rollback_svp(x, &i, 0); sx_promote(x, SX_COMMIT); sx_end(x); return SX_COMMIT; }
sxstate sx_commit(sx *x) { assert(x->state == SXPREPARE); sxmanager *m = x->manager; ssiter i; ss_iterinit(ss_bufiter, &i); ss_iteropen(ss_bufiter, &i, &x->log.buf, sizeof(svlogv)); uint64_t csn = ++m->csn; for (; ss_iterhas(ss_bufiter, &i); ss_iternext(ss_bufiter, &i)) { svlogv *lv = ss_iterof(ss_bufiter, &i); sxv *v = lv->v.v; if ((int)v->lo == x->log_read) break; /* abort conflict reader */ if (v->prev && !sx_vcommitted(v->prev)) { assert(v->prev->v->flags & SVGET); sx_vabort(v->prev); } /* abort waiters */ sx_vabort_all(v->next); /* mark stmt as commited */ sx_vcommit(v, csn); /* translate log version from sxv to svv */ sv_init(&lv->v, &sv_vif, v->v, NULL); /* schedule read stmt for gc */ if (v->v->flags & SVGET) { sv_vref(v->v); v->gc = m->gc; m->gc = v; m->count_gc++; } 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; }
sxstate sx_prepare(sx *x, sxpreparef prepare, void *arg) { uint64_t lsn = sr_seq(x->manager->seq, SR_LSN); /* proceed read-only transactions */ if (x->type == SX_RO || sv_logcount_write(x->log) == 0) return sx_promote(x, SX_PREPARE); ssiter i; ss_iterinit(ss_bufiter, &i); ss_iteropen(ss_bufiter, &i, &x->log->buf, sizeof(svlogv)); sxstate rc; for (; ss_iterhas(ss_bufiter, &i); ss_iternext(ss_bufiter, &i)) { svlogv *lv = ss_iterof(ss_bufiter, &i); sxv *v = lv->ptr; if ((int)v->lo == x->log_read) break; if (sx_vaborted(v)) return sx_promote(x, SX_ROLLBACK); if (sslikely(v->prev == NULL)) { rc = sx_preparecb(x, lv, lsn, prepare, arg); if (ssunlikely(rc != 0)) return sx_promote(x, SX_ROLLBACK); continue; } if (sx_vcommitted(v->prev)) { if (v->prev->csn > x->csn) return sx_promote(x, SX_ROLLBACK); continue; } /* force commit for read-only conflicts */ sxindex *i = v->prev->index; if (sv_vflags(v->prev->v, i->r) & SVGET) { rc = sx_preparecb(x, lv, lsn, prepare, arg); if (ssunlikely(rc != 0)) return sx_promote(x, SX_ROLLBACK); continue; } return sx_promote(x, SX_LOCK); } return sx_promote(x, SX_PREPARE); }
sxstate sx_prepare(sx *x, sxpreparef prepare, void *arg) { uint64_t lsn = sr_seq(x->manager->r->seq, SR_LSN); /* proceed read-only transactions */ if (x->type == SXRO || sv_logcount_write(&x->log) == 0) return sx_promote(x, SXPREPARE); ssiter i; ss_iterinit(ss_bufiter, &i); ss_iteropen(ss_bufiter, &i, &x->log.buf, sizeof(svlogv)); for (; ss_iterhas(ss_bufiter, &i); ss_iternext(ss_bufiter, &i)) { svlogv *lv = ss_iterof(ss_bufiter, &i); sxv *v = lv->v.v; if ((int)v->lo == x->log_read) break; if (sx_vaborted(v)) return sx_promote(x, SXROLLBACK); if (sslikely(v->prev == NULL)) { if (prepare && lsn != x->vlsn) { sxindex *i = v->index; if (prepare(x, &lv->v, arg, i->ptr)) return sx_promote(x, SXROLLBACK); } continue; } if (sx_vcommitted(v->prev)) { if (v->prev->csn > x->csn) return sx_promote(x, SXROLLBACK); continue; } /* force commit for read-only conflicts */ if (v->prev->v->flags & SVGET) continue; return sx_promote(x, SXLOCK); } return sx_promote(x, SXPREPARE); }