diff --git a/src/compiler/GF/Infra/SIO.hs b/src/compiler/GF/Infra/SIO.hs index 629eaccd3..27b4926c3 100644 --- a/src/compiler/GF/Infra/SIO.hs +++ b/src/compiler/GF/Infra/SIO.hs @@ -136,4 +136,4 @@ importSource opts files = lift0 $ GF.importSource opts files link opts pgf src = lift0 $ GF.link opts pgf src modifyPGF gr t = lift0 (PGFT.modifyPGF gr t) -checkoutPGF gr b = lift0 (PGFT.checkoutPGF gr b) +checkoutPGF gr = lift0 (PGFT.checkoutPGF gr) diff --git a/src/compiler/GF/Interactive.hs b/src/compiler/GF/Interactive.hs index 6f7569efe..19a21d028 100644 --- a/src/compiler/GF/Interactive.hs +++ b/src/compiler/GF/Interactive.hs @@ -154,8 +154,8 @@ execute1' s0 = checkout = do mb_pgf <- gets multigrammar case mb_pgf of - Just pgf -> do mb_pgf <- lift $ checkoutPGF pgf "master" - modify $ \gfenv -> gfenv{pgfenv = (fst (pgfenv gfenv),mb_pgf)} + Just pgf -> do pgf <- lift $ checkoutPGF pgf + modify $ \gfenv -> gfenv{pgfenv = (fst (pgfenv gfenv),Just pgf)} Nothing -> return () interruptible :: ShellM Bool -> ShellM Bool diff --git a/src/runtime/c/pgf/data.cxx b/src/runtime/c/pgf/data.cxx index 9ec6eb9e3..42e2f504d 100644 --- a/src/runtime/c/pgf/data.cxx +++ b/src/runtime/c/pgf/data.cxx @@ -2,31 +2,31 @@ void PgfFlag::release(ref flag) { - pgf_literal_free(flag->value); - PgfDB::free(flag); + pgf_literal_release(flag->value); + PgfDB::free(flag, flag->name.size+1); } void PgfAbsFun::release(ref absfun) { - pgf_type_free(absfun->type); + pgf_type_release(absfun->type); if (absfun->bytecode != 0) { PgfDB::free(absfun->bytecode); } - PgfDB::free(absfun); + PgfDB::free(absfun, absfun->name.size+1); } void PgfAbsCat::release(ref abscat) { - pgf_context_free(abscat->context); - PgfDB::free(abscat); + pgf_context_release(abscat->context); + PgfDB::free(abscat, abscat->name.size+1); } void PgfPGF::release(ref pgf) { namespace_release(pgf->gflags); - PgfDB::free(pgf->abstract.name); + text_db_release(pgf->abstract.name); namespace_release(pgf->abstract.aflags); namespace_release(pgf->abstract.funs); namespace_release(pgf->abstract.cats); @@ -41,112 +41,112 @@ void PgfConcr::release(ref concr) namespace_release(concr->lincats); phrasetable_release(concr->phrasetable); namespace_release(concr->printnames); - PgfDB::free(concr); + PgfDB::free(concr, concr->name.size+1); } void PgfConcrLincat::release(ref lincat) { for (size_t i = 0; i < lincat->fields->len; i++) { - PgfDB::free(*vector_elem(lincat->fields, i)); + text_db_release(*vector_elem(lincat->fields, i)); } + Vector>::release(lincat->fields); - PgfDB::free(lincat->fields); - for (size_t i = 0; i < lincat->args->len; i++) { - PgfDB::free(vector_elem(lincat->args, i)->param); + PgfLParam::release(vector_elem(lincat->args, i)->param); } - PgfDB::free(lincat->args); + Vector::release(lincat->args); for (size_t i = 0; i < lincat->res->len; i++) { - ref res = *vector_elem(lincat->res, i); - if (res->vars != 0) - PgfDB::free(res->vars); - PgfDB::free(res); + PgfPResult::release(*vector_elem(lincat->res, i)); } - PgfDB::free(lincat->res); + Vector>::release(lincat->res); - for (size_t i = 0; i < lincat->seqs->len; i++) { - ref seq = *vector_elem(lincat->seqs, i); - if (!(--seq->ref_count)) { - PgfSequence::release(seq); - } - } - PgfDB::free(lincat->seqs); + Vector>::release(lincat->seqs); - PgfDB::free(lincat); + PgfDB::free(lincat, lincat->name.size+1); } -PGF_INTERNAL -void pgf_symbol_free(PgfSymbol sym) +void PgfLParam::release(ref param) { - switch (ref::get_tag(sym)) { - case PgfSymbolKP::tag: { - auto sym_kp = ref::untagged(sym); - PgfSequence::release(sym_kp->default_form); - for (size_t i = 0; i < sym_kp->alts.len; i++) { - PgfSequence::release(sym_kp->alts.data[i].form); - for (size_t j = 0; j < sym_kp->alts.data[i].prefixes->len; j++) { - ref prefix = *vector_elem(sym_kp->alts.data[i].prefixes, j); - PgfDB::free(prefix); - } - } - PgfDB::free(sym_kp); - break; - } - case PgfSymbolBIND::tag: - case PgfSymbolSOFTBIND::tag: - case PgfSymbolNE::tag: - case PgfSymbolSOFTSPACE::tag: - case PgfSymbolCAPIT::tag: - case PgfSymbolALLCAPIT::tag: - break; - default: - PgfDB::free(ref::untagged(sym)); - } + PgfDB::free(param, param->n_terms*sizeof(param->terms[0])); +} + +void PgfPResult::release(ref res) +{ + if (res->vars != 0) + Vector::release(res->vars); + PgfDB::free(res, res->param.n_terms*sizeof(res->param.terms[0])); } void PgfSequence::release(ref seq) { for (size_t i = 0; i < seq->syms.len; i++) { PgfSymbol sym = *vector_elem(&seq->syms, i); - pgf_symbol_free(sym); - } - PgfDB::free(seq); -} -void PgfSequenceBackrefs::release(ref backrefs) -{ - PgfDB::free(backrefs); + switch (ref::get_tag(sym)) { + case PgfSymbolCat::tag: { + auto sym_cat = ref::untagged(sym); + PgfDB::free(sym_cat, sym_cat->r.n_terms*sizeof(sym_cat->r.terms[0])); + break; + } + case PgfSymbolLit::tag: { + auto sym_lit = ref::untagged(sym); + PgfDB::free(sym_lit, sym_lit->r.n_terms*sizeof(sym_lit->r.terms[0])); + break; + } + case PgfSymbolVar::tag: + PgfDB::free(ref::untagged(sym)); + break; + case PgfSymbolKS::tag: { + auto sym_ks = ref::untagged(sym); + PgfDB::free(sym_ks, sym_ks->token.size+1); + break; + } + case PgfSymbolKP::tag: { + auto sym_kp = ref::untagged(sym); + PgfSequence::release(sym_kp->default_form); + for (size_t i = 0; i < sym_kp->alts.len; i++) { + PgfSequence::release(sym_kp->alts.data[i].form); + for (size_t j = 0; j < sym_kp->alts.data[i].prefixes->len; j++) { + text_db_release(*vector_elem(sym_kp->alts.data[i].prefixes, j)); + } + } + PgfDB::free(sym_kp, sym_kp->alts.len*sizeof(PgfAlternative)); + break; + } + case PgfSymbolBIND::tag: + case PgfSymbolSOFTBIND::tag: + case PgfSymbolNE::tag: + case PgfSymbolSOFTSPACE::tag: + case PgfSymbolCAPIT::tag: + case PgfSymbolALLCAPIT::tag: + break; + default: + throw pgf_error("Unknown symbol tag"); + } + } + PgfDB::free(seq,seq->syms.len*sizeof(PgfSymbol)); } void PgfConcrLin::release(ref lin) { for (size_t i = 0; i < lin->args->len; i++) { - PgfDB::free(vector_elem(lin->args, i)->param); + PgfLParam::release(vector_elem(lin->args, i)->param); } - PgfDB::free(lin->args); + Vector::release(lin->args); for (size_t i = 0; i < lin->res->len; i++) { - ref res = *vector_elem(lin->res, i); - if (res->vars != 0) - PgfDB::free(res->vars); - PgfDB::free(res); + PgfPResult::release(*vector_elem(lin->res, i)); } - PgfDB::free(lin->res); + Vector>::release(lin->res); - for (size_t i = 0; i < lin->seqs->len; i++) { - ref seq = *vector_elem(lin->seqs, i); - if (!(--seq->ref_count)) { - PgfSequence::release(seq); - } - } - PgfDB::free(lin->seqs); + Vector>::release(lin->seqs); - PgfDB::free(lin); + PgfDB::free(lin, lin->name.size+1); } void PgfConcrPrintname::release(ref printname) { - PgfDB::free(printname->printname); - PgfDB::free(printname); + text_db_release(printname->printname); + PgfDB::free(printname, printname->name.size+1); } diff --git a/src/runtime/c/pgf/data.h b/src/runtime/c/pgf/data.h index 40f3e1b92..ac066e4c1 100644 --- a/src/runtime/c/pgf/data.h +++ b/src/runtime/c/pgf/data.h @@ -73,7 +73,6 @@ class PgfConcr; #include "expr.h" struct PGF_INTERNAL_DECL PgfFlag { - size_t ref_count; PgfLiteral value; PgfText name; @@ -81,8 +80,6 @@ struct PGF_INTERNAL_DECL PgfFlag { }; struct PGF_INTERNAL_DECL PgfAbsFun { - size_t ref_count; - ref type; int arity; ref bytecode; @@ -93,8 +90,6 @@ struct PGF_INTERNAL_DECL PgfAbsFun { }; struct PGF_INTERNAL_DECL PgfAbsCat { - size_t ref_count; - ref> context; prob_t prob; PgfText name; @@ -116,6 +111,8 @@ struct PGF_INTERNAL_DECL PgfLParam { size_t factor; size_t var; } terms[]; + + static void release(ref param); }; struct PGF_INTERNAL_DECL PgfVariableRange { @@ -130,15 +127,16 @@ struct PGF_INTERNAL_DECL PgfPArg { struct PGF_INTERNAL_DECL PgfPResult { ref> vars; PgfLParam param; + + static void release(ref res); }; typedef object PgfSymbol; struct PGF_INTERNAL_DECL PgfSequence { - size_t ref_count; Vector syms; - static void release(ref lincat); + static void release(ref seq); }; struct PGF_INTERNAL_DECL PgfSequenceBackref { @@ -146,14 +144,6 @@ struct PGF_INTERNAL_DECL PgfSequenceBackref { size_t seq_index; }; -struct PGF_INTERNAL_DECL PgfSequenceBackrefs { - size_t ref_count; - Vector list; - - static - void release(ref backrefs); -}; - struct PGF_INTERNAL_DECL PgfSymbolCat { static const uint8_t tag = 0; size_t d; @@ -215,14 +205,9 @@ struct PGF_INTERNAL_DECL PgfSymbolALLCAPIT { static const uint8_t tag = 10; }; -PGF_INTERNAL_DECL -void pgf_symbol_free(PgfSymbol sym); - struct PGF_INTERNAL_DECL PgfConcrLincat { static const uint8_t tag = 0; - size_t ref_count; - ref abscat; ref>> fields; @@ -240,8 +225,6 @@ struct PGF_INTERNAL_DECL PgfConcrLincat { struct PGF_INTERNAL_DECL PgfConcrLin { static const uint8_t tag = 1; - size_t ref_count; - ref absfun; ref> args; @@ -254,7 +237,6 @@ struct PGF_INTERNAL_DECL PgfConcrLin { }; struct PGF_INTERNAL_DECL PgfConcrPrintname { - size_t ref_count; ref printname; PgfText name; @@ -262,8 +244,8 @@ struct PGF_INTERNAL_DECL PgfConcrPrintname { }; struct PGF_INTERNAL_DECL PgfConcr { - size_t ref_count; - size_t ref_count_ex; + static const uint8_t tag = 1; + Namespace cflags; Namespace lins; Namespace lincats; @@ -282,7 +264,7 @@ struct PGF_INTERNAL_DECL PgfConcr { }; struct PGF_INTERNAL_DECL PgfPGF { - size_t ref_count; + static const uint8_t tag = 0; uint16_t major_version; uint16_t minor_version; @@ -290,18 +272,7 @@ struct PGF_INTERNAL_DECL PgfPGF { PgfAbstr abstract; Namespace concretes; - // If the revision is transient, then it is in a double-linked list - // with all other transient revisions. - ref prev, next; - - // The name lets the user to find a particular revision in - // the database. - PgfText name; - static void release(ref pgf); }; -extern PGF_INTERNAL_DECL size_t master_size; -extern PGF_INTERNAL_DECL char master_text[]; - #endif diff --git a/src/runtime/c/pgf/db.cxx b/src/runtime/c/pgf/db.cxx index 77db9db9b..3cc69f40c 100644 --- a/src/runtime/c/pgf/db.cxx +++ b/src/runtime/c/pgf/db.cxx @@ -12,169 +12,6 @@ #include #include -typedef struct { - dev_t dev; - ino_t ino; - pthread_rwlock_t rwlock; -} lock_entry; - -typedef struct { - pthread_mutex_t mutex; - size_t n_entries; - size_t n_max_entries; - lock_entry entries[]; -} file_locks; - -static char gf_runtime_locks[] = "/gf-runtime-locks"; - -static file_locks *locks = NULL; - -static -pthread_rwlock_t *ipc_rwlock_new(const char* file_path) -{ - int res; - - if (file_path == NULL) { - pthread_rwlock_t *rwlock = (pthread_rwlock_t *) - malloc(sizeof(pthread_rwlock_t)); - if (rwlock == NULL) - throw pgf_systemerror(ENOMEM); - if ((res = pthread_rwlock_init(rwlock, NULL)) != 0) { - throw pgf_systemerror(res); - } - return rwlock; - } - - if (locks == NULL) { - int created = 0; - - // Uncomment if you want a clean state - //shm_unlink(gf_runtime_locks); - - int fd = - shm_open(gf_runtime_locks, O_RDWR, 0); - if (errno == ENOENT) { - created = 1; - fd = shm_open(gf_runtime_locks, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); - } - if (fd < 0) { - throw pgf_systemerror(errno); - } - - int pagesize = getpagesize(); - - if (ftruncate(fd, pagesize) != 0) { - close(fd); - throw pgf_systemerror(errno); - } - - locks = (file_locks *) - mmap(NULL, pagesize, - PROT_READ|PROT_WRITE, - MAP_SHARED, - fd,0); - close(fd); - if (locks == MAP_FAILED) { - locks = NULL; - throw pgf_systemerror(errno); - } - - if (created) { - pthread_mutexattr_t attr; - if (pthread_mutexattr_init(&attr)) { - throw pgf_systemerror(errno); - } - if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) { - throw pgf_systemerror(errno); - } - if (pthread_mutex_init(&locks->mutex, &attr)) { - throw pgf_systemerror(errno); - } - pthread_mutexattr_destroy(&attr); - - locks->n_entries = 0; - locks->n_max_entries = (pagesize-sizeof(file_locks))/sizeof(lock_entry); - } - } - - struct stat s; - if (stat(file_path, &s) != 0) { - throw pgf_systemerror(errno); - } - - pthread_mutex_lock(&locks->mutex); - - lock_entry *entry = NULL; - for (size_t i = 0; i < locks->n_entries; i++) { - if (locks->entries[i].dev == 0 && locks->entries[i].ino == 0) { - entry = &locks->entries[i]; - } - if (locks->entries[i].dev == s.st_dev && locks->entries[i].ino == s.st_ino) { - entry = &locks->entries[i]; - break; - } - } - - if (entry == NULL) { - if (locks->n_entries >= locks->n_max_entries) { - pthread_mutex_unlock(&locks->mutex); - throw pgf_error("Too many open grammars"); - } - - entry = &locks->entries[locks->n_entries++]; - - pthread_rwlockattr_t attr; - if ((res = pthread_rwlockattr_init(&attr)) != 0) { - pthread_mutex_unlock(&locks->mutex); - throw pgf_systemerror(res); - } - if ((res = pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) != 0) { - pthread_rwlockattr_destroy(&attr); - pthread_mutex_unlock(&locks->mutex); - throw pgf_systemerror(res); - } - if ((res = pthread_rwlock_init(&entry->rwlock, &attr)) != 0) { - pthread_rwlockattr_destroy(&attr); - pthread_mutex_unlock(&locks->mutex); - throw pgf_systemerror(res); - } - pthread_rwlockattr_destroy(&attr); - } - - entry->dev = s.st_dev; - entry->ino = s.st_ino; - - pthread_mutex_unlock(&locks->mutex); - - return &entry->rwlock; -} - -static -void ipc_rwlock_destroy(const char* file_path, - pthread_rwlock_t *rwlock) -{ - if (file_path == NULL) { - pthread_rwlock_destroy(rwlock); - free(rwlock); - return; - } - - if (locks == NULL) - return; - - pthread_mutex_lock(&locks->mutex); - - for (size_t i = 0; i < locks->n_entries; i++) { - if (&locks->entries[i].rwlock == rwlock) { - locks->entries[i].dev = 0; - locks->entries[i].ino = 0; - break; - } - } - - pthread_mutex_unlock(&locks->mutex); -} - #else static @@ -208,255 +45,12 @@ PGF_INTERNAL __thread unsigned char* current_base __attribute__((tls_model("init PGF_INTERNAL __thread PgfDB* current_db __attribute__((tls_model("initial-exec"))) = NULL; PGF_INTERNAL __thread DB_scope *last_db_scope __attribute__((tls_model("initial-exec"))) = NULL; -#ifndef DEFAULT_TOP_PAD -#define DEFAULT_TOP_PAD (0) -#endif -#define ptr(ms,o) ((mchunk*) (((char*) (ms)) + (o))) -#define ofs(ms,p) (((char*) (p)) - ((char*) (ms))) - -struct mchunk { - size_t mchunk_prev_size; /* Size of previous chunk (if free). */ - size_t mchunk_size; /* Size in bytes, including overhead. */ - - object fd; /* double links -- used only if free. */ - object bk; - - /* Only used for large blocks: pointer to next larger size. */ - object fd_nextsize; /* double links -- used only if free. */ - object bk_nextsize; -}; - -#define POOL_ALIGNMENT (2 * sizeof(size_t) < __alignof__ (long double) \ - ? __alignof__ (long double) : 2 * sizeof(size_t)) - -/* - Bins - An array of bin headers for free chunks. Each bin is doubly - linked. The bins are approximately proportionally (log) spaced. - There are a lot of these bins (128). This may look excessive, but - works very well in practice. Most bins hold sizes that are - unusual as allocation request sizes, but are more usual for fragments - and consolidated sets of chunks, which is what these bins hold, so - they can be found quickly. All procedures maintain the invariant - that no consolidated chunk physically borders another one, so each - chunk in a list is known to be preceeded and followed by either - inuse chunks or the ends of memory. - Chunks in bins are kept in size order, with ties going to the - approximately least recently used chunk. Ordering isn't needed - for the small bins, which all contain the same-sized chunks, but - facilitates best-fit allocation for larger chunks. These lists - are just sequential. Keeping them in order almost never requires - enough traversal to warrant using fancier ordered data - structures. - Chunks of the same size are linked with the most - recently freed at the front, and allocations are taken from the - back. This results in LRU (FIFO) allocation order, which tends - to give each chunk an equal opportunity to be consolidated with - adjacent freed chunks, resulting in larger free chunks and less - fragmentation. - To simplify use in double-linked lists, each bin header acts - as an mchunk. This avoids special-casing for headers. - But to conserve space and improve locality, we allocate - only the fd/bk pointers of bins, and then use repositioning tricks - to treat these as the fields of a mchunk*. - */ - -typedef struct mchunk mbin; - -/* addressing -- note that bin_at(0) does not exist */ -#define bin_at(m, i) \ - (mbin*) (((char *) &((m)->bins[((i) - 1) * 2])) \ - - offsetof (mchunk, fd)) -/* analog of ++bin */ -#define next_bin(b) ((mbin*) ((char *) (b) + (sizeof(mchunk*) << 1))) -/* Reminders about list directionality within bins */ -#define first(b) ((b)->fd) -#define last(b) ((b)->bk) - -/* - Indexing - Bins for sizes < 512 bytes contain chunks of all the same size, spaced - 8 bytes apart. Larger bins are approximately logarithmically spaced: - 64 bins of size 8 - 32 bins of size 64 - 16 bins of size 512 - 8 bins of size 4096 - 4 bins of size 32768 - 2 bins of size 262144 - 1 bin of size what's left - There is actually a little bit of slop in the numbers in bin_index - for the sake of speed. This makes no difference elsewhere. - The bins top out around 1MB because we expect to service large - requests via mmap. - Bin 0 does not exist. Bin 1 is the unordered list; if that would be - a valid chunk size the small bins are bumped up one. - */ -#define NBINS 128 -#define NSMALLBINS 64 -#define SMALLBIN_WIDTH POOL_ALIGNMENT -#define SMALLBIN_CORRECTION (POOL_ALIGNMENT > 2 * sizeof(size_t)) -#define MIN_LARGE_SIZE ((NSMALLBINS - SMALLBIN_CORRECTION) * SMALLBIN_WIDTH) - -#define in_smallbin_range(sz) \ - ((unsigned long) (sz) < (unsigned long) MIN_LARGE_SIZE) -#define smallbin_index(sz) \ - ((SMALLBIN_WIDTH == 16 ? (((unsigned) (sz)) >> 4) : (((unsigned) (sz)) >> 3))\ - + SMALLBIN_CORRECTION) -#define largebin_index_32(sz) \ - (((((unsigned long) (sz)) >> 6) <= 38) ? 56 + (((unsigned long) (sz)) >> 6) :\ - ((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :\ - ((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\ - ((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\ - ((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\ - 126) -#define largebin_index_32_big(sz) \ - (((((unsigned long) (sz)) >> 6) <= 45) ? 49 + (((unsigned long) (sz)) >> 6) :\ - ((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :\ - ((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\ - ((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\ - ((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\ - 126) -// XXX It remains to be seen whether it is good to keep the widths of -// XXX the buckets the same or whether it should be scaled by a factor -// XXX of two as well. -#define largebin_index_64(sz) \ - (((((unsigned long) (sz)) >> 6) <= 48) ? 48 + (((unsigned long) (sz)) >> 6) :\ - ((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :\ - ((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\ - ((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\ - ((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\ - 126) -#define largebin_index(sz) \ - (sizeof(size_t) == 8 ? largebin_index_64 (sz) \ - : POOL_ALIGNMENT == 16 ? largebin_index_32_big (sz) \ - : largebin_index_32 (sz)) - - -/* - Unsorted chunks - All remainders from chunk splits, as well as all returned chunks, - are first placed in the "unsorted" bin. They are then placed - in regular bins after malloc gives them ONE chance to be used before - binning. So, basically, the unsorted_chunks list acts as a queue, - with chunks being placed on it in free (and pool_consolidate), - and taken off (to be either used or placed in bins) in malloc. - */ -/* The otherwise unindexable 1-bin is used to hold unsorted chunks. */ -#define unsorted_chunks(M) (bin_at (M, 1)) - -/* conversion from malloc headers to user pointers, and back */ -#define chunk2mem(p) ((void*)((char*)(p) + 2*sizeof(size_t))) -#define mem2chunk(mem) ((mchunk*)((char*)(mem) - 2*sizeof(size_t))) - -#define MIN_CHUNK_SIZE (offsetof(mchunk, fd_nextsize)) - -/* The smallest size we can malloc is an aligned minimal chunk */ -#define MINSIZE \ - (unsigned long)(((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)) +#define ptr(T,o) ((T*) (base + (o))) /* pad request bytes into a usable size -- internal version */ #define request2size(req) \ - (((req) + sizeof(size_t) + MALLOC_ALIGN_MASK < MINSIZE) ? \ - MINSIZE : \ - ((req) + sizeof(size_t) + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) - -/* - --------------- Physical chunk operations --------------- - */ -/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */ -#define PREV_INUSE 0x1 -/* extract inuse bit of previous chunk */ -#define prev_inuse(p) ((p)->mchunk_size & PREV_INUSE) - -/* Get size, ignoring use bits */ -#define chunksize(p) (p->mchunk_size & ~(PREV_INUSE)) - -/* Size of the chunk below P. Only valid if !prev_inuse (P). */ -#define prev_size(p) ((p)->mchunk_prev_size) - -/* Treat space at ptr + offset as a chunk */ -#define chunk_at_offset(p, s) ((mchunk*) (((char *) (p)) + (s))) - -/* extract p's inuse bit */ -#define inuse(p) \ - ((((mchunk*) (((char *) (p)) + chunksize(p)))->mchunk_size) & PREV_INUSE) - -/* check/set/clear inuse bits in known places */ -#define inuse_bit_at_offset(p, s) \ - (((mchunk*) (((char *) (p)) + (s)))->mchunk_size & PREV_INUSE) - -#define set_inuse_bit_at_offset(p, s) \ - (((mchunk*) (((char *) (p)) + (s)))->mchunk_size |= PREV_INUSE) - -#define clear_inuse_bit_at_offset(p, s) \ - (((mchunk*) (((char *) (p)) + (s)))->mchunk_size &= ~(PREV_INUSE)) - - -/* Set size at head, without disturbing its use bit */ -#define set_head_size(p, s) ((p)->mchunk_size = (((p)->mchunk_size & PREV_INUSE) | (s))) - -/* Set size/use field */ -#define set_head(p, s) ((p)->mchunk_size = (s)) - -/* Set size at footer (only when chunk is not in use) */ -#define set_foot(p, s) (((mchunk*) ((char *) (p) + (s)))->mchunk_prev_size = (s)) - -/* - Binmap - To help compensate for the large number of bins, a one-level index - structure is used for bin-by-bin searching. `binmap' is a - bitvector recording whether bins are definitely empty so they can - be skipped over during during traversals. The bits are NOT always - cleared as soon as bins are empty, but instead only - when they are noticed to be empty during traversal in malloc. - */ -/* Conservatively use 32 bits per map word, even if on 64bit system */ -#define BINMAPSHIFT 5 -#define BITSPERMAP (1U << BINMAPSHIFT) -#define BINMAPSIZE (NBINS / BITSPERMAP) - -#define idx2block(i) ((i) >> BINMAPSHIFT) -#define idx2bit(i) ((1U << ((i) & ((1U << BINMAPSHIFT) - 1)))) -#define mark_bin(ms, i) ((ms)->binmap[idx2block(i)] |= idx2bit (i)) -#define unmark_bin(ms, i) ((ms)->binmap[idx2block(i)] &= ~(idx2bit (i))) -#define get_binmap(ms, i) ((ms)->binmap[idx2block(i)] & idx2bit (i)) - -/* - Fastbins - An array of lists holding recently freed small chunks. Fastbins - are not doubly linked. It is faster to single-link them, and - since chunks are never removed from the middles of these lists, - double linking is not necessary. Also, unlike regular bins, they - are not even processed in FIFO order (they use faster LIFO) since - ordering doesn't much matter in the transient contexts in which - fastbins are normally used. - Chunks in fastbins keep their inuse bit set, so they cannot - be consolidated with other free chunks. malloc_consolidate - releases all chunks in fastbins and consolidates them with - other free chunks. - */ - -#define DEFAULT_MXFAST (64 * sizeof(size_t) / 4) - -/* offset 2 to use otherwise unindexable first 2 bins */ -#define fastbin_index(sz) \ - ((((unsigned int) (sz)) >> (sizeof(size_t) == 8 ? 4 : 3)) - 2) -/* The maximum fastbin request size we support */ -#define MAX_FAST_SIZE (80 * sizeof(size_t) / 4) -#define NFASTBINS (fastbin_index (request2size (MAX_FAST_SIZE)) + 1) - -/* - FASTBIN_CONSOLIDATION_THRESHOLD is the size of a chunk in free() - that triggers automatic consolidation of possibly-surrounding - fastbin chunks. This is a heuristic, so the exact value should not - matter too much. It is defined at half the default trim threshold as a - compromise heuristic to only attempt consolidation if it is likely - to lead to trimming. However, it is not dynamically tunable, since - consolidation reduces fragmentation surrounding large chunks even - if trimming is not used. - */ -#define FASTBIN_CONSOLIDATION_THRESHOLD (65536UL) + (((req) + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) static char slovo[5] = {'S','L','O','V','O'}; @@ -466,8 +60,22 @@ typedef struct { #else DWORD pid; #endif - object next; -} process_entry; + object o; + txn_t txn_id; + size_t ref_count; +} revision_entry; + +struct PGF_INTERNAL_DECL block_descr +{ + size_t sz; // the size of the binary tree + size_t block_size; // the size of the block + object o; // the block itself + object left; + object right; + object chain; // links descriptors that are not in use + txn_t block_txn_id; // transaction which released the block + txn_t descr_txn_id; // transaction which allocated the descriptor +}; struct PGF_INTERNAL_DECL malloc_state { @@ -477,37 +85,32 @@ struct PGF_INTERNAL_DECL malloc_state */ char sign[5]; - /* Set if the fastbin chunks contain recently inserted free blocks. */ - bool have_fastchunks; - /* Fastbins */ - object fastbins[NFASTBINS]; - /* Base of the topmost chunk -- not otherwise kept in a bin */ - object top; - /* The remainder from the most recent split of a small request */ - object last_remainder; - /* Normal bins packed as described above */ - object bins[NBINS * 2 - 2]; - /* Bitmap of bins */ - unsigned int binmap[BINMAPSIZE]; - + /* The current size is used to detect when the file was resized + * by another process. The file size doesn't include the first 4K */ size_t file_size; - /* The namespace of all persistant grammar revisions */ - Namespace revisions; - - /* A reference to the first transient revisions in - * a double-linked list. - */ - ref transient_revisions; - ref transient_concr_revisions; - -#ifdef _WIN32 +#ifndef _WIN32 + pthread_mutex_t mutex; + pthread_rwlock_t rwlock; +#else /* Stores a Reader/Writer lock for Windows */ LONG rwlock; #endif - process_entry p; + + txn_t curr_txn_id; + txn_t min_txn_id; + + /* The top address that is not allocated yet. */ + object top; + object free_blocks; // a binary tree of descriptors for free blocks + object free_descriptors; + + size_t n_revisions; + object active_revision; + revision_entry revisions[]; }; + PGF_INTERNAL PgfDB::PgfDB(const char* filepath, int flags, int mode) { bool is_new = false; @@ -515,10 +118,12 @@ PgfDB::PgfDB(const char* filepath, int flags, int mode) { fd = -1; ms = NULL; ref_count = 0; + page_size = getpagesize(); + pid = getpid(); if (filepath == NULL) { this->filepath = NULL; - mmap_size = getpagesize(); + mmap_size = page_size*2; is_new = true; } else { fd = open(filepath, flags, mode); @@ -534,7 +139,7 @@ PgfDB::PgfDB(const char* filepath, int flags, int mode) { is_new = false; if (mmap_size == 0) { - mmap_size = getpagesize(); + mmap_size = page_size*2; if (ftruncate(fd, mmap_size) < 0) { int code = errno; close(fd); @@ -544,6 +149,10 @@ PgfDB::PgfDB(const char* filepath, int flags, int mode) { } this->filepath = strdup(filepath); + if (this->filepath == NULL) { + close(fd); + throw pgf_systemerror(ENOMEM); + } } int code = 0; @@ -552,23 +161,44 @@ PgfDB::PgfDB(const char* filepath, int flags, int mode) { if (fd >= 0) { ms = (malloc_state*) mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - code = errno; + if (ms == MAP_FAILED) { + code = errno; + ms = NULL; // mark that ms is not created. + base = NULL; + ::free((void *) this->filepath); + close(fd); + throw pgf_systemerror(code, filepath); + } + + mmap_size -= page_size; + base = ((unsigned char *) ms) + page_size; } else { - ms = (malloc_state*) ::malloc(mmap_size); - code = ENOMEM; + ms = (malloc_state*) ::malloc(page_size); + if (ms == NULL) + throw pgf_systemerror(ENOMEM); + + mmap_size -= page_size; + + base = ::malloc(mmap_size); + if (base == NULL) + throw pgf_systemerror(ENOMEM); } #else int mflags = (fd < 0) ? (MAP_PRIVATE | MAP_ANONYMOUS) : MAP_SHARED; ms = (malloc_state*) mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, mflags, fd, 0); - code = errno; -#endif - if (ms == MAP_FAILED || ms == NULL) { + if (ms == MAP_FAILED) { + code = errno; ms = NULL; // mark that ms is not created. + base = NULL; ::free((void *) this->filepath); close(fd); throw pgf_systemerror(code, filepath); } + + mmap_size -= page_size; + base = ((unsigned char *) ms) + page_size; +#endif #else char *name; char buf[256]; @@ -599,24 +229,26 @@ PgfDB::PgfDB(const char* filepath, int flags, int mode) { if (ms == NULL) { code = last_error_to_errno(); CloseHandle(hMap); - hMap = INVALID_HANDLE_VALUE; + ::free((void *) this->filepath); + close(fd); + throw pgf_systemerror(code, filepath); } + mmap_size -= page_size; + base = ((unsigned char *) ms) + page_size; } else { code = last_error_to_errno(); - hMap = INVALID_HANDLE_VALUE; - ms = NULL; + ::free((void *) this->filepath); + close(fd); + throw pgf_systemerror(code, filepath); } } else { - code = ENOMEM; name = NULL; hMap = INVALID_HANDLE_VALUE; ms = (malloc_state*) ::malloc(mmap_size); - } - - if (ms == NULL) { - ::free((void *) this->filepath); - close(fd); - throw pgf_systemerror(code, filepath); + if (ms == NULL) + throw pgf_systemerror(ENOMEM); + mmap_size -= page_size; + base = ((unsigned char *) ms) + page_size; } hRWEvent = CreateEvent(NULL, FALSE, FALSE, name); @@ -633,21 +265,42 @@ PgfDB::PgfDB(const char* filepath, int flags, int mode) { } #endif + if (is_new) { + code = init_state(); + if (code != 0) { #ifndef _WIN32 - rwlock = ipc_rwlock_new(filepath); +#ifndef MREMAP_MAYMOVE + if (fd < 0) { + ::free(ms); + ::free(base); + } else +#endif + munmap(ms,page_size+mmap_size); +#else + if (fd < 0) { + ::free(ms); + } else { + UnmapViewOfFile(ms); + CloseHandle(hMap); + } + CloseHandle(hRWEvent); #endif - if (is_new) { - init_state(mmap_size); + ::free((void *) this->filepath); + close(fd); + + throw pgf_systemerror(code, filepath); + } } else { if (strncmp(ms->sign, slovo, sizeof(ms->sign)) != 0) { #ifndef _WIN32 #ifndef MREMAP_MAYMOVE if (fd < 0) { ::free(ms); + ::free(base); } else #endif - munmap(ms,mmap_size); + munmap(ms,page_size+mmap_size); #else if (fd < 0) { ::free(ms); @@ -663,41 +316,42 @@ PgfDB::PgfDB(const char* filepath, int flags, int mode) { throw pgf_error("Invalid file content"); } - register_process(); + cleanup_revisions(); } + + top = ms->top; + free_blocks = ms->free_blocks; + free_descriptors[0] = ms->free_descriptors; + free_descriptors[1] = 0; } PGF_INTERNAL PgfDB::~PgfDB() { - if (ms != NULL) { - unregister_process(); - -#ifndef _WIN32 - if (ms->p.pid == 0) - ipc_rwlock_destroy(filepath, rwlock); -#endif - - size_t size = - ms->top + chunksize(ptr(ms,ms->top)) + sizeof(size_t); - #ifndef _WIN32 #ifndef MREMAP_MAYMOVE - if (fd < 0) { - ::free(ms); - } else -#endif - munmap(ms,size); -#else - if (fd < 0) { - ::free(ms); - } else { - UnmapViewOfFile(ms); - CloseHandle(hMap); - } - CloseHandle(hRWEvent); + if (fd < 0) { + pthread_rwlock_destroy(ms->rwlock); + pthread_mutex_destroy(ms->mutex); + ::free(ms); + ::free(base); + } else #endif + { + if (ms != NULL) + munmap(ms,sizeof(*ms)); + if (base != NULL) + munmap(base,mmap_size); } +#else + if (fd < 0) { + ::free(ms); + } else { + UnmapViewOfFile(ms); + CloseHandle(hMap); + } + CloseHandle(hRWEvent); +#endif if (fd >= 0) close(fd); @@ -706,925 +360,819 @@ PgfDB::~PgfDB() } PGF_INTERNAL -void PgfDB::register_process() -{ - process_entry *pentry = &ms->p; - object *plast = NULL; +txn_t PgfDB::get_txn_id() { + return current_db->ms->curr_txn_id; +} - if (ms->p.pid != 0) { - while (pentry != (process_entry *) ptr(ms,0)) { +PGF_INTERNAL +void PgfDB::register_revision(object o) +{ + pthread_mutex_lock(&ms->mutex); + + revision_entry *free_entry = NULL; + + for (size_t i = 0; i < ms->n_revisions; i++) { + if (ms->revisions[i].ref_count == 0) { + if (free_entry == NULL) + free_entry = &ms->revisions[i]; + } else if (ms->revisions[i].pid == pid && + ms->revisions[i].o == o) { + ms->revisions[i].ref_count++; + goto done; + } + } + + if (free_entry == NULL) { + size_t n_max = (page_size-sizeof(malloc_state))/sizeof(revision_entry); + if (ms->n_revisions >= n_max) { + pthread_mutex_unlock(&ms->mutex); + throw pgf_error("Too many retained database revisions"); + } + free_entry = &ms->revisions[ms->n_revisions++]; + } + + free_entry->pid = pid; + free_entry->o = o; + free_entry->ref_count = 1; + free_entry->txn_id = ms->curr_txn_id; + +done: + pthread_mutex_unlock(&ms->mutex); +} + +PGF_INTERNAL +void PgfDB::unregister_revision(object o) +{ + pthread_mutex_lock(&ms->mutex); + + revision_entry *free_entry = NULL; + + ms->min_txn_id = SIZE_MAX; + for (size_t i = 0; i < ms->n_revisions; i++) { + revision_entry *entry = &ms->revisions[i]; + if (entry->ref_count > 0) { + if (entry->pid == pid && entry->o == o) { + if (--entry->ref_count == 0) { + // Maybe this was the last revision in the list. + // Decrement n_revisions if possible. + while (ms->revisions[ms->n_revisions-1].ref_count == 0){ + ms->n_revisions--; + } + continue; // We skip the update of min_txn_id + } + } + + if (ms->min_txn_id > entry->txn_id) + ms->min_txn_id = entry->txn_id; + } + } + + pthread_mutex_unlock(&ms->mutex); +} + +void PgfDB::cleanup_revisions() +{ + pthread_mutex_lock(&ms->mutex); + + ms->min_txn_id = SIZE_MAX; + // If there are dead processes, set their reference counts to 0. + for (size_t i = 0; i < ms->n_revisions; i++) { + revision_entry *entry = &ms->revisions[i]; + if (entry->ref_count > 0) { #ifndef _WIN32 char proc_file[32]; - sprintf(proc_file, "/proc/%d", pentry->pid); + sprintf(proc_file, "/proc/%d", entry->pid); bool alive = (access(proc_file, F_OK) == 0); #else HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, - FALSE,pentry->pid); + FALSE,entry->pid); DWORD dwExitCode = STILL_ACTIVE; if (hProcess != NULL) GetExitCodeProcess(hProcess,&dwExitCode); bool alive = (dwExitCode == STILL_ACTIVE); CloseHandle(hProcess); #endif - if (!alive) { - // if there are dead processes -> remove them - if (plast == NULL) { - if (ms->p.next == 0) { - ms->p.pid = 0; - break; - } else { - object next = pentry->next; - *pentry = *((process_entry *) ptr(ms,next)); - free_internal(next); - } - } else { - *plast = pentry->next; - free_internal(ofs(ms,pentry)); - pentry = (process_entry *) ptr(ms, *plast); - } + + if (alive) { + if (ms->min_txn_id > entry->txn_id) + ms->min_txn_id = entry->txn_id; } else { - plast = &pentry->next; - pentry = (process_entry *) ptr(ms, *plast); + entry->ref_count = 0; } } } - if (plast != NULL) { - *plast = malloc_internal(sizeof(process_entry)); - pentry = (process_entry*) ptr(ms,*plast); - pentry->next = 0; - } - pentry->pid = getpid(); + pthread_mutex_unlock(&ms->mutex); } PGF_INTERNAL -void PgfDB::unregister_process() +object PgfDB::get_active_revision() { - auto pid = getpid(); - process_entry *pentry = &ms->p; - object *plast = NULL; - - while (pentry != (process_entry *) ptr(ms,0)) { - if (pentry->pid == pid) { - if (plast == NULL) { - if (ms->p.next == 0) { - ms->p.pid = 0; - } else { - object next = pentry->next; - *pentry = *((process_entry *) ptr(ms,next)); - free_internal(next); - } - } else { - *plast = pentry->next; - free_internal(ofs(ms,pentry)); - pentry = (process_entry *) ptr(ms, *plast); - } - break; - } else { - plast = &pentry->next; - pentry = (process_entry *) ptr(ms, *plast); - } - } -} - -void PgfDB::cleanup_revisions() -{ - if (ms->p.next == 0) { - // The first process that opens this file makes sure that - // left-over transient revisions are released. - // They may be left-over of a client process that was killed - // or if the garbadge collector has not managed to run - // pgf_release_revision() before the process ended. - - while (ms->transient_revisions != 0) { - pgf_free_revision(this, ms->transient_revisions.as_object()); - ref pgf = ms->transient_revisions; - ref next = pgf->next; - PgfPGF::release(pgf); - ms->transient_revisions = next; - } - - while (ms->transient_concr_revisions != 0) { - ref concr = ms->transient_concr_revisions; - ref next = concr->next; - concr->ref_count -= concr->ref_count_ex; - if (!concr->ref_count) { - PgfConcr::release(concr); - } - ms->transient_concr_revisions = next; - } - } + return current_db->ms->active_revision; } PGF_INTERNAL -ref PgfDB::get_revision(PgfText *name) +void PgfDB::set_active_revision(object o) { - return namespace_lookup(current_db->ms->revisions, name); + current_db->ms->active_revision = o; } PGF_INTERNAL -void PgfDB::set_revision(ref pgf) -{ - pgf->ref_count++; - Namespace nmsp = namespace_insert(current_db->ms->revisions, pgf); - namespace_release(current_db->ms->revisions); - current_db->ms->revisions = nmsp; -} - -PGF_INTERNAL -void PgfDB::init_state(size_t size) +int PgfDB::init_state() { memcpy(ms->sign, slovo, sizeof(ms->sign)); - /* Init fastbins */ - ms->have_fastchunks = false; - for (int i = 0; i < NFASTBINS; ++i) { - ms->fastbins[i] = 0; - } - - size_t sz = (sizeof(*ms) + sizeof(size_t)); - sz = (sz & ~MALLOC_ALIGN_MASK) + MALLOC_ALIGN_MASK + 1; - - mchunk* top_chunk = mem2chunk(((char*) ms) + sz); - ms->top = ofs(ms,top_chunk); - set_head(top_chunk, (size - (sz - sizeof(size_t))) | PREV_INUSE); - - ms->last_remainder = 0; - - /* Establish circular links for normal bins */ - for (int i = 1; i < NBINS; ++i) { - mbin *bin = bin_at(ms, i); - bin->fd = bin->bk = ofs(ms,bin); - } - - memset(ms->binmap, 0, sizeof(ms->binmap)); - - ms->file_size = size; - - ms->revisions = 0; - ms->transient_revisions = 0; - ms->transient_concr_revisions = 0; + ms->top = request2size(1); // we don't want to start from 0 + ms->file_size = mmap_size; #ifdef _WIN32 ms->rwlock = 0; +#else + int res; + + { + pthread_mutexattr_t attr; + if ((res = pthread_mutexattr_init(&attr)) != 0) { + return res; + } + if ((res = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) != 0) { + return res; + } + if ((res = pthread_mutex_init(&ms->mutex, &attr)) != 0) { + return res; + } + pthread_mutexattr_destroy(&attr); + } + + { + pthread_rwlockattr_t attr; + if ((res = pthread_rwlockattr_init(&attr)) != 0) { + return res; + } + if (fd >= 0 && + (res = pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) != 0) { + pthread_rwlockattr_destroy(&attr); + return res; + } + if ((res = pthread_rwlock_init(&ms->rwlock, &attr)) != 0) { + pthread_rwlockattr_destroy(&attr); + return res; + } + pthread_rwlockattr_destroy(&attr); + } #endif - ms->p.pid = getpid(); - ms->p.next = 0; + + ms->curr_txn_id = 0; + ms->min_txn_id = 0; + ms->free_blocks = 0; + ms->free_descriptors = 0; + ms->n_revisions = 0; + return 0; } -/* Take a chunk off a bin list. */ -static void -unlink_chunk (malloc_state* ms, mchunk* p) +PGF_INTERNAL +size_t PgfDB::block_descr_size(object map) { - mchunk* fd = ptr(ms,p->fd); - mchunk* bk = ptr(ms,p->bk); - fd->bk = ofs(ms,bk); - bk->fd = ofs(ms,fd); - if (!in_smallbin_range(p->mchunk_size) && p->fd_nextsize != 0) { - if (fd->fd_nextsize == 0) { - if (p->fd_nextsize == ofs(ms,p)) - fd->fd_nextsize = fd->bk_nextsize = ofs(ms,fd); - else { - fd->fd_nextsize = p->fd_nextsize; - fd->bk_nextsize = p->bk_nextsize; - ptr(ms,p->fd_nextsize)->bk_nextsize = ofs(ms,fd); - ptr(ms,p->bk_nextsize)->fd_nextsize = ofs(ms,fd); + if (map == 0) + return 0; + return ptr(block_descr, map)->sz; +} + +PGF_INTERNAL_DECL object PgfDB::new_block_descr(object o, size_t size) +{ + object odescr; + block_descr *descr; + + if (free_descriptors[0] != 0) { + odescr = free_descriptors[0]; + descr = ptr(block_descr, odescr); + free_descriptors[0] = descr->chain; + } else { + size_t block_size = request2size(sizeof(block_descr)); + + size_t free_size = mmap_size - top; + if (block_size > free_size) { + size_t alloc_size = + ((block_size - free_size + page_size - 1) / page_size) * page_size; + size_t new_size = + ms->file_size + alloc_size; + + resize_map(new_size); + } + + odescr = top; + top += block_size; + + descr = ptr(block_descr, odescr); + } + + descr->sz = 1; + descr->left = 0; + descr->right = 0; + descr->chain = 0; + descr->o = o; + descr->block_size = size; + descr->block_txn_id = ms->curr_txn_id; + descr->descr_txn_id = ms->curr_txn_id; + + return odescr; +} + +PGF_INTERNAL +object PgfDB::upd_block_descr(object map, object left, object right) +{ + block_descr *descr = ptr(block_descr, map); + + if (descr->descr_txn_id != ms->curr_txn_id) { + block_descr *new_descr; + + descr->chain = free_descriptors[1]; + free_descriptors[1] = map; + + if (free_descriptors[0] != 0) { + map = free_descriptors[0]; + new_descr = ptr(block_descr, map); + free_descriptors[0] = new_descr->chain; + } else { + size_t block_size = request2size(sizeof(block_descr)); + + size_t free_size = mmap_size - top; + if (block_size > free_size) { + size_t alloc_size = + ((block_size - free_size + page_size - 1) / page_size) * page_size; + size_t new_size = + ms->file_size + alloc_size; + + resize_map(new_size); + + // refresh the pointer + descr = ptr(block_descr, map); } - } else { - ptr(ms,p->fd_nextsize)->bk_nextsize = p->bk_nextsize; - ptr(ms,p->bk_nextsize)->fd_nextsize = p->fd_nextsize; + + map = top; + top += block_size; + + new_descr = ptr(block_descr, map); } + + new_descr->o = descr->o; + new_descr->chain = 0; + new_descr->block_txn_id = descr->block_txn_id; + new_descr->descr_txn_id = ms->curr_txn_id; + + descr = new_descr; } + + descr->sz = 1+block_descr_size(left)+block_descr_size(right); + descr->left = left; + descr->right = right; + + return map; } -/* - ------------------------- malloc_consolidate ------------------------- - malloc_consolidate is a specialized version of free() that tears - down chunks held in fastbins. Free itself cannot be used for this - purpose since, among other things, it might place chunks back onto - fastbins. So, instead, we need to use a minor variant of the same - code. -*/ -static void malloc_consolidate(malloc_state *ms) +PGF_INTERNAL +object PgfDB::balanceL_block_descriptor(object map) { - object* fb; /* current fastbin being consolidated */ - object* maxfb; /* last fastbin (for loop control) */ - mchunk* p; /* current chunk being consolidated */ - object next_fb; /* next chunk to consolidate */ - mchunk* unsorted_bin; /* bin header */ - mchunk* first_unsorted; /* chunk to link to */ - /* These have same use as in free() */ - mchunk* nextchunk; - size_t size; - size_t nextsize; - size_t prevsize; - int nextinuse; - - ms->have_fastchunks = false; - unsorted_bin = unsorted_chunks(ms); - /* - Remove each chunk from fast bin and consolidate it, placing it - then in unsorted bin. Among other reasons for doing this, - placing in unsorted bin avoids needing to calculate actual bins - until malloc is sure that chunks aren't immediately going to be - reused anyway. - */ - maxfb = &ms->fastbins[NFASTBINS - 1]; - fb = &ms->fastbins[0]; - do { - if (*fb != 0) { - p = ptr(ms,*fb); - *fb = 0; - for (;;) { - next_fb = p->fd; - /* Slightly streamlined version of consolidation code in free() */ - size = chunksize(p); - nextchunk = chunk_at_offset(p, size); - nextsize = chunksize(nextchunk); - if (!prev_inuse(p)) { - prevsize = prev_size(p); - size += prevsize; - p = chunk_at_offset(p, -((long) prevsize)); - unlink_chunk (ms, p); - } - if (nextchunk != ptr(ms,ms->top)) { - nextinuse = inuse_bit_at_offset(nextchunk, nextsize); - if (!nextinuse) { - size += nextsize; - unlink_chunk (ms, nextchunk); - } else - clear_inuse_bit_at_offset(nextchunk, 0); - first_unsorted = ptr(ms,unsorted_bin->fd); - unsorted_bin->fd = ofs(ms,p); - first_unsorted->bk = ofs(ms,p); - if (!in_smallbin_range(size)) { - p->fd_nextsize = 0; - p->bk_nextsize = 0; - } - set_head(p, size | PREV_INUSE); - p->bk = ofs(ms,unsorted_bin); - p->fd = ofs(ms,first_unsorted); - set_foot(p, size); + block_descr *descr = ptr(block_descr, map); + if (descr->right == 0) { + if (descr->left == 0) { + return map; } else { - size += nextsize; - set_head(p, size | PREV_INUSE); - ms->top = ofs(ms,p); + block_descr *left = ptr(block_descr, descr->left); + if (left->left == 0) { + if (left->right == 0) { + return map; + } else { + object left_right = left->right; + object left = upd_block_descr(descr->left,0,0); + object right = upd_block_descr(map,0,0); + return upd_block_descr(left_right, + left, + right); + } + } else { + if (left->right == 0) { + object left_left = left->left; + object left = descr->left; + object right = upd_block_descr(map,0,0); + return upd_block_descr(left, + left_left, + right); + } else { + object left_left = left->left; + object left_right = left->right; + if (ptr(block_descr, left_right)->sz < 2 * ptr(block_descr, left_left)->sz) { + object left = descr->left; + object right = + upd_block_descr(map, + left_right, + 0); + return upd_block_descr(left, + left_left, + right); + } else { + object left = + upd_block_descr(descr->left, + left_left, + ptr(block_descr, left_right)->left); + object right = + upd_block_descr(map, + ptr(block_descr, left_right)->right, + 0); + return upd_block_descr(left_right, + left, + right); + } + } + } } + } else { + if (descr->left == 0) { + return map; + } else { + if (ptr(block_descr, descr->left)->sz > 3*ptr(block_descr, descr->right)->sz) { + block_descr *left = ptr(block_descr, descr->left); + object left_left = left->left; + object left_right = left->right; - if (next_fb == 0) - break; - p = ptr(ms,next_fb); - } + if (ptr(block_descr, left_right)->sz < 2*ptr(block_descr, left_left)->sz) { + object left = descr->left; + object right = + upd_block_descr(map, + left_right, + descr->right); + return upd_block_descr(left, + left_left, + right); + } else { + object left = + upd_block_descr(descr->left, + left_left, + ptr(block_descr, left_right)->left); + object right = + upd_block_descr(map, + ptr(block_descr, left_right)->right, + ptr(block_descr, map)->right); + return upd_block_descr(left_right, + left, + right); + } + } else { + return map; + } + } } - } while (fb++ != maxfb); } +PGF_INTERNAL +object PgfDB::balanceR_block_descriptor(object map) +{ + block_descr *descr = ptr(block_descr, map); + if (descr->left == 0) { + if (descr->right == 0) { + return map; + } else { + block_descr *right = ptr(block_descr, descr->right); + if (right->left == 0) { + if (right->right == 0) { + return map; + } else { + object right_right = right->right; + object right = descr->right; + object left = + upd_block_descr(map, + 0, + 0); + return upd_block_descr(right, + left, + right_right); + } + } else { + if (right->right == 0) { + object right_left = right->left; + object right = + upd_block_descr(descr->right,0,0); + object left = + upd_block_descr(map,0,0); + return upd_block_descr(right_left, + left, + right); + } else { + object right_left = right->left; + object right_right = right->right; + if (ptr(block_descr,right_left)->sz < 2 * ptr(block_descr,right_right)->sz) { + object right = descr->right; + object left = + upd_block_descr(map, + 0, + right_left); + return upd_block_descr(right, + left, + right_right); + } else { + object right = + upd_block_descr(descr->right, + ptr(block_descr,right_left)->right, + right_right); + object left = + upd_block_descr(map, + 0, + ptr(block_descr,right_left)->left); + return upd_block_descr(right_left, + left, + right); + } + } + } + } + } else { + if (descr->right == 0) { + return map; + } else { + if (ptr(block_descr,descr->right)->sz > 3*ptr(block_descr,descr->left)->sz) { + block_descr *right = ptr(block_descr,descr->right); + object right_left = right->left; + object right_right = right->right; + if (ptr(block_descr,right_left)->sz < 2*ptr(block_descr,right_right)->sz) { + object right = descr->right; + object left = + upd_block_descr(map, + descr->left, + right_left); + return upd_block_descr(right, + left, + right_right); + } else { + object right = + upd_block_descr(descr->right, + ptr(block_descr,right_left)->right, + right_right); + object left = + upd_block_descr(map, + descr->left, + ptr(block_descr,right_left)->left); + return upd_block_descr(right_left, + left, + right); + } + } else { + return map; + } + } + } +} + +PGF_INTERNAL +object PgfDB::pop_first_block_descriptor(object map, object *res) +{ + block_descr *descr = ptr(block_descr, map); + if (map == 0) { + return 0; + } else if (descr->left == 0) { + *res = map; + return descr->right; + } else { + object right = descr->right; + object left = pop_first_block_descriptor(descr->left, res); + map = upd_block_descr(map, left, right); + return balanceR_block_descriptor(map); + } +} + +PGF_INTERNAL +object PgfDB::pop_last_block_descriptor(object map, object *res) +{ + block_descr *descr = ptr(block_descr, map); + if (map == 0) { + return 0; + } else if (descr->right == 0) { + *res = map; + return descr->left; + } else { + object left = descr->left; + object right = pop_last_block_descriptor(descr->right, res); + map = upd_block_descr(map, left, right); + return balanceL_block_descriptor(map); + } +} + +PGF_INTERNAL +object PgfDB::delete_block_descriptor(object map, size_t *psize, object *po) +{ + if (map == 0) { + *po = 0; + return 0; + } + + block_descr *descr = ptr(block_descr, map); + int cmp = (*psize < descr->block_size) ? -1 + : (*psize > descr->block_size) ? 1 + : (descr->block_txn_id > ms->min_txn_id) ? -1 + : 0; + if (cmp < 0) { + object right = descr->right; + object left = delete_block_descriptor(descr->left, psize, po); + if (*po != 0) { + map = upd_block_descr(map,left,right); + map = balanceR_block_descriptor(map); + } else { + descr = ptr(block_descr, map); + if (descr->block_txn_id < ms->min_txn_id) { + *psize = descr->block_size; + goto fit; + } + } + return map; + } else if (cmp > 0) { + object left = descr->left; + object right = delete_block_descriptor(descr->right, psize, po); + if (*po != 0) { + map = upd_block_descr(map,left,right); + map = balanceL_block_descriptor(map); + } + return map; + } else { +fit: + *po = descr->o; + + int index = (descr->descr_txn_id != ms->curr_txn_id); + descr->chain = free_descriptors[index]; + free_descriptors[index] = map; + + if (descr->left == 0) { + return descr->right; + } else if (descr->right == 0) { + return descr->left; + } else { + if (ptr(block_descr,descr->left)->sz > ptr(block_descr,descr->right)->sz) { + object right = descr->right; + object left = pop_last_block_descriptor(descr->left, &map); + map = upd_block_descr(map, left, right); + return balanceR_block_descriptor(map); + } else { + object left = descr->left; + object right = pop_first_block_descriptor(descr->right, &map); + map = upd_block_descr(map, left, right); + return balanceL_block_descriptor(map); + } + } + } +} + +#ifdef DEBUG_MEMORY_ALLOCATOR +PGF_INTERNAL void PgfDB::dump_free_blocks(object map) +{ + if (map == 0) { + printf("."); + return; + } + + block_descr *descr = ptr(block_descr, map); + if (descr->left != 0 || descr->right != 0) { + printf("("); + dump_free_blocks(descr->left); + printf(" "); + } + + printf("[%016lx %ld %ld]", descr->o, descr->block_size, descr->block_txn_id); + + if (descr->left != 0 || descr->right != 0) { + printf(" "); + dump_free_blocks(descr->right); + printf(")"); + } +} +#endif + PGF_INTERNAL object PgfDB::malloc_internal(size_t bytes) { - unsigned int idx; /* associated bin index */ - mbin* bin; /* associated bin */ - mchunk* victim; /* inspected/selected chunk */ + size_t block_size = request2size(bytes); - mchunk* remainder; /* remainder from a split */ - unsigned long remainder_size; /* its size */ - - /* - Convert request size to internal form by adding SIZE_SZ bytes - overhead plus possibly more to obtain necessary alignment and/or - to obtain a size of at least MINSIZE, the smallest allocatable - size. Also, checked_request2size traps (returning 0) request sizes - that are so large that they wrap around zero when padded and - aligned. - */ - size_t nb = request2size(bytes); - - if (nb <= DEFAULT_MXFAST) { - idx = fastbin_index(nb); - - if (ms->fastbins[idx] != 0) { - victim = ptr(ms,ms->fastbins[idx]); - ms->fastbins[idx] = victim->fd; - return ofs(ms,chunk2mem(victim)); + object o; + size_t alloc_size = block_size; + free_blocks = delete_block_descriptor(free_blocks, &alloc_size, &o); + if (o != 0) { + if (alloc_size > block_size) { + free_blocks = insert_block_descriptor(free_blocks, o+block_size, alloc_size-block_size); } + +#ifdef DEBUG_MEMORY_ALLOCATOR + dump_free_blocks(free_blocks); + printf("\n"); +#endif + + return o; } - /* - If a small request, check regular bin. Since these "smallbins" - hold one size each, no searching within bins is necessary. - (For a large request, we need to wait until unsorted chunks are - processed to find best fit. But for small ones, fits are exact - anyway, so we can check now, which is faster.) - */ - if (in_smallbin_range (nb)) { - idx = smallbin_index (nb); - bin = bin_at (ms, idx); - if ((victim = ptr(ms,last(bin))) != bin) - { - object bck = victim->bk; - set_inuse_bit_at_offset (victim, nb); - bin->bk = bck; - ptr(ms,bck)->fd = ofs(ms,bin); - return ofs(ms,chunk2mem(victim)); - } - } else { - /* - If this is a large request, consolidate fastbins before continuing. - While it might look excessive to kill all fastbins before - even seeing if there is space available, this avoids - fragmentation problems normally associated with fastbins. - Also, in practice, programs tend to have runs of either small or - large requests, but less often mixtures, so consolidation is not - invoked all that often in most programs. And the programs that - it is called frequently in otherwise tend to fragment. - */ + size_t free_size = mmap_size - top; + if (block_size > free_size) { + size_t alloc_size = + ((block_size - free_size + page_size - 1) / page_size) * page_size; + size_t new_size = + ms->file_size + alloc_size; - idx = largebin_index(nb); - if (ms->have_fastchunks) - malloc_consolidate(ms); + resize_map(new_size); } - /* - Process recently freed or remaindered chunks, taking one only if - it is exact fit, or, if this a small request, the chunk is remainder from - the most recent non-exact fit. Place other traversed chunks in - bins. Note that this step is the only place in any routine where - chunks are placed in bins. - The outer loop here is needed because we might not realize until - near the end of malloc that we should have consolidated, so must - do so and retry. This happens at most once, and only when we would - otherwise need to expand memory to service a "small" request. - */ - for (;;) - { - size_t size; - mchunk *fwd, *bck; + o = top; + top += block_size; - int iters = 0; - while ((victim = ptr(ms,unsorted_chunks(ms)->bk)) != unsorted_chunks(ms)) { - bck = ptr(ms,victim->bk); - size = chunksize(victim); - mchunk *next = chunk_at_offset(victim, size); + return o; +} - /* - If a small request, try to use last remainder if it is the - only chunk in unsorted bin. This helps promote locality for - runs of consecutive small requests. This is the only - exception to best-fit, and applies only when there is - no exact fit for a small chunk. - */ +PGF_INTERNAL +object PgfDB::realloc_internal(object oldo, size_t old_bytes, size_t new_bytes) +{ + if (oldo == 0) + return malloc_internal(new_bytes); - if (in_smallbin_range(nb) && - bck == unsorted_chunks(ms) && - victim == ptr(ms,ms->last_remainder) && - (unsigned long) (size) > (unsigned long) (nb + MINSIZE)) { + size_t old_nb = request2size(old_bytes); + size_t new_nb = request2size(new_bytes); - /* split and reattach remainder */ - remainder_size = size - nb; - remainder = chunk_at_offset(victim, nb); - ms->last_remainder = - unsorted_chunks(ms)->bk = - unsorted_chunks(ms)->fd = ofs(ms,remainder); - remainder->bk = remainder->fd = ofs(ms,unsorted_chunks(ms)); - if (!in_smallbin_range(remainder_size)) { - remainder->fd_nextsize = 0; - remainder->bk_nextsize = 0; - } - set_head(victim, nb | PREV_INUSE); - set_head(remainder, remainder_size | PREV_INUSE); - set_foot(remainder, remainder_size); - return ofs(ms,chunk2mem(victim)); - } + if (oldo + old_nb == top) { + ssize_t nb = new_nb-old_nb; + ssize_t free_size = mmap_size - top; - /* remove from unsorted list */ - unsorted_chunks(ms)->bk = ofs(ms,bck); - bck->fd = ofs(ms,unsorted_chunks(ms)); - - /* Take now instead of binning if exact fit */ - if (size == nb) { - set_inuse_bit_at_offset(victim, size); - return ofs(ms,chunk2mem(victim)); - } - - /* place chunk in bin */ - size_t victim_index; - if (in_smallbin_range(size)) { - victim_index = smallbin_index(size); - bck = bin_at(ms, victim_index); - fwd = ptr(ms,bck->fd); - } else { - victim_index = largebin_index(size); - bck = bin_at(ms, victim_index); - fwd = ptr(ms,bck->fd); - - /* maintain large bins in sorted order */ - if (fwd != bck) { - /* Or with inuse bit to speed comparisons */ - size |= PREV_INUSE; - /* if smaller than smallest, bypass loop below */ - if ((unsigned long) (size) < (unsigned long) ptr(ms,bck->bk)->mchunk_size) { - fwd = bck; - bck = ptr(ms,bck->bk); - victim->fd_nextsize = fwd->fd; - victim->bk_nextsize = ptr(ms,fwd->fd)->bk_nextsize; - ptr(ms,fwd->fd)->bk_nextsize = ptr(ms,victim->bk_nextsize)->fd_nextsize = ofs(ms,victim); - } else { - while ((unsigned long) size < fwd->mchunk_size) { - fwd = ptr(ms,fwd->fd_nextsize); - } - if ((unsigned long) size == (unsigned long) fwd->mchunk_size) - /* Always insert in the second position. */ - fwd = ptr(ms,fwd->fd); - else { - victim->fd_nextsize = ofs(ms,fwd); - victim->bk_nextsize = fwd->bk_nextsize; - fwd->bk_nextsize = ofs(ms,victim); - ptr(ms,victim->bk_nextsize)->fd_nextsize = ofs(ms,victim); - } - bck = ptr(ms,fwd->bk); - } - } else { - victim->fd_nextsize = victim->bk_nextsize = ofs(ms,victim); - } - } - - mark_bin(ms, victim_index); - victim->bk = ofs(ms,bck); - victim->fd = ofs(ms,fwd); - fwd->bk = ofs(ms,victim); - bck->fd = ofs(ms,victim); - -#define MAX_ITERS 10000 - if (++iters >= MAX_ITERS) - break; - } - - /* - If a large request, scan through the chunks of current bin in - sorted order to find smallest that fits. Use the skip list for this. - */ - if (!in_smallbin_range(nb)) { - bin = bin_at(ms, idx); - - /* skip scan if empty or largest chunk is too small */ - if ((victim = ptr(ms,first(bin))) != bin && - (unsigned long) victim->mchunk_size >= (unsigned long) (nb)) { - size_t size; - - victim = ptr(ms,victim->bk_nextsize); - while (((unsigned long) (size = chunksize(victim)) < - (unsigned long) (nb))) - victim = ptr(ms,victim->bk_nextsize); - - /* Avoid removing the first entry for a size so that the skip - list does not have to be rerouted. */ - if (victim != ptr(ms,last(bin)) && - victim->mchunk_size == ptr(ms,victim->fd)->mchunk_size) - victim = ptr(ms,victim->fd); - - remainder_size = size - nb; - unlink_chunk(ms, victim); - - /* Exhaust */ - if (remainder_size < MINSIZE) { - set_inuse_bit_at_offset(victim, size); - } else { /* Split */ - remainder = chunk_at_offset(victim, nb); - - /* We cannot assume the unsorted list is empty and therefore - have to perform a complete insert here. */ - bck = unsorted_chunks(ms); - fwd = ptr(ms,bck->fd); - remainder->bk = ofs(ms,bck); - remainder->fd = ofs(ms,fwd); - bck->fd = fwd->bk = ofs(ms,remainder); - if (!in_smallbin_range(remainder_size)) { - remainder->fd_nextsize = 0; - remainder->bk_nextsize = 0; - } - set_head (victim, nb | PREV_INUSE); - set_head (remainder, remainder_size | PREV_INUSE); - set_foot (remainder, remainder_size); - } - return ofs(ms,chunk2mem(victim)); - } - } - - /* - Search for a chunk by scanning bins, starting with next largest - bin. This search is strictly by best-fit; i.e., the smallest - (with ties going to approximately the least recently used) chunk - that fits is selected. - The bitmap avoids needing to check that most blocks are nonempty. - The particular case of skipping all bins during warm-up phases - when no chunks have been returned yet is faster than it might look. - */ - - ++idx; - bin = bin_at(ms, idx); - unsigned int block = idx2block(idx); - unsigned int map = ms->binmap[block]; - unsigned int bit = idx2bit(idx); - - for (;;) - { - /* Skip rest of block if there are no more set bits in this block. */ - if (bit > map || bit == 0) { - do { - if (++block >= BINMAPSIZE) /* out of bins */ - goto use_top; - } while ((map = ms->binmap[block]) == 0); - bin = bin_at(ms, (block << BINMAPSHIFT)); - bit = 1; - } - - /* Advance to bin with set bit. There must be one. */ - while ((bit & map) == 0) { - bin = next_bin(bin); - bit <<= 1; - } - /* Inspect the bin. It is likely to be non-empty */ - victim = ptr(ms,last(bin)); - /* If a false alarm (empty bin), clear the bit. */ - if (victim == bin) { - ms->binmap[block] = map &= ~bit; /* Write through */ - bin = next_bin(bin); - bit <<= 1; - } else { - size = chunksize(victim); - /* We know the first chunk in this bin is big enough to use. */ - remainder_size = size - nb; - /* unlink */ - unlink_chunk (ms, victim); - /* Exhaust */ - if (remainder_size < MINSIZE) { - set_inuse_bit_at_offset(victim, size); - } else { /* Split */ - remainder = chunk_at_offset(victim, nb); - /* We cannot assume the unsorted list is empty and therefore - have to perform a complete insert here. */ - bck = unsorted_chunks(ms); - fwd = ptr(ms,bck->fd); - remainder->bk = ofs(ms,bck); - remainder->fd = ofs(ms,fwd); - bck->fd = fwd->bk = ofs(ms,remainder); - - /* advertise as last remainder */ - if (in_smallbin_range(nb)) - ms->last_remainder = ofs(ms,remainder); - if (!in_smallbin_range(remainder_size)) { - remainder->fd_nextsize = 0; - remainder->bk_nextsize = 0; - } - set_head (victim, nb | PREV_INUSE); - set_head (remainder, remainder_size | PREV_INUSE); - set_foot (remainder, remainder_size); - } - return ofs(ms,chunk2mem(victim)); - } - } - - use_top: - /* - If large enough, split off the chunk bordering the end of memory - (held in ms->top). Note that this is in accord with the best-fit - search rule. In effect, ms->top is treated as larger (and thus - less well fitting) than any other available chunk since it can - be extended to be as large as necessary (up to system - limitations). - We require that ms->top always exists (i.e., has size >= - MINSIZE) after initialization, so if it would otherwise be - exhausted by current request, it is replenished. (The main - reason for ensuring it exists is that we may need MINSIZE space - to put in fenceposts in sysmalloc.) - */ - victim = ptr(ms,ms->top); - size = chunksize(victim); - - if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE)) { - remainder_size = size - nb; - remainder = chunk_at_offset(victim, nb); - ms->top = ofs(ms,remainder); - set_head(victim, nb | PREV_INUSE); - set_head(remainder, remainder_size | PREV_INUSE); - return ofs(ms,chunk2mem(victim)); - } else if (ms->have_fastchunks) { - malloc_consolidate (ms); - /* restore original bin index */ - if (in_smallbin_range (nb)) - idx = smallbin_index (nb); - else - idx = largebin_index (nb); - } else { /* Otherwise, relay to handle system-dependent cases */ - size_t page_size = getpagesize(); + if (nb > free_size) { size_t alloc_size = - ((nb + MINSIZE - size + page_size - 1) / page_size) * page_size; - + ((nb - free_size + page_size - 1) / page_size) * page_size; size_t new_size = ms->file_size + alloc_size; - resize_map(new_size); - - victim = ptr(ms,ms->top); - - size += alloc_size; - - remainder_size = size - nb; - remainder = chunk_at_offset(victim, nb); - ms->top = ofs(ms,remainder); - set_head(victim, nb | PREV_INUSE); - set_head(remainder, remainder_size | PREV_INUSE); - return ofs(ms,chunk2mem(victim)); + resize_map(new_size); } + + // If the object is at the end of the allocation area + top += nb; + + return oldo; } + + object newo = malloc_internal(new_bytes); + memcpy(base+newo, base+oldo, old_bytes); + free_internal(oldo, old_bytes); + return newo; } PGF_INTERNAL -object PgfDB::realloc_internal(object oldo, size_t bytes) +object PgfDB::insert_block_descriptor(object map, object o, size_t size) { - if (oldo == 0) - return malloc_internal(bytes); + if (map == 0) + return new_block_descr(o, size); - mchunk *newp; /* chunk to return */ - size_t newsize; /* its size */ - mchunk *remainder; /* extra space at end of newp */ - size_t remainder_size; /* its size */ + txn_t txn_id = (o >= ms->top) ? 0 : ms->curr_txn_id; - size_t nb = request2size(bytes); - - mchunk *oldp = mem2chunk(ptr(ms,oldo)); - size_t oldsize = chunksize(oldp); - mchunk *next = chunk_at_offset(oldp, oldsize); - size_t nextsize = chunksize(next); - - if (oldsize >= nb) { - /* already big enough; split below */ - newp = oldp; - newsize = oldsize; + block_descr *descr = ptr(block_descr, map); + int cmp = (size < descr->block_size) ? -1 + : (size > descr->block_size) ? 1 + : (txn_id < descr->block_txn_id) ? -1 + : (txn_id > descr->block_txn_id) ? 1 + : ptr(block_descr,descr->left)->sz < ptr(block_descr,descr->right)->sz ? -1 + : 1; + if (cmp < 0) { + object right = descr->right; + object left = insert_block_descriptor(descr->left, o, size); + map = upd_block_descr(map,left,right); + return balanceL_block_descriptor(map); } else { - /* Try to expand forward into top */ - if (ofs(ms,next) == ms->top && - (unsigned long) (newsize = oldsize + nextsize) >= - (unsigned long) (nb + MINSIZE)) - { - set_head_size(oldp, nb); - remainder = chunk_at_offset(oldp, nb); - ms->top = ofs(ms,remainder); - set_head(remainder, (newsize - nb) | PREV_INUSE); - return oldo; - } - /* Try to expand forward into next chunk; split off remainder below */ - else if (ofs(ms,next) != ms->top && - !inuse(next) && - (unsigned long) (newsize = oldsize + nextsize) >= - (unsigned long) (nb)) - { - newp = oldp; - unlink_chunk(ms, next); - } - /* allocate, copy, free */ - else - { - object newo = malloc_internal(bytes); - newp = mem2chunk(ptr(ms,newo)); - newsize = chunksize(newp); - /* - Avoid copy if newp is next chunk after oldp. - */ - if (newp == next) { - newsize += oldsize; - newp = oldp; - } else { - memcpy(ptr(ms,newo), ptr(ms,oldo), oldsize - sizeof(size_t)); - free_internal(oldo); - return newo; - } - } + object left = descr->left; + object right = insert_block_descriptor(descr->right, o, size); + map = upd_block_descr(map,left,right); + return balanceR_block_descriptor(map); } - - /* If possible, free extra space in old or extended chunk */ - assert(newsize >= nb); - remainder_size = newsize - nb; - if (remainder_size < MINSIZE) { /* not enough extra to split off */ - set_head_size(newp, newsize); - set_inuse_bit_at_offset(newp, newsize); - } else { /* split remainder */ - remainder = chunk_at_offset(newp, nb); - set_head_size(newp, nb); - set_head(remainder, remainder_size | PREV_INUSE); - /* Mark remainder as inuse so free() won't complain */ - set_inuse_bit_at_offset(remainder, remainder_size); - free_internal(ofs(ms,chunk2mem(remainder))); - } - return ofs(ms,chunk2mem(newp)); } PGF_INTERNAL -void PgfDB::free_internal(object o) +void PgfDB::free_internal(object o, size_t bytes) { - size_t size; /* its size */ - object *fb; /* associated fastbin */ - mchunk *nextchunk; /* next contiguous chunk */ - size_t nextsize; /* its size */ - int nextinuse; /* true if nextchunk is used */ - size_t prevsize; /* size of previous contiguous chunk */ - mchunk* bck; /* misc temp for linking */ - mchunk* fwd; /* misc temp for linking */ + if (o == 0) + return; - mchunk* p = mem2chunk(ptr(ms,o)); - size = chunksize(p); + size_t block_size = request2size(bytes); - - /* - If eligible, place chunk on a fastbin so it can be found - and used quickly in malloc. - */ - if ((unsigned long)(size) <= (unsigned long)(DEFAULT_MXFAST)) { - ms->have_fastchunks = true; - unsigned int idx = fastbin_index(size); - fb = &ms->fastbins[idx]; - /* Atomically link P to its fastbin: P->FD = *FB; *FB = P; */ - p->fd = *fb; - *fb = ofs(ms,p); - } else { /* Consolidate other chunks as they arrive. */ - nextchunk = chunk_at_offset(p, size); - nextsize = chunksize(nextchunk); - /* consolidate backward */ - if (!prev_inuse(p)) { - prevsize = prev_size(p); - size += prevsize; - p = chunk_at_offset(p, -((long) prevsize)); - unlink_chunk (ms, p); - } - if (nextchunk != ptr(ms,ms->top)) { - /* get and clear inuse bit */ - nextinuse = inuse_bit_at_offset(nextchunk, nextsize); - /* consolidate forward */ - if (!nextinuse) { - unlink_chunk (ms, nextchunk); - size += nextsize; - } else - clear_inuse_bit_at_offset(nextchunk, 0); - /* - Place the chunk in unsorted chunk list. Chunks are - not placed into regular bins until after they have - been given one chance to be used in malloc. - */ - bck = unsorted_chunks(ms); - fwd = ptr(ms,bck->fd); - p->fd = ofs(ms,fwd); - p->bk = ofs(ms,bck); - if (!in_smallbin_range(size)) { - p->fd_nextsize = 0; - p->bk_nextsize = 0; - } - bck->fd = ofs(ms,p); - fwd->bk = ofs(ms,p); - set_head(p, size | PREV_INUSE); - set_foot(p, size); - } else { - /* - If the chunk borders the current high end of memory, - consolidate into top - */ - - size += nextsize; - set_head(p, size | PREV_INUSE); - ms->top = ofs(ms,p); - } - - /* - If freeing a large space, consolidate possibly-surrounding - chunks. Then, if the total unused topmost memory exceeds trim - threshold, ask malloc_trim to reduce top. - Unless max_fast is 0, we don't know if there are fastbins - bordering top, so we cannot tell for sure whether threshold - has been reached unless fastbins are consolidated. But we - don't want to consolidate on each free. As a compromise, - consolidation is performed if FASTBIN_CONSOLIDATION_THRESHOLD - is reached. - */ - if ((unsigned long)(size) >= FASTBIN_CONSOLIDATION_THRESHOLD) { - if (ms->have_fastchunks) - malloc_consolidate(ms); - } + if (o >= ms->top && o+block_size == top) { + // The block has been allocated in the current transaction + // and it is the last just before the top area. We can + // simply decrement top; + top -= block_size; + return; } + + free_blocks = insert_block_descriptor(free_blocks, o, block_size); + +#ifdef DEBUG_MEMORY_ALLOCATOR + dump_free_blocks(free_blocks); + printf("\n"); +#endif } PGF_INTERNAL ref PgfDB::revision2pgf(PgfRevision revision) { - if (revision <= sizeof(*current_db->ms) || revision >= current_db->ms->top) + if (revision == 0 || ref::get_tag(revision) != PgfPGF::tag) throw pgf_error("Invalid revision"); - mchunk *chunk = mem2chunk(ptr(current_db->ms,revision)); - if (chunksize(chunk) < sizeof(PgfPGF)) - throw pgf_error("Invalid revision"); - - ref pgf = revision; - if (chunksize(chunk) - request2size(sizeof(PgfPGF)+pgf->name.size+1) > MINSIZE) + ref pgf = ref::untagged(revision); + if (pgf.as_object() >= top) throw pgf_error("Invalid revision"); return pgf; } -PGF_INTERNAL -bool PgfDB::is_persistant_revision(ref pgf) -{ - return (pgf->prev == 0 && pgf->next == 0 && - current_db->ms->transient_revisions != pgf); -} - -PGF_INTERNAL -void PgfDB::link_transient_revision(ref pgf) -{ - pgf->next = current_db->ms->transient_revisions; - if (current_db->ms->transient_revisions != 0) - current_db->ms->transient_revisions->prev = pgf; - current_db->ms->transient_revisions = pgf; -} - -PGF_INTERNAL -void PgfDB::unlink_transient_revision(ref pgf) -{ - if (pgf->next != 0) - pgf->next->prev = pgf->prev; - if (pgf->prev != 0) - pgf->prev->next = pgf->next; - else if (current_db->ms->transient_revisions == pgf) - current_db->ms->transient_revisions = pgf->next; -} - PGF_INTERNAL ref PgfDB::revision2concr(PgfConcrRevision revision) { - if (revision <= sizeof(*current_db->ms) || revision >= current_db->ms->top) + if (revision == 0 || ref::get_tag(revision) != PgfConcr::tag) throw pgf_error("Invalid revision"); - mchunk *chunk = mem2chunk(ptr(current_db->ms,revision)); - if (chunksize(chunk) < sizeof(PgfConcr)) - throw pgf_error("Invalid revision"); - - ref concr = revision; - if (chunksize(chunk) - request2size(sizeof(PgfConcr)+concr->name.size+1) > MINSIZE) + ref concr = ref::untagged(revision); + if (concr.as_object() >= top) throw pgf_error("Invalid revision"); return concr; } PGF_INTERNAL -bool PgfDB::is_persistant_revision(ref concr) +void PgfDB::start_transaction() { - return (concr->prev == 0 && concr->next == 0 && - current_db->ms->transient_concr_revisions != concr); + top = ms->top; + free_blocks = ms->free_blocks; + free_descriptors[0] = ms->free_descriptors; + free_descriptors[1] = 0; } PGF_INTERNAL -void PgfDB::link_transient_revision(ref concr) -{ - concr->next = current_db->ms->transient_concr_revisions; - if (current_db->ms->transient_concr_revisions != 0) - current_db->ms->transient_concr_revisions->prev = concr; - current_db->ms->transient_concr_revisions = concr; -} - -PGF_INTERNAL -void PgfDB::unlink_transient_revision(ref concr) -{ - if (concr->next != 0) - concr->next->prev = concr->prev; - if (concr->prev != 0) - concr->prev->next = concr->next; - else if (current_db->ms->transient_concr_revisions == concr) - current_db->ms->transient_concr_revisions = concr->next; -} - -PGF_INTERNAL -void PgfDB::sync() +void PgfDB::commit() { malloc_state *ms = current_db->ms; - size_t size = - ms->top + chunksize(ptr(ms,ms->top)) + sizeof(size_t); + object save_top = ms->top; + object save_free_blocks = ms->free_blocks; + object save_free_descriptors = ms->free_descriptors; int res; #ifndef _WIN32 #ifndef MREMAP_MAYMOVE if (current_db->fd < 0) { - res = 0; - } else + ms->top = top; + ms->free_blocks = free_blocks; + ms->free_descriptors = free_descriptors[0]; + free_descriptors[1] = 0; + ms->curr_txn_id++; + res = 0; + } else { +#endif + res = msync((void *) base, mmap_size, MS_SYNC | MS_INVALIDATE); + if (res != 0) + throw pgf_systemerror(errno); + + ms->top = top; + ms->free_blocks = free_blocks; + ms->free_descriptors = free_descriptors[0]; + free_descriptors[1] = 0; + ms->curr_txn_id++; + + res = msync((void *) ms, page_size, MS_SYNC | MS_INVALIDATE); + if (res != 0) { + ms->top = save_top; + ms->free_blocks = save_free_blocks; + ms->free_descriptors = save_free_descriptors; + ms->curr_txn_id--; + throw pgf_systemerror(errno); + } +#ifndef MREMAP_MAYMOVE + } #endif - res = msync((void *) ms, size, MS_SYNC | MS_INVALIDATE); - if (res != 0) - throw pgf_systemerror(errno); #else if (current_db->fd > 0) { - if (!FlushViewOfFile(ms,size)) { + if (!FlushViewOfFile(base,mmap_size)) { + throw pgf_systemerror(last_error_to_errno()); + } + ms->top = top; + ms->free_blocks = free_blocks; + ms->free_descriptors = free_descriptors[0]; + free_descriptors[1] = 0; + ms->curr_txn_id++; + if (!FlushViewOfFile(ms,page_size)) { + ms->top = save_top; + ms->free_blocks = save_free_blocks; + ms->free_descriptors = save_free_descriptors; + ms->curr_txn_id--; throw pgf_systemerror(last_error_to_errno()); } } #endif } +PGF_INTERNAL +void PgfDB::rollback() +{ + top = ms->top; + free_blocks = ms->free_blocks; + free_descriptors[0] = ms->free_descriptors; + free_descriptors[1] = 0; +} + #ifdef _WIN32 #define MAX_SPIN 50000 @@ -1671,8 +1219,8 @@ void PgfDB::lock(DB_scope_mode m) { #ifndef _WIN32 int res = - (m == READER_SCOPE) ? pthread_rwlock_rdlock(rwlock) - : pthread_rwlock_wrlock(rwlock); + (m == READER_SCOPE) ? pthread_rwlock_rdlock(&ms->rwlock) + : pthread_rwlock_wrlock(&ms->rwlock); if (res != 0) throw pgf_systemerror(res); #else @@ -1717,7 +1265,7 @@ void PgfDB::lock(DB_scope_mode m) void PgfDB::unlock() { #ifndef _WIN32 - pthread_rwlock_unlock(rwlock); + pthread_rwlock_unlock(&ms->rwlock); #else while (true) { unsigned __int32 temp = ms->rwlock; @@ -1756,43 +1304,47 @@ void PgfDB::unlock() void PgfDB::resize_map(size_t new_size) { - malloc_state* new_ms; #ifndef _WIN32 -// OSX do not implement mremap or MREMAP_MAYMOVE + unsigned char* new_base; + +// OSX does not implement mremap or MREMAP_MAYMOVE #ifndef MREMAP_MAYMOVE if (fd >= 0) { - size_t old_file_size = ms->file_size; - if (munmap(ms, mmap_size) == -1) + if (munmap(base, mmap_size) == -1) throw pgf_systemerror(errno); - ms = NULL; - if (old_file_size != new_size) { - if (ftruncate(fd, new_size) < 0) + base = NULL; + if (ms->file_size != new_size) { + if (ftruncate(fd, page_size+new_size) < 0) throw pgf_systemerror(errno, filepath); } - new_ms = - (malloc_state*) mmap(0, new_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (new_ms == MAP_FAILED) + new_base = + (unsigned char *) mmap(0, new_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, page_size); + if (new_base == MAP_FAILED) throw pgf_systemerror(errno); } else { - new_ms = (malloc_state*) ::realloc(ms, new_size); - if (new_ms == NULL) + new_base = ::realloc(base, new_size); + if (new_base == NULL) throw pgf_systemerror(ENOMEM); } #else if (fd >= 0 && ms->file_size != new_size) { - if (ftruncate(fd, new_size) < 0) + if (ftruncate(fd, page_size+new_size) < 0) throw pgf_systemerror(errno, filepath); } - new_ms = - (malloc_state*) mremap(ms, mmap_size, new_size, MREMAP_MAYMOVE); - if (new_ms == MAP_FAILED) + new_base = + (unsigned char *) mremap(base, mmap_size, new_size, MREMAP_MAYMOVE); + if (new_base == MAP_FAILED) throw pgf_systemerror(errno); #endif + + base = new_base; #else + new_size += page_size; if (fd >= 0) { UnmapViewOfFile(ms); CloseHandle(hMap); ms = NULL; + base = NULL; hMap = CreateFileMapping((HANDLE) _get_osfhandle(fd), NULL, @@ -1814,10 +1366,12 @@ void PgfDB::resize_map(size_t new_size) if (new_ms == NULL) throw pgf_systemerror(ENOMEM); } -#endif + new_size -= page_size; ms = new_ms; - current_base = (unsigned char*) ms; + base = ((unsigned char*) ms) + page_size; +#endif + current_base = (unsigned char*) base; mmap_size = new_size; ms->file_size = new_size; } @@ -1828,7 +1382,7 @@ DB_scope::DB_scope(PgfDB *db, DB_scope_mode m) save_db = current_db; current_db = db; - current_base = (unsigned char*) current_db->ms; + current_base = db->base; next_scope = last_db_scope; last_db_scope = this; @@ -1841,10 +1395,9 @@ DB_scope::~DB_scope() current_db->unlock(); current_db = save_db; - current_base = current_db ? (unsigned char*) current_db->ms + current_base = current_db ? current_db->base : NULL; last_db_scope = next_scope; - #pragma GCC diagnostic pop } diff --git a/src/runtime/c/pgf/db.h b/src/runtime/c/pgf/db.h index c7d919e0d..94e77a596 100644 --- a/src/runtime/c/pgf/db.h +++ b/src/runtime/c/pgf/db.h @@ -8,6 +8,7 @@ class PgfDB; extern PGF_INTERNAL_DECL __thread unsigned char* current_base __attribute__((tls_model("initial-exec"))); extern PGF_INTERNAL_DECL __thread PgfDB* current_db __attribute__((tls_model("initial-exec"))); +struct block_descr; struct malloc_state; template class PGF_INTERNAL_DECL ref { @@ -37,10 +38,9 @@ public: object as_object() const { return offset; } - static - object tagged(ref ref) { + object tagged() { assert(A::tag < MALLOC_ALIGN_MASK + 1); - return (ref.offset | A::tag); + return (offset | A::tag); } static @@ -56,16 +56,28 @@ public: enum DB_scope_mode {READER_SCOPE, WRITER_SCOPE}; +typedef size_t txn_t; + class PgfDB { private: int fd; const char *filepath; malloc_state* ms; - size_t mmap_size; + unsigned char* base; + // The following four fields are normally equal to + // the corresponding fields in the malloc_state. + // The exception is when a transaction is active. + object top; + object free_blocks; + object free_descriptors[2]; + + size_t mmap_size; + size_t page_size; #ifndef _WIN32 - pthread_rwlock_t *rwlock; + pid_t pid; #else + DWORD pid; HANDLE hMap; HANDLE hRWEvent; #endif @@ -80,48 +92,60 @@ public: PGF_INTERNAL_DECL PgfDB(const char* filepath, int flags, int mode); PGF_INTERNAL_DECL ~PgfDB(); + PGF_INTERNAL_DECL static txn_t get_txn_id(); + template static ref malloc(size_t extra_bytes=0) { return current_db->malloc_internal(sizeof(A)+extra_bytes); } template - static ref realloc(ref r, size_t extra_bytes) { - return current_db->realloc_internal(r.as_object(), sizeof(A)+extra_bytes); + static ref realloc(ref r, size_t old_extra_bytes, size_t new_extra_bytes) { + return current_db->realloc_internal(r.as_object(), sizeof(A)+old_extra_bytes, sizeof(A)+new_extra_bytes); } template - static void free(ref o) { - current_db->free_internal(o.as_object()); + static void free(ref o, size_t extra_bytes=0) { + current_db->free_internal(o.as_object(), sizeof(A)+extra_bytes); } PGF_INTERNAL_DECL void cleanup_revisions(); - static PGF_INTERNAL_DECL ref get_revision(PgfText *name); - static PGF_INTERNAL_DECL void set_revision(ref pgf); + PGF_INTERNAL_DECL object get_active_revision(); + PGF_INTERNAL_DECL void set_active_revision(object o); + PGF_INTERNAL_DECL void register_revision(object o); + PGF_INTERNAL_DECL void unregister_revision(object o); - static PGF_INTERNAL_DECL ref revision2pgf(PgfRevision revision); - static PGF_INTERNAL_DECL bool is_persistant_revision(ref pgf); - static PGF_INTERNAL_DECL void link_transient_revision(ref pgf); - static PGF_INTERNAL_DECL void unlink_transient_revision(ref pgf); + PGF_INTERNAL_DECL ref revision2pgf(PgfRevision revision); + PGF_INTERNAL_DECL ref revision2concr(PgfConcrRevision revision); - static PGF_INTERNAL_DECL ref revision2concr(PgfConcrRevision revision); - static PGF_INTERNAL_DECL bool is_persistant_revision(ref concr); - static PGF_INTERNAL_DECL void link_transient_revision(ref concr); - static PGF_INTERNAL_DECL void unlink_transient_revision(ref concr); - - static PGF_INTERNAL_DECL void sync(); + PGF_INTERNAL_DECL void start_transaction(); + PGF_INTERNAL_DECL void commit(); + PGF_INTERNAL_DECL void rollback(); private: - PGF_INTERNAL_DECL void init_state(size_t size); + PGF_INTERNAL_DECL int init_state(); + + PGF_INTERNAL_DECL size_t block_descr_size(object map); + PGF_INTERNAL_DECL object new_block_descr(object o, size_t size); + PGF_INTERNAL_DECL object upd_block_descr(object map, object left, object right); + PGF_INTERNAL_DECL object balanceL_block_descriptor(object map); + PGF_INTERNAL_DECL object balanceR_block_descriptor(object map); + PGF_INTERNAL_DECL object pop_first_block_descriptor(object map, object *res); + PGF_INTERNAL_DECL object pop_last_block_descriptor(object map, object *res); + PGF_INTERNAL_DECL object insert_block_descriptor(object map, object o, size_t size); + PGF_INTERNAL_DECL object delete_block_descriptor(object map, size_t *psize, object *po); + +#ifdef DEBUG_MEMORY_ALLOCATOR + PGF_INTERNAL_DECL void dump_free_blocks(object map); +#endif + PGF_INTERNAL_DECL object malloc_internal(size_t bytes); - PGF_INTERNAL_DECL object realloc_internal(object oldo, size_t bytes); - PGF_INTERNAL_DECL void free_internal(object o); + PGF_INTERNAL_DECL object realloc_internal(object oldo, size_t old_bytes, size_t new_bytes); - PGF_INTERNAL_DECL void register_process(); - PGF_INTERNAL_DECL void unregister_process(); + PGF_INTERNAL_DECL void free_internal(object o, size_t bytes); PGF_INTERNAL_DECL void lock(DB_scope_mode m); PGF_INTERNAL_DECL void unlock(); diff --git a/src/runtime/c/pgf/expr.cxx b/src/runtime/c/pgf/expr.cxx index 99f5c78a6..66ccfb13b 100644 --- a/src/runtime/c/pgf/expr.cxx +++ b/src/runtime/c/pgf/expr.cxx @@ -116,7 +116,7 @@ PgfExpr PgfDBUnmarshaller::eabs(PgfBindType bind_type, PgfText *name, PgfExpr bo eabs->bind_type = bind_type; eabs->body = m->match_expr(this, body); memcpy(&eabs->name, name, sizeof(PgfText)+name->size+1); - return ref::tagged(eabs); + return eabs.tagged(); } PgfExpr PgfDBUnmarshaller::eapp(PgfExpr fun, PgfExpr arg) @@ -124,21 +124,21 @@ PgfExpr PgfDBUnmarshaller::eapp(PgfExpr fun, PgfExpr arg) ref eapp = PgfDB::malloc(); eapp->fun = m->match_expr(this, fun); eapp->arg = m->match_expr(this, arg); - return ref::tagged(eapp); + return eapp.tagged(); } PgfExpr PgfDBUnmarshaller::elit(PgfLiteral lit) { ref elit = PgfDB::malloc(); elit->lit = m->match_lit(this, lit); - return ref::tagged(elit); + return elit.tagged(); } PgfExpr PgfDBUnmarshaller::emeta(PgfMetaId meta_id) { ref emeta = PgfDB::malloc(); emeta->id = meta_id; - return ref::tagged(emeta); + return emeta.tagged(); } PgfExpr PgfDBUnmarshaller::efun(PgfText *name) @@ -146,14 +146,14 @@ PgfExpr PgfDBUnmarshaller::efun(PgfText *name) ref efun = PgfDB::malloc(name->size+1); memcpy(&efun->name, name, sizeof(PgfText)+name->size+1); - return ref::tagged(efun); + return efun.tagged(); } PgfExpr PgfDBUnmarshaller::evar(int index) { ref evar = PgfDB::malloc(); evar->var = index; - return ref::tagged(evar); + return evar.tagged(); } PgfExpr PgfDBUnmarshaller::etyped(PgfExpr expr, PgfType ty) @@ -161,14 +161,14 @@ PgfExpr PgfDBUnmarshaller::etyped(PgfExpr expr, PgfType ty) ref etyped = PgfDB::malloc(); etyped->expr = m->match_expr(this, expr); etyped->type = m->match_type(this, ty); - return ref::tagged(etyped); + return etyped.tagged(); } PgfExpr PgfDBUnmarshaller::eimplarg(PgfExpr expr) { ref eimpl = current_db->malloc(); eimpl->expr = m->match_expr(this, expr); - return ref::tagged(eimpl); + return eimpl.tagged(); } PgfLiteral PgfDBUnmarshaller::lint(size_t size, uintmax_t *val) @@ -177,14 +177,14 @@ PgfLiteral PgfDBUnmarshaller::lint(size_t size, uintmax_t *val) PgfDB::malloc(size*sizeof(uintmax_t)); lit_int->size = size; memcpy(&lit_int->val, val, size*sizeof(uintmax_t)); - return ref::tagged(lit_int); + return lit_int.tagged(); } PgfLiteral PgfDBUnmarshaller::lflt(double val) { ref lit_flt = PgfDB::malloc(); lit_flt->val = val; - return ref::tagged(lit_flt); + return lit_flt.tagged(); } PgfLiteral PgfDBUnmarshaller::lstr(PgfText *val) @@ -192,7 +192,7 @@ PgfLiteral PgfDBUnmarshaller::lstr(PgfText *val) ref lit_str = PgfDB::malloc(val->size+1); memcpy(&lit_str->val, val, sizeof(PgfText)+val->size+1); - return ref::tagged(lit_str); + return lit_str.tagged(); } PgfType PgfDBUnmarshaller::dtyp(size_t n_hypos, PgfTypeHypo *hypos, @@ -217,9 +217,8 @@ PgfType PgfDBUnmarshaller::dtyp(size_t n_hypos, PgfTypeHypo *hypos, return ty.as_object(); } -void PgfDBUnmarshaller::free_ref(object x) +void PgfDBUnmarshaller::free_ref(object expr) { - PgfDB::free(ref::untagged(x)); } PgfLiteral PgfInternalMarshaller::match_lit(PgfUnmarshaller *u, PgfLiteral l) @@ -1170,11 +1169,12 @@ void PgfExprProbEstimator::free_ref(object x) } PGF_INTERNAL -void pgf_literal_free(PgfLiteral literal) +void pgf_literal_release(PgfLiteral literal) { switch (ref::get_tag(literal)) { case PgfLiteralInt::tag: { - PgfDB::free(ref::untagged(literal)); + auto lint = ref::untagged(literal); + PgfDB::free(lint, lint->size*sizeof(uintmax_t)); break; } case PgfLiteralFlt::tag: { @@ -1182,7 +1182,8 @@ void pgf_literal_free(PgfLiteral literal) break; } case PgfLiteralStr::tag: { - PgfDB::free(ref::untagged(literal)); + auto lstr = ref::untagged(literal); + PgfDB::free(lstr, lstr->val.size+1); break; } default: @@ -1191,25 +1192,25 @@ void pgf_literal_free(PgfLiteral literal) } PGF_INTERNAL -void pgf_expr_free(PgfExpr expr) +void pgf_expr_release(PgfExpr expr) { switch (ref::get_tag(expr)) { case PgfExprAbs::tag: { auto eabs = ref::untagged(expr); - pgf_expr_free(eabs->body); - PgfDB::free(eabs); + pgf_expr_release(eabs->body); + PgfDB::free(eabs, eabs->name.size+1); break; } case PgfExprApp::tag: { auto eapp = ref::untagged(expr); - pgf_expr_free(eapp->fun); - pgf_expr_free(eapp->arg); + pgf_expr_release(eapp->fun); + pgf_expr_release(eapp->arg); PgfDB::free(eapp); break; } case PgfExprLit::tag: { auto elit = ref::untagged(expr); - pgf_literal_free(elit->lit); + pgf_literal_release(elit->lit); PgfDB::free(elit); break; } @@ -1218,7 +1219,8 @@ void pgf_expr_free(PgfExpr expr) break; } case PgfExprFun::tag: { - PgfDB::free(ref::untagged(expr)); + auto efun = ref::untagged(expr); + PgfDB::free(efun, efun->name.size+1); break; } case PgfExprVar::tag: { @@ -1227,14 +1229,14 @@ void pgf_expr_free(PgfExpr expr) } case PgfExprTyped::tag: { auto etyped = ref::untagged(expr); - pgf_expr_free(etyped->expr); - pgf_type_free(etyped->type); + pgf_expr_release(etyped->expr); + pgf_type_release(etyped->type); PgfDB::free(etyped); break; } case PgfExprImplArg::tag: { auto eimpl = ref::untagged(expr); - pgf_expr_free(eimpl->expr); + pgf_expr_release(eimpl->expr); PgfDB::free(eimpl); break; } @@ -1244,25 +1246,25 @@ void pgf_expr_free(PgfExpr expr) } PGF_INTERNAL -void pgf_context_free(ref> hypos) +void pgf_context_release(ref> hypos) { for (size_t i = 0; i < hypos->len; i++) { - PgfDB::free(vector_elem(hypos, i)->cid); - pgf_type_free(vector_elem(hypos, i)->type); + text_db_release(vector_elem(hypos, i)->cid); + pgf_type_release(vector_elem(hypos, i)->type); } - PgfDB::free(hypos); + Vector::release(hypos); } PGF_INTERNAL -void pgf_type_free(ref dtyp) +void pgf_type_release(ref dtyp) { - pgf_context_free(dtyp->hypos); + pgf_context_release(dtyp->hypos); for (size_t i = 0; i < dtyp->exprs->len; i++) { - pgf_expr_free(*vector_elem(dtyp->exprs, i)); + pgf_expr_release(*vector_elem(dtyp->exprs, i)); } - PgfDB::free(dtyp->exprs); + Vector::release(dtyp->exprs); - PgfDB::free(dtyp); + PgfDB::free(dtyp, dtyp->name.size+1); } diff --git a/src/runtime/c/pgf/expr.h b/src/runtime/c/pgf/expr.h index 782822a43..85e30fe1f 100644 --- a/src/runtime/c/pgf/expr.h +++ b/src/runtime/c/pgf/expr.h @@ -228,15 +228,15 @@ public: */ PGF_INTERNAL_DECL -void pgf_literal_free(PgfLiteral literal); +void pgf_literal_release(PgfLiteral literal); PGF_INTERNAL_DECL -void pgf_expr_free(PgfExpr expr); +void pgf_expr_release(PgfExpr expr); PGF_INTERNAL_DECL -void pgf_context_free(ref> hypos); +void pgf_context_release(ref> hypos); PGF_INTERNAL_DECL -void pgf_type_free(ref dtyp); +void pgf_type_release(ref dtyp); #endif /* EXPR_H_ */ diff --git a/src/runtime/c/pgf/namespace.h b/src/runtime/c/pgf/namespace.h index 41cabf429..28e007bae 100644 --- a/src/runtime/c/pgf/namespace.h +++ b/src/runtime/c/pgf/namespace.h @@ -5,15 +5,8 @@ // #define DEBUG_NAMESPACE -/* Namespace expects that the class V contains: - * - * - A member 'size_t ref_count' which keeps track of the number of - * references to the particular object. - * - A member 'PgfText name' which contains the name of the object. - * - A method: - * static void release(ref object) - * which is executed when ref_count becomes zero. After that the memory - * for the object is released as well. +/* Namespace expects that the class V contains, + * a member 'PgfText name' which contains the name of the object. */ template @@ -26,7 +19,7 @@ template class PGF_INTERNAL_DECL Node { public: - size_t ref_count; + txn_t txn_id; size_t sz; V value; @@ -36,12 +29,12 @@ public: static ref new_node(V value) { - ref node = current_db->malloc(); - node->ref_count = 1; - node->sz = 1; - node->value = value; - node->left = 0; - node->right = 0; + ref node = PgfDB::malloc(); + node->txn_id = PgfDB::get_txn_id(); + node->sz = 1; + node->value = value; + node->left = 0; + node->right = 0; #ifdef DEBUG_NAMESPACE printf("new node %6ld %s\n", node.as_object(), node->value->name.text); @@ -50,310 +43,200 @@ public: } static - ref new_node(V value, ref left, ref right) + ref upd_node(ref node, ref left, ref right) { - ref node = current_db->malloc(); - node->ref_count = 1; - node->sz = 1+Node::size(left)+Node::size(right); - node->value = value; - node->left = left; - node->right = right; + if (node->txn_id != PgfDB::get_txn_id()) { + ref new_node = PgfDB::malloc(); + new_node->txn_id = PgfDB::get_txn_id(); + new_node->value = node->value; + release(node); + node = new_node; #ifdef DEBUG_NAMESPACE - printf("new node %6ld %s(%ld,%ld)\n", node.as_object(), node->value->name.text, left.as_object(), right.as_object()); + printf("new node %6ld %s(%ld,%ld)\n", node.as_object(), node->value->name.text, left.as_object(), right.as_object()); #endif + } + + node->sz = 1+Node::size(left)+Node::size(right); + node->left = left; + node->right = right; return node; } static - void add_node_ref(ref node) + ref balanceL(ref node) { - node->ref_count++; -#ifdef DEBUG_NAMESPACE - printf("add_ref node %6ld %s (ref_count=%ld)\n", node.as_object(), node->value->name.text, node->ref_count); -#endif - } - - template static - void add_value_ref(A &value) - { - value.add_ref(); -#ifdef DEBUG_NAMESPACE - printf("add_ref value %5ld %s (ref_count=%ld)\n", value.as_object(), value->name.text, value->ref_count); -#endif - } - - template static - void add_value_ref(ref value) - { - value->ref_count++; -#ifdef DEBUG_NAMESPACE - printf("add_ref value %5ld %s (ref_count=%ld)\n", value.as_object(), value->name.text, value->ref_count); -#endif - } - - template static - void release_value_ref(A &value) - { -#ifdef DEBUG_NAMESPACE - printf("release value %5ld %s (ref_count=%ld)\n", value.as_object(), value->name.text, value->ref_count-1); -#endif - - value.release_ref(); - } - - template static - void release_value_ref(ref value) - { -#ifdef DEBUG_NAMESPACE - printf("release value %5ld %s (ref_count=%ld)\n", value.as_object(), value->name.text, value->ref_count-1); -#endif - - if (!(--value->ref_count)) { - A::release(value); - } - } - - static - ref balanceL(V value, ref left, ref right) - { - if (right == 0) { - if (left == 0) { - add_value_ref(value); - return new_node(value); + if (node->right == 0) { + if (node->left == 0) { + return node; } else { - if (left->left == 0) { - if (left->right == 0) { - add_value_ref(value); - add_node_ref(left); - return new_node(value,left,0); + if (node->left->left == 0) { + if (node->left->right == 0) { + return node; } else { - add_value_ref(value); - add_value_ref(left->value); - add_value_ref(left->right->value); - ref> new_left = new_node(left->value); - ref> new_right = new_node(value); - return new_node(left->right->value, - new_left, - new_right); + ref> left_right = node->left->right; + ref> left = upd_node(node->left,0,0); + ref> right = upd_node(node,0,0); + return upd_node(left_right, + left, + right); } } else { - if (left->right == 0) { - add_value_ref(value); - ref> new_right = new_node(value); - add_value_ref(left->value); - add_node_ref(left->left); - return new_node(left->value, + if (node->left->right == 0) { + ref> left = node->left; + ref> right = upd_node(node,0,0); + return upd_node(left, left->left, - new_right); + right); } else { - if (left->right->sz < 2 * left->left->sz) { - add_value_ref(value); - add_value_ref(left->value); - add_node_ref(left->left); - add_node_ref(left->right); - ref> new_right = - new_node(value, + if (node->left->right->sz < 2 * node->left->left->sz) { + ref> left = node->left; + ref> right = + upd_node(node, left->right, 0); - return new_node(left->value, + return upd_node(left, left->left, - new_right); + right); } else { - add_value_ref(value); - add_value_ref(left->value); - add_value_ref(left->right->value); - add_node_ref(left->left); - if (left->right->left != 0) - add_node_ref(left->right->left); - if (left->right->right != 0) - add_node_ref(left->right->right); - ref> new_left = - new_node(left->value, - left->left, - left->right->left); - ref> new_right = - new_node(value, - left->right->right, + ref> left_right = node->left->right; + ref> left = + upd_node(node->left, + node->left->left, + left_right->left); + ref> right = + upd_node(node, + left_right->right, 0); - return new_node(left->right->value, - new_left, - new_right); + return upd_node(left_right, + left, + right); } } } } } else { - if (left == 0) { - add_value_ref(value); - add_node_ref(right); - return new_node(value,0,right); + if (node->left == 0) { + return node; } else { - if (left->sz > 3*right->sz) { - if (left->right->sz < 2*left->left->sz) { - add_value_ref(value); - add_value_ref(left->value); - add_node_ref(left->left); - add_node_ref(left->right); - add_node_ref(right); - ref> new_right = - new_node(value, + if (node->left->sz > 3*node->right->sz) { + if (node->left->right->sz < 2*node->left->left->sz) { + ref> left = node->left; + ref> right = + upd_node(node, left->right, - right); - return new_node(left->value, + node->right); + return upd_node(left, left->left, - new_right); + right); } else { - add_value_ref(value); - add_value_ref(left->value); - add_value_ref(left->right->value); - add_node_ref(left->left); - if (left->right->left != 0) - add_node_ref(left->right->left); - if (left->right->right != 0) - add_node_ref(left->right->right); - add_node_ref(right); - ref> new_left = - new_node(left->value, - left->left, - left->right->left); - ref> new_right = - new_node(value, - left->right->right, - right); - return new_node(left->right->value, - new_left, - new_right); + ref> left_right = node->left->right; + ref> left = + upd_node(node->left, + node->left->left, + left_right->left); + ref> right = + upd_node(node, + left_right->right, + node->right); + return upd_node(left_right, + left, + right); } } else { - add_value_ref(value); - add_node_ref(left); - add_node_ref(right); - return new_node(value,left,right); + return node; } } } } static - ref balanceR(V value, ref left, ref right) + ref balanceR(ref node) { - if (left == 0) { - if (right == 0) { - add_value_ref(value); - return new_node(value); + if (node->left == 0) { + if (node->right == 0) { + return node; } else { - if (right->left == 0) { - if (right->right == 0) { - add_value_ref(value); - add_node_ref(right); - return new_node(value,0,right); + if (node->right->left == 0) { + if (node->right->right == 0) { + return node; } else { - add_value_ref(value); - add_value_ref(right->value); - add_node_ref(right->right); - ref> new_left = - new_node(value); - return new_node(right->value, - new_left, + ref> right = node->right; + ref> left = + upd_node(node, + 0, + 0); + return upd_node(right, + left, right->right); } } else { - if (right->right == 0) { - add_value_ref(value); - add_value_ref(right->value); - add_value_ref(right->left->value); - ref> new_left = - new_node(value); - ref> new_right = - new_node(right->value); - return new_node(right->left->value, - new_left, - new_right); + if (node->right->right == 0) { + ref> right_left = node->right->left; + ref> right = + upd_node(node->right,0,0); + ref> left = + upd_node(node,0,0); + return upd_node(right_left, + left, + right); } else { - if (right->left->sz < 2 * right->right->sz) { - add_value_ref(value); - add_value_ref(right->value); - add_node_ref(right->left); - add_node_ref(right->right); - ref> new_left = - new_node(value, + if (node->right->left->sz < 2 * node->right->right->sz) { + ref> right = node->right; + ref> left = + upd_node(node, 0, right->left); - return new_node(right->value, - new_left, + return upd_node(right, + left, right->right); } else { - add_value_ref(value); - add_value_ref(right->value); - add_value_ref(right->left->value); - if (right->left->left != 0) - add_node_ref(right->left->left); - if (right->left->right != 0) - add_node_ref(right->left->right); - add_node_ref(right->right); - ref> new_left = - new_node(value, + ref> right_left = node->right->left; + ref> right = + upd_node(node->right, + right_left->right, + node->right->right); + ref> left = + upd_node(node, 0, - right->left->left); - ref> new_right = - new_node(right->value, - right->left->right, - right->right); - return new_node(right->left->value, - new_left, - new_right); + right_left->left); + return upd_node(right_left, + left, + right); } } } } } else { - if (right == 0) { - add_value_ref(value); - add_node_ref(left); - return new_node(value,left,0); + if (node->right == 0) { + return node; } else { - if (right->sz > 3*left->sz) { - if (right->left->sz < 2*right->right->sz) { - add_value_ref(value); - add_value_ref(right->value); - add_node_ref(left); - add_node_ref(right->left); - add_node_ref(right->right); - ref> new_left = - new_node(value, - left, + if (node->right->sz > 3*node->left->sz) { + if (node->right->left->sz < 2*node->right->right->sz) { + ref> right = node->right; + ref> left = + upd_node(node, + node->left, right->left); - return new_node(right->value, - new_left, + return upd_node(right, + left, right->right); } else { - add_value_ref(value); - add_value_ref(right->value); - add_value_ref(right->left->value); - add_node_ref(left); - if (right->left->left != 0) - add_node_ref(right->left->left); - if (right->left->right != 0) - add_node_ref(right->left->right); - add_node_ref(right->right); - ref> new_left = - new_node(value, - left, - right->left->left); - ref> new_right = - new_node(right->value, - right->left->right, - right->right); - return new_node(right->left->value, - new_left, - new_right); + ref> right_left = node->right->left; + ref> right = + upd_node(node->right, + right_left->right, + node->right->right); + ref> left = + upd_node(node, + node->left, + right_left->left); + return upd_node(right_left, + left, + right); } } else { - add_value_ref(value); - add_node_ref(left); - add_node_ref(right); - return new_node(value,left,right); + return node; } } } @@ -368,57 +251,42 @@ public: } static - ref pop_first(ref node, V *res) + ref pop_first(ref node, ref *res) { if (node == 0) { return 0; } else if (node->left == 0) { - *res = node->value; - if (node->right != 0) - node->right->ref_count++; + *res = node; return node->right; } else { - ref new_left = pop_first(node->left, res); - ref new_node = balanceR(node->value, new_left, node->right); - release(new_left); - return new_node; + ref left = pop_first(node->left, res); + ref node = upd_node(node, left, node->right); + return balanceR(node); } } static - ref pop_last(ref node, V *res) + ref pop_last(ref node, ref *res) { if (node == 0) { return 0; } else if (node->right == 0) { - *res = node->value; - if (node->left != 0) - node->left->ref_count++; + *res = node; return node->left; } else { - ref new_right = pop_last(node->right, res); - ref new_node = balanceR(node->value, node->left, new_right); - release(new_right); - return new_node; + ref right = pop_last(node->right, res); + ref node = upd_node(node, node->left, right); + return balanceL(node); } } static void release(ref node) { - if (node == 0) - return; - #ifdef DEBUG_NAMESPACE printf("release node %6ld %s (ref_count=%ld)\n", node.as_object(), node->value->name.text, node->ref_count-1); #endif - - if (!(--node->ref_count)) { - release(node->left); - release(node->right); - release_value_ref(node->value); - PgfDB::free(node); - } + PgfDB::free(node); } }; @@ -443,26 +311,22 @@ Namespace namespace_insert(Namespace map, ref value) int cmp = textcmp(&value->name,&map->value->name); if (cmp < 0) { Namespace left = namespace_insert(map->left, value); - Namespace node = Node>::balanceL(map->value,left,map->right); - namespace_release(left); - return node; + map = Node>::upd_node(map,left,map->right); + return Node>::balanceL(map); } else if (cmp > 0) { Namespace right = namespace_insert(map->right, value); - Namespace node = Node>::balanceR(map->value, map->left, right); - namespace_release(right); - return node; + map = Node>::upd_node(map,map->left,right); + return Node>::balanceR(map); } else { - if (map->left != 0) - map->left->ref_count++; - if (map->right != 0) - map->right->ref_count++; - return Node>::new_node(value,map->left,map->right); + map = Node>::upd_node(map,map->left,map->right); + map->value = value; + return map; } } template Namespace namespace_delete(Namespace map, PgfText* name, - ref *pvalue = NULL) + ref *pvalue) { if (map == 0) { if (pvalue != NULL) *pvalue = 0; @@ -472,41 +336,33 @@ Namespace namespace_delete(Namespace map, PgfText* name, int cmp = textcmp(name,&map->value->name); if (cmp < 0) { Namespace left = namespace_delete(map->left, name, pvalue); - if (left == map->left) - return map; - Namespace node = Node>::balanceR(map->value,left,map->right); - namespace_release(left); - return node; + map = Node>::upd_node(map,left,map->right); + return Node>::balanceR(map); } else if (cmp > 0) { Namespace right = namespace_delete(map->right, name, pvalue); - if (right == map->right) - return map; - Namespace node = Node>::balanceL(map->value,map->left,right); - namespace_release(right); - return node; + map = Node>::upd_node(map,map->left,right); + return Node>::balanceL(map); } else { if (pvalue != NULL) *pvalue = map->value; if (map->left == 0) { - if (map->right != 0) - map->right->ref_count++; + Node>::release(map); return map->right; } else if (map->right == 0) { - if (map->left != 0) - map->left->ref_count++; + Node>::release(map); return map->left; } else if (map->left->sz > map->right->sz) { - ref value; - Namespace new_left = Node>::pop_last(map->left, &value); - Namespace node = Node>::balanceR(value, new_left, map->right); - namespace_release(new_left); - return node; + Namespace node; + Namespace left = Node>::pop_last(map->left, &node); + node = Node>::upd_node(node, left, map->right); + Node>::release(map); + return Node>::balanceR(node); } else { - ref value; - Namespace new_right = Node>::pop_first(map->right, &value); - Namespace node = Node>::balanceL(value, map->left, new_right); - namespace_release(new_right); - return node; + Namespace node; + Namespace right = Node>::pop_first(map->right, &node); + node = Node>::upd_node(node, map->left, right); + Node>::release(map); + return Node>::balanceL(node); } } } @@ -554,6 +410,10 @@ void namespace_iter(Namespace map, PgfItor* itor, PgfExn *err) template void namespace_release(Namespace node) { + if (node == 0) + return; + namespace_release(node->left); + namespace_release(node->right); Node>::release(node); } diff --git a/src/runtime/c/pgf/pgf.cxx b/src/runtime/c/pgf/pgf.cxx index c629d28fa..3f7fdd345 100644 --- a/src/runtime/c/pgf/pgf.cxx +++ b/src/runtime/c/pgf/pgf.cxx @@ -36,9 +36,6 @@ pgf_exn_clear(PgfExn* err) err->msg = strdup(e.what()); \ } -PGF_INTERNAL size_t master_size = 6; -PGF_INTERNAL char master_text[] = {'m','a','s','t','e','r',0}; - PGF_API PgfDB *pgf_read_pgf(const char* fpath, PgfRevision *revision, @@ -57,18 +54,21 @@ PgfDB *pgf_read_pgf(const char* fpath, { DB_scope scope(db, WRITER_SCOPE); + db->start_transaction(); + PgfReader rdr(in); ref pgf = rdr.read_pgf(); - PgfDB::set_revision(pgf); - *revision = pgf.as_object(); + db->set_active_revision(pgf.as_object()); + db->register_revision(*revision = pgf.tagged()); + + db->commit(); } db->ref_count++; return db; } PGF_API_END -end: if (in != NULL) fclose(in); @@ -103,13 +103,15 @@ PgfDB *pgf_boot_ngf(const char* pgf_path, const char* ngf_path, { DB_scope scope(db, WRITER_SCOPE); + db->start_transaction(); + PgfReader rdr(in); ref pgf = rdr.read_pgf(); - PgfDB::set_revision(pgf); - *revision = pgf.as_object(); + db->set_active_revision(pgf.as_object()); + db->register_revision(*revision = pgf.tagged()); - PgfDB::sync(); + db->commit(); } db->ref_count++; @@ -137,18 +139,13 @@ PgfDB *pgf_read_ngf(const char *fpath, PGF_API_BEGIN { db = new PgfDB(fpath, O_RDWR, 0); - PgfText *master = (PgfText *)alloca(sizeof(PgfText)+master_size+1); - master->size = master_size; - memcpy(&master->text, master_text, master_size+1); - { DB_scope scope(db, WRITER_SCOPE); db->cleanup_revisions(); - ref pgf = PgfDB::get_revision(master); - Node>::add_value_ref(pgf); - *revision = pgf.as_object(); + ref pgf = db->get_active_revision(); + db->register_revision(*revision = pgf.tagged()); } db->ref_count++; @@ -181,8 +178,9 @@ PgfDB *pgf_new_ngf(PgfText *abstract_name, { DB_scope scope(db, WRITER_SCOPE); - ref pgf = PgfDB::malloc(master_size+1); - pgf->ref_count = 1; + db->start_transaction(); + + ref pgf = PgfDB::malloc(); pgf->major_version = PGF_MAJOR_VERSION; pgf->minor_version = PGF_MINOR_VERSION; pgf->gflags = 0; @@ -192,14 +190,10 @@ PgfDB *pgf_new_ngf(PgfText *abstract_name, pgf->abstract.funs = 0; pgf->abstract.cats = 0; pgf->concretes = 0; - pgf->prev = 0; - pgf->next = 0; - pgf->name.size = master_size; - memcpy(&pgf->name.text, master_text, master_size+1); - PgfDB::set_revision(pgf); - *revision = pgf.as_object(); + db->set_active_revision(pgf.as_object()); + db->register_revision(*revision = pgf.tagged()); - PgfDB::sync(); + db->commit(); } db->ref_count++; @@ -230,14 +224,13 @@ void pgf_merge_pgf(PgfDB *db, PgfRevision revision, { DB_scope scope(db, WRITER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); PgfReader rdr(in); rdr.merge_pgf(pgf); } } PGF_API_END -end: if (in != NULL) fclose(in); } @@ -257,7 +250,7 @@ void pgf_write_pgf(const char* fpath, { DB_scope scope(db, READER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); PgfWriter wtr(out); wtr.write_pgf(pgf); @@ -273,22 +266,8 @@ PGF_API_DECL void pgf_free_revision(PgfDB *db, PgfRevision revision) { try { - DB_scope scope(db, READER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); - - if (pgf->ref_count == 1 && PgfDB::is_persistant_revision(pgf)) { - // Someone is trying to release the last reference count - // to a persistant revision. Most likely this is an - // error in the reference counting for one of the clients. - // The best that we can do is to ignore the request. - return; - } - - if (!(--pgf->ref_count)) { - PgfDB::unlink_transient_revision(pgf); - PgfPGF::release(pgf); - } - + ref pgf = db->revision2pgf(revision); + db->unregister_revision(pgf.tagged()); db->ref_count--; } catch (std::runtime_error& e) { // silently ignore and hope for the best @@ -303,16 +282,8 @@ void pgf_free_concr_revision(PgfDB *db, PgfConcrRevision revision) { try { DB_scope scope(db, READER_SCOPE); - ref concr = PgfDB::revision2concr(revision); - - if (!(--concr->ref_count_ex)) { - PgfDB::unlink_transient_revision(concr); - } - - if (!(--concr->ref_count)) { - PgfConcr::release(concr); - } - + ref concr = db->revision2concr(revision); + db->unregister_revision(concr.tagged()); db->ref_count--; } catch (std::runtime_error& e) { // silently ignore and hope for the best @@ -328,7 +299,7 @@ PgfText *pgf_abstract_name(PgfDB *db, PgfRevision revision, { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); return textdup(&(*pgf->abstract.name)); } PGF_API_END @@ -342,7 +313,7 @@ void pgf_iter_categories(PgfDB *db, PgfRevision revision, { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); namespace_iter(pgf->abstract.cats, itor, err); } PGF_API_END @@ -359,10 +330,9 @@ void iter_concretes_helper(PgfItor *itor, PgfText *key, object value, PgfExn *er { PgfItorConcrHelper* helper = (PgfItorConcrHelper*) itor; ref concr = value; - concr->ref_count++; - concr->ref_count_ex++; + helper->db->register_revision(concr.tagged()); helper->db->ref_count++; - helper->itor->fn(helper->itor, key, value, err); + helper->itor->fn(helper->itor, key, concr.tagged(), err); } PGF_API @@ -371,7 +341,7 @@ void pgf_iter_concretes(PgfDB *db, PgfRevision revision, { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); PgfItorConcrHelper helper; helper.fn = iter_concretes_helper; @@ -389,7 +359,7 @@ PgfType pgf_start_cat(PgfDB *db, PgfRevision revision, { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); PgfText *startcat = (PgfText *) alloca(sizeof(PgfText)+9); @@ -430,7 +400,7 @@ PgfTypeHypo *pgf_category_context(PgfDB *db, PgfRevision revision, { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); ref abscat = namespace_lookup(pgf->abstract.cats, catname); @@ -464,7 +434,7 @@ prob_t pgf_category_prob(PgfDB *db, PgfRevision revision, { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); ref abscat = namespace_lookup(pgf->abstract.cats, catname); @@ -484,7 +454,7 @@ void pgf_iter_functions(PgfDB *db, PgfRevision revision, { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); pgf_exn_clear(err); namespace_iter(pgf->abstract.funs, itor, err); @@ -512,7 +482,7 @@ void pgf_iter_functions_by_cat(PgfDB *db, PgfRevision revision, { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); PgfItorCatHelper helper; helper.fn = iter_by_cat_helper; @@ -530,7 +500,7 @@ PgfType pgf_function_type(PgfDB *db, PgfRevision revision, { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); ref absfun = namespace_lookup(pgf->abstract.funs, funname); @@ -550,7 +520,7 @@ int pgf_function_is_constructor(PgfDB *db, PgfRevision revision, { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); ref absfun = namespace_lookup(pgf->abstract.funs, funname); @@ -570,7 +540,7 @@ prob_t pgf_function_prob(PgfDB *db, PgfRevision revision, { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); ref absfun = namespace_lookup(pgf->abstract.funs, funname); @@ -589,7 +559,7 @@ PgfText *pgf_concrete_name(PgfDB *db, PgfConcrRevision revision, { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref concr = PgfDB::revision2concr(revision); + ref concr = db->revision2concr(revision); return textdup(&concr->name); } PGF_API_END @@ -604,7 +574,7 @@ PgfText *pgf_concrete_language_code(PgfDB *db, PgfConcrRevision revision, PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref concr = PgfDB::revision2concr(revision); + ref concr = db->revision2concr(revision); size_t size = strlen("language"); PgfText *language = (PgfText *) alloca(sizeof(PgfText)+size+1); @@ -670,7 +640,7 @@ prob_t pgf_expr_prob(PgfDB *db, PgfRevision revision, { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); PgfExprProbEstimator estimator(pgf, m); m->match_expr(&estimator, e); @@ -763,7 +733,7 @@ PgfText *pgf_print_start_cat_internal(PgfDB *db, PgfRevision revision, PgfExn *e { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); PgfText *startcat = (PgfText *) alloca(sizeof(PgfText)+9); @@ -808,7 +778,7 @@ void pgf_iter_lincats(PgfDB *db, PgfConcrRevision cnc_revision, { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref concr = PgfDB::revision2concr(cnc_revision); + ref concr = db->revision2concr(cnc_revision); namespace_iter(concr->lincats, itor, err); } PGF_API_END @@ -820,7 +790,7 @@ void pgf_iter_lins(PgfDB *db, PgfConcrRevision cnc_revision, { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref concr = PgfDB::revision2concr(cnc_revision); + ref concr = db->revision2concr(cnc_revision); namespace_iter(concr->lins, itor, err); } PGF_API_END @@ -834,7 +804,7 @@ PgfPhrasetableIds *pgf_iter_sequences(PgfDB *db, PgfConcrRevision cnc_revision, { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref concr = PgfDB::revision2concr(cnc_revision); + ref concr = db->revision2concr(cnc_revision); PgfPhrasetableIds *seq_ids = new PgfPhrasetableIds(); seq_ids->start(concr); @@ -1045,7 +1015,7 @@ void pgf_check_expr(PgfDB *db, PgfRevision revision, PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); PgfTypechecker checker(pgf,u); *pe = m->match_expr(&checker, *pe); @@ -1061,7 +1031,7 @@ PgfType pgf_infer_expr(PgfDB *db, PgfRevision revision, PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); PgfTypechecker checker(pgf,u); *pe = m->match_expr(&checker, *pe); @@ -1083,7 +1053,7 @@ void pgf_check_type(PgfDB *db, PgfRevision revision, PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); PgfTypechecker checker(pgf,u); *pty = m->match_type(&checker, *pty); @@ -1091,91 +1061,81 @@ void pgf_check_type(PgfDB *db, PgfRevision revision, } PGF_API -PgfRevision pgf_clone_revision(PgfDB *db, PgfRevision revision, - PgfText *name, - PgfExn *err) +PgfRevision pgf_start_transaction(PgfDB *db, PgfRevision revision, + PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); - size_t name_size = - (name == NULL) ? pgf->name.size : name->size; + db->start_transaction(); - ref new_pgf = PgfDB::malloc(name_size+1); - new_pgf->ref_count = 1; + ref new_pgf = PgfDB::malloc(); new_pgf->major_version = pgf->major_version; new_pgf->minor_version = pgf->minor_version; - new_pgf->gflags = pgf->gflags; - if (pgf->gflags != 0) - Node>::add_node_ref(pgf->gflags); - new_pgf->abstract.name = textdup_db(&(*pgf->abstract.name)); - new_pgf->abstract.aflags = pgf->abstract.aflags; - if (pgf->abstract.aflags != 0) - Node>::add_node_ref(pgf->abstract.aflags); - new_pgf->abstract.funs = pgf->abstract.funs; - if (pgf->abstract.funs != 0) - Node>::add_node_ref(pgf->abstract.funs); - new_pgf->abstract.cats = pgf->abstract.cats; - if (pgf->abstract.cats != 0) - Node>::add_node_ref(pgf->abstract.cats); - new_pgf->concretes = pgf->concretes; - if (pgf->concretes != 0) - Node>::add_node_ref(pgf->concretes); - new_pgf->prev = 0; - new_pgf->next = 0; - PgfDB::link_transient_revision(new_pgf); - - memcpy(&new_pgf->name, ((name == NULL) ? &pgf->name : name), - sizeof(PgfText)+name_size+1); + db->register_revision(new_pgf.tagged()); db->ref_count++; - return new_pgf.as_object(); + return new_pgf.tagged(); } PGF_API_END return 0; } PGF_API -void pgf_commit_revision(PgfDB *db, PgfRevision revision, - PgfExn *err) +void pgf_commit_transaction(PgfDB *db, PgfRevision revision, + PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); - ref new_pgf = PgfDB::revision2pgf(revision); - ref old_pgf = PgfDB::get_revision(&new_pgf->name); + ref new_pgf = db->revision2pgf(revision); + ref old_pgf = db->get_active_revision(); - PgfDB::unlink_transient_revision(new_pgf); - PgfDB::set_revision(new_pgf); + db->set_active_revision(new_pgf.as_object()); if (old_pgf != 0) - PgfDB::link_transient_revision(old_pgf); + PgfPGF::release(old_pgf); - PgfDB::sync(); + db->commit(); } PGF_API_END } PGF_API -PgfRevision pgf_checkout_revision(PgfDB *db, PgfText *name, - PgfExn *err) +void pgf_rollback_transaction(PgfDB *db, PgfRevision revision) +{ + try { + ref pgf = db->revision2pgf(revision); + db->unregister_revision(pgf.tagged()); + db->rollback(); + db->ref_count--; + } catch (std::runtime_error& e) { + // silently ignore and hope for the best + } + + if (!db->ref_count) + delete db; +} + +PGF_API +PgfRevision pgf_checkout_revision(PgfDB *db, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); - ref pgf = PgfDB::get_revision(name); + ref pgf = db->get_active_revision(); if (pgf != 0) { - Node>::add_value_ref(pgf); + db->register_revision(pgf.tagged()); db->ref_count++; } - return pgf.as_object(); + return pgf.tagged(); } PGF_API_END return 0; @@ -1194,9 +1154,8 @@ void pgf_create_function(PgfDB *db, PgfRevision revision, PgfDBUnmarshaller u(m); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); ref absfun = PgfDB::malloc(name->size+1); - absfun->ref_count = 1; absfun->type = m->match_type(&u, ty); absfun->arity = arity; absfun->bytecode = bytecode ? PgfDB::malloc(0) : 0; @@ -1205,7 +1164,6 @@ void pgf_create_function(PgfDB *db, PgfRevision revision, Namespace funs = namespace_insert(pgf->abstract.funs, absfun); - namespace_release(pgf->abstract.funs); pgf->abstract.funs = funs; } PGF_API_END } @@ -1218,11 +1176,13 @@ void pgf_drop_function(PgfDB *db, PgfRevision revision, PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); + ref fun; Namespace funs = - namespace_delete(pgf->abstract.funs, name); - namespace_release(pgf->abstract.funs); + namespace_delete(pgf->abstract.funs, name, &fun); + if (fun != 0) + PgfAbsFun::release(fun); pgf->abstract.funs = funs; } PGF_API_END } @@ -1239,9 +1199,8 @@ void pgf_create_category(PgfDB *db, PgfRevision revision, PgfDBUnmarshaller u(m); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); ref abscat = PgfDB::malloc(name->size+1); - abscat->ref_count = 1; abscat->context = vector_new(n_hypos); abscat->prob = prob; memcpy(&abscat->name, name, sizeof(PgfText)+name->size+1); @@ -1254,7 +1213,6 @@ void pgf_create_category(PgfDB *db, PgfRevision revision, Namespace cats = namespace_insert(pgf->abstract.cats, abscat); - namespace_release(pgf->abstract.cats); pgf->abstract.cats = cats; } PGF_API_END } @@ -1267,11 +1225,13 @@ void pgf_drop_category(PgfDB *db, PgfRevision revision, PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); + ref cat; Namespace cats = - namespace_delete(pgf->abstract.cats, name); - namespace_release(pgf->abstract.cats); + namespace_delete(pgf->abstract.cats, name, &cat); + if (cat != 0) + PgfAbsCat::release(cat); pgf->abstract.cats = cats; } PGF_API_END } @@ -1284,7 +1244,7 @@ PgfConcrRevision pgf_create_concrete(PgfDB *db, PgfRevision revision, PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); ref concr = namespace_lookup(pgf->concretes, name); @@ -1292,8 +1252,6 @@ PgfConcrRevision pgf_create_concrete(PgfDB *db, PgfRevision revision, throw pgf_error("The concrete syntax already exists"); concr = PgfDB::malloc(name->size+1); - concr->ref_count = 2; - concr->ref_count_ex = 1; concr->cflags = 0; concr->lins = 0; concr->lincats = 0; @@ -1303,15 +1261,14 @@ PgfConcrRevision pgf_create_concrete(PgfDB *db, PgfRevision revision, concr->next = 0; memcpy(&concr->name, name, sizeof(PgfText)+name->size+1); - PgfDB::link_transient_revision(concr); + db->register_revision(concr.tagged()); Namespace concrs = namespace_insert(pgf->concretes, concr); - namespace_release(pgf->concretes); pgf->concretes = concrs; db->ref_count++; - return concr.as_object(); + return concr.tagged(); } PGF_API_END return 0; } @@ -1324,7 +1281,7 @@ PgfConcrRevision pgf_clone_concrete(PgfDB *db, PgfRevision revision, PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); ref concr = namespace_lookup(pgf->concretes, name); @@ -1332,42 +1289,23 @@ PgfConcrRevision pgf_clone_concrete(PgfDB *db, PgfRevision revision, throw pgf_error("Unknown concrete syntax"); ref clone = PgfDB::malloc(name->size+1); - clone->ref_count = 2; - clone->ref_count_ex = 1; - clone->cflags = concr->cflags; - if (clone->cflags != 0) - Node>::add_node_ref(clone->cflags); - clone->lins = concr->lins; - if (clone->lins != 0) - Node>::add_node_ref(clone->lins); - clone->lincats = concr->lincats; - if (clone->lincats != 0) - Node>::add_node_ref(clone->lincats); - clone->phrasetable = concr->phrasetable; - if (clone->phrasetable != 0) - Node::add_node_ref(clone->phrasetable); - clone->printnames = concr->printnames; - if (clone->printnames != 0) - Node>::add_node_ref(clone->printnames); - clone->prev = 0; clone->next = 0; memcpy(&clone->name, name, sizeof(PgfText)+name->size+1); - PgfDB::link_transient_revision(clone); + db->register_revision(clone.tagged()); Namespace concrs = namespace_insert(pgf->concretes, clone); - namespace_release(pgf->concretes); pgf->concretes = concrs; db->ref_count++; - return clone.as_object(); + return clone.tagged(); } PGF_API_END return 0; } @@ -1380,11 +1318,13 @@ void pgf_drop_concrete(PgfDB *db, PgfRevision revision, PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); + ref concr; Namespace concrs = - namespace_delete(pgf->concretes, name); - namespace_release(pgf->concretes); + namespace_delete(pgf->concretes, name, &concr); + if (concr != 0) + PgfConcr::release(concr); pgf->concretes = concrs; } PGF_API_END } @@ -1456,7 +1396,6 @@ public: ref lincat = PgfDB::malloc(abscat->name.size+1); memcpy(&lincat->name, &abscat->name, sizeof(PgfText)+abscat->name.size+1); - lincat->ref_count = 1; lincat->abscat = abscat; lincat->args = args; lincat->res = res; @@ -1464,7 +1403,7 @@ public: lincat->fields = db_fields; lincat->n_lindefs = n_lindefs; - this->container = ref::tagged(lincat); + this->container = lincat.tagged(); build->build(this, err); if (err->type == PGF_EXN_NONE && res_index != res->len) { @@ -1473,12 +1412,6 @@ public: } if (err->type != PGF_EXN_NONE) { - failed(); - for (size_t i = 0; i < n_fields; i++) { - PgfDB::free(*vector_elem(db_fields, i)); - } - PgfDB::free(db_fields); - PgfDB::free(lincat); return 0; } @@ -1501,13 +1434,12 @@ public: ref lin = PgfDB::malloc(absfun->name.size+1); memcpy(&lin->name, &absfun->name, sizeof(PgfText)+absfun->name.size+1); - lin->ref_count = 1; lin->absfun = absfun; lin->args = args; lin->res = res; lin->seqs = seqs; - this->container = ref::tagged(lin); + this->container = lin.tagged(); build->build(this, err); if (err->type == PGF_EXN_NONE && res_index != res->len) { @@ -1516,8 +1448,6 @@ public: } if (err->type != PGF_EXN_NONE) { - failed(); - PgfDB::free(lin); return 0; } @@ -1623,7 +1553,6 @@ public: throw pgf_error(builder_error_msg); seq = PgfDB::malloc(n_syms*sizeof(PgfSymbol)); - seq->ref_count = 1; seq->syms.len = n_syms; *vector_elem(seqs, seq_index) = seq; @@ -1650,7 +1579,7 @@ public: symcat->r.terms[i].var = terms[2*i+1]; } - *vector_elem(&seq->syms, sym_index) = ref::tagged(symcat); + *vector_elem(&seq->syms, sym_index) = symcat.tagged(); sym_index++; } PGF_API_END } @@ -1674,7 +1603,7 @@ public: symlit->r.terms[i].var = terms[2*i+1]; } - *vector_elem(&seq->syms, sym_index) = ref::tagged(symlit); + *vector_elem(&seq->syms, sym_index) = symlit.tagged(); sym_index++; } PGF_API_END } @@ -1692,7 +1621,7 @@ public: symvar->d = d; symvar->r = r; - *vector_elem(&seq->syms, sym_index) = ref::tagged(symvar); + *vector_elem(&seq->syms, sym_index) = symvar.tagged(); sym_index++; } PGF_API_END } @@ -1709,7 +1638,7 @@ public: ref symtok = PgfDB::malloc(token->size+1); memcpy(&symtok->token, token, sizeof(PgfText)+token->size+1); - *vector_elem(&seq->syms, sym_index) = ref::tagged(symtok); + *vector_elem(&seq->syms, sym_index) = symtok.tagged(); sym_index++; } PGF_API_END } @@ -1724,14 +1653,13 @@ public: throw pgf_error(builder_error_msg); ref def = PgfDB::malloc(n_syms*sizeof(PgfSymbol)); - def->ref_count = 1; def->syms.len = n_syms; ref symkp = PgfDB::malloc(n_alts*sizeof(PgfAlternative)); symkp->default_form = def; symkp->alts.len = n_alts; - *vector_elem(&seq->syms, sym_index) = ref::tagged(symkp); + *vector_elem(&seq->syms, sym_index) = symkp.tagged(); pre_sym_index = sym_index; seq = def; @@ -1750,7 +1678,6 @@ public: throw pgf_error(builder_error_msg); ref form = PgfDB::malloc(n_syms*sizeof(PgfSymbol)); - form->ref_count = 1; form->syms.len = n_syms; ref>> prefixes = vector_new>(n_prefs); @@ -1814,7 +1741,7 @@ public: if (seq == 0 || sym_index == (size_t) -1 || sym_index >= seq->syms.len) throw pgf_error(builder_error_msg); - *vector_elem(&seq->syms, sym_index) = ref::tagged(0); + *vector_elem(&seq->syms, sym_index) = ref(0).tagged(); sym_index++; } PGF_API_END } @@ -1828,7 +1755,7 @@ public: if (seq == 0 || sym_index == (size_t) -1 || sym_index >= seq->syms.len) throw pgf_error(builder_error_msg); - *vector_elem(&seq->syms, sym_index) = ref::tagged(0); + *vector_elem(&seq->syms, sym_index) = ref(0).tagged(); sym_index++; } PGF_API_END } @@ -1842,7 +1769,7 @@ public: if (seq == 0 || sym_index == (size_t) -1 || sym_index >= seq->syms.len) throw pgf_error(builder_error_msg); - *vector_elem(&seq->syms, sym_index) = ref::tagged(0); + *vector_elem(&seq->syms, sym_index) = ref(0).tagged(); sym_index++; } PGF_API_END } @@ -1856,7 +1783,7 @@ public: if (seq == 0 || sym_index == (size_t) -1 || sym_index >= seq->syms.len) throw pgf_error(builder_error_msg); - *vector_elem(&seq->syms, sym_index) = ref::tagged(0); + *vector_elem(&seq->syms, sym_index) = ref(0).tagged(); sym_index++; } PGF_API_END } @@ -1870,7 +1797,7 @@ public: if (seq == 0 || sym_index == (size_t) -1 || sym_index >= seq->syms.len) throw pgf_error(builder_error_msg); - *vector_elem(&seq->syms, sym_index) = ref::tagged(0); + *vector_elem(&seq->syms, sym_index) = ref(0).tagged(); sym_index++; } PGF_API_END } @@ -1884,7 +1811,7 @@ public: if (seq == 0 || sym_index == (size_t) -1 || sym_index >= seq->syms.len) throw pgf_error(builder_error_msg); - *vector_elem(&seq->syms, sym_index) = ref::tagged(0); + *vector_elem(&seq->syms, sym_index) = ref(0).tagged(); sym_index++; } PGF_API_END } @@ -1894,7 +1821,7 @@ public: if (err->type != PGF_EXN_NONE) return 0; - ref res = 0; + ref entry = 0; PGF_API_BEGIN { if (seq == 0 || sym_index != seq->syms.len) @@ -1902,20 +1829,17 @@ public: PgfPhrasetable phrasetable = phrasetable_internalize(concr->phrasetable, - container, seq_index, - &seq); - phrasetable_release(concr->phrasetable); + seq, container, seq_index, + &entry); concr->phrasetable = phrasetable; - *vector_elem(seqs, seq_index) = seq; - - res = seq; + *vector_elem(seqs, seq_index) = entry->seq; sym_index = (size_t) -1; seq = 0; seq_index++; } PGF_API_END - return res.as_object(); + return entry.as_object(); } void add_sequence_id(object seq_id, PgfExn *err) @@ -1927,16 +1851,16 @@ public: if (seq_index >= seqs->len) throw pgf_error(builder_error_msg); - ref seq = seq_id; - seq->ref_count++; + ref entry = seq_id; - PgfPhrasetable phrasetable = - phrasetable_internalize(concr->phrasetable, - container, seq_index, - &seq); - phrasetable_release(concr->phrasetable); - concr->phrasetable = phrasetable; - *vector_elem(seqs, seq_index) = seq; + size_t len = entry->backrefs->len; + ref> backrefs = + vector_unsafe_resize(entry->backrefs, len+1); + backrefs->data[len].container = container; + backrefs->data[len].seq_index = seq_index; + entry->backrefs = backrefs; + + *vector_elem(seqs, seq_index) = entry->seq; seq_index++; } PGF_API_END @@ -1965,71 +1889,6 @@ public: res_index++; } PGF_API_END } - - void failed() - { - for (size_t i = 0; i < arg_index; i++) { - PgfDB::free(vector_elem(args, i)->param); - } - PgfDB::free(args); - - for (size_t i = 0; i < res_index; i++) { - ref res_elem = *vector_elem(res, i); - PgfDB::free(res_elem->vars); - PgfDB::free(res_elem); - } - PgfDB::free(res); - - for (size_t i = 0; i < seq_index; i++) { - ref seq = *vector_elem(seqs, i); - PgfSequence::release(seq); - } - - if (sym_index != (size_t) -1) { - ref seq = *vector_elem(seqs, seq_index); - - if (pre_sym_index != (size_t) -1) { - auto sym_kp = ref::untagged(*vector_elem(&seq->syms, pre_sym_index)); - - if (this->seq == sym_kp->default_form) { - for (size_t i = 0; i < sym_index; i++) { - PgfSymbol sym = *vector_elem(&seq->syms, i); - pgf_symbol_free(sym); - } - PgfDB::free(seq); - } else { - PgfSequence::release(sym_kp->default_form); - for (size_t i = 0; i < alt_index; i++) { - PgfSequence::release(sym_kp->alts.data[i].form); - for (size_t j = 0; j < sym_kp->alts.data[i].prefixes->len; j++) { - ref prefix = *vector_elem(sym_kp->alts.data[i].prefixes, j); - PgfDB::free(prefix); - } - } - for (size_t i = 0; i < sym_index; i++) { - PgfSymbol sym = *vector_elem(&sym_kp->alts.data[alt_index].form->syms, i); - pgf_symbol_free(sym); - } - PgfDB::free(sym_kp->alts.data[alt_index].form); - for (size_t i = 0; i < sym_kp->alts.data[alt_index].prefixes->len; i++) { - ref prefix = *vector_elem(sym_kp->alts.data[alt_index].prefixes, i); - PgfDB::free(prefix); - } - } - PgfDB::free(sym_kp); - - sym_index = pre_sym_index; - } - - for (size_t j = 0; j < sym_index; j++) { - PgfSymbol sym = *vector_elem(&seq->syms, j); - pgf_symbol_free(sym); - } - PgfDB::free(seq); - } - - PgfDB::free(seqs); - } }; @@ -2043,8 +1902,8 @@ void pgf_create_lincat(PgfDB *db, PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); - ref concr = PgfDB::revision2concr(cnc_revision); + ref pgf = db->revision2pgf(revision); + ref concr = db->revision2concr(cnc_revision); ref abscat = namespace_lookup(pgf->abstract.cats, name); @@ -2057,7 +1916,6 @@ void pgf_create_lincat(PgfDB *db, if (lincat != 0) { Namespace lincats = namespace_insert(concr->lincats, lincat); - namespace_release(concr->lincats); concr->lincats = lincats; } } PGF_API_END @@ -2071,22 +1929,21 @@ void pgf_drop_lincat(PgfDB *db, PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); - ref concr = PgfDB::revision2concr(revision); + ref concr = db->revision2concr(revision); ref lincat; Namespace lincats = namespace_delete(concr->lincats, name, &lincat); if (lincat != 0) { - object container = ref::tagged(lincat); + object container = lincat.tagged(); for (size_t i = 0; i < lincat->seqs->len; i++) { ref seq = *vector_elem(lincat->seqs, i); - PgfPhrasetable new_phrasetable = + PgfPhrasetable phrasetable = phrasetable_delete(concr->phrasetable,container,i,seq); - phrasetable_release(concr->phrasetable); - concr->phrasetable = new_phrasetable; + concr->phrasetable = phrasetable; } + PgfConcrLincat::release(lincat); } - namespace_release(concr->lincats); concr->lincats = lincats; } PGF_API_END } @@ -2104,8 +1961,8 @@ void pgf_create_lin(PgfDB *db, PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); - ref concr = PgfDB::revision2concr(cnc_revision); + ref pgf = db->revision2pgf(revision); + ref concr = db->revision2concr(cnc_revision); ref absfun = namespace_lookup(pgf->abstract.funs, name); @@ -2118,7 +1975,6 @@ void pgf_create_lin(PgfDB *db, if (lin != 0) { Namespace lins = namespace_insert(concr->lins, lin); - namespace_release(concr->lins); concr->lins = lins; } } PGF_API_END @@ -2132,22 +1988,21 @@ void pgf_drop_lin(PgfDB *db, PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); - ref concr = PgfDB::revision2concr(revision); + ref concr = db->revision2concr(revision); ref lin; Namespace lins = namespace_delete(concr->lins, name, &lin); if (lin != 0) { - object container = ref::tagged(lin); + object container = lin.tagged(); for (size_t i = 0; i < lin->seqs->len; i++) { ref seq = *vector_elem(lin->seqs, i); - PgfPhrasetable new_phrasetable = + PgfPhrasetable phrasetable = phrasetable_delete(concr->phrasetable,container,i,seq); - phrasetable_release(concr->phrasetable); - concr->phrasetable = new_phrasetable; + concr->phrasetable = phrasetable; } + PgfConcrLin::release(lin); } - namespace_release(concr->lins); concr->lins = lins; } PGF_API_END } @@ -2159,7 +2014,7 @@ int pgf_has_linearization(PgfDB *db, PgfConcrRevision revision, PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref concr = PgfDB::revision2concr(revision); + ref concr = db->revision2concr(revision); ref lin = namespace_lookup(concr->lins, name); @@ -2178,7 +2033,7 @@ PgfText **pgf_category_fields(PgfDB *db, PgfConcrRevision revision, PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref concr = PgfDB::revision2concr(revision); + ref concr = db->revision2concr(revision); ref lincat = namespace_lookup(concr->lincats, name); @@ -2211,7 +2066,7 @@ PgfText *pgf_linearize(PgfDB *db, PgfConcrRevision revision, PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref concr = PgfDB::revision2concr(revision); + ref concr = db->revision2concr(revision); PgfLinearizationOutput out; PgfLinearizer linearizer(ctxt, concr, m); m->match_expr(&linearizer, expr); @@ -2237,7 +2092,7 @@ PgfText **pgf_linearize_all(PgfDB *db, PgfConcrRevision revision, PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref concr = PgfDB::revision2concr(revision); + ref concr = db->revision2concr(revision); PgfLinearizationOutput out; PgfLinearizer linearizer(ctxt, concr, m); m->match_expr(&linearizer, expr); @@ -2264,7 +2119,7 @@ PgfText **pgf_tabular_linearize(PgfDB *db, PgfConcrRevision revision, PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref concr = PgfDB::revision2concr(revision); + ref concr = db->revision2concr(revision); PgfLinearizationOutput out; PgfLinearizer linearizer(ctxt, concr, m); m->match_expr(&linearizer, expr); @@ -2304,7 +2159,7 @@ PgfText **pgf_tabular_linearize_all(PgfDB *db, PgfConcrRevision revision, PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref concr = PgfDB::revision2concr(revision); + ref concr = db->revision2concr(revision); PgfLinearizationOutput out; PgfLinearizer linearizer(ctxt, concr, m); m->match_expr(&linearizer, expr); @@ -2344,7 +2199,7 @@ void pgf_bracketed_linearize(PgfDB *db, PgfConcrRevision revision, PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref concr = PgfDB::revision2concr(revision); + ref concr = db->revision2concr(revision); PgfLinearizer linearizer(ctxt, concr, m); m->match_expr(&linearizer, expr); linearizer.reverse_and_label(true); @@ -2364,7 +2219,7 @@ void pgf_bracketed_linearize_all(PgfDB *db, PgfConcrRevision revision, PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref concr = PgfDB::revision2concr(revision); + ref concr = db->revision2concr(revision); PgfLinearizer linearizer(ctxt, concr, m); m->match_expr(&linearizer, expr); linearizer.reverse_and_label(true); @@ -2382,7 +2237,7 @@ PgfText *pgf_get_printname(PgfDB *db, PgfConcrRevision revision, PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref concr = PgfDB::revision2concr(revision); + ref concr = db->revision2concr(revision); PgfText *printname = namespace_lookup(concr->printnames, fun)->printname; return textdup(printname); } PGF_API_END @@ -2397,16 +2252,14 @@ void pgf_set_printname(PgfDB *db, PgfConcrRevision revision, PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); - ref concr = PgfDB::revision2concr(revision); + ref concr = db->revision2concr(revision); ref printname = PgfDB::malloc(fun->size+1); - printname->ref_count = 1; memcpy(&printname->name, fun, sizeof(PgfText)+fun->size+1); printname->printname = textdup_db(name); Namespace printnames = namespace_insert(concr->printnames, printname); - namespace_release(concr->printnames); concr->printnames = printnames; } PGF_API_END } @@ -2420,7 +2273,7 @@ PgfLiteral pgf_get_global_flag(PgfDB *db, PgfRevision revision, PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); ref flag = namespace_lookup(pgf->gflags, name); @@ -2444,16 +2297,14 @@ void pgf_set_global_flag(PgfDB *db, PgfRevision revision, PgfDBUnmarshaller u(m); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); ref flag = PgfDB::malloc(name->size+1); - flag->ref_count = 1; memcpy(&flag->name, name, sizeof(PgfText)+name->size+1); PgfLiteral lit = m->match_lit(&u, value); flag->value = lit; Namespace gflags = namespace_insert(pgf->gflags, flag); - namespace_release(pgf->gflags); pgf->gflags = gflags; } PGF_API_END } @@ -2467,7 +2318,7 @@ PgfLiteral pgf_get_abstract_flag(PgfDB *db, PgfRevision revision, PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); ref flag = namespace_lookup(pgf->abstract.aflags, name); @@ -2491,16 +2342,14 @@ void pgf_set_abstract_flag(PgfDB *db, PgfRevision revision, PgfDBUnmarshaller u(m); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); ref flag = PgfDB::malloc(name->size+1); - flag->ref_count = 1; memcpy(&flag->name, name, sizeof(PgfText)+name->size+1); PgfLiteral lit = m->match_lit(&u, value); flag->value = lit; Namespace aflags = namespace_insert(pgf->abstract.aflags, flag); - namespace_release(pgf->abstract.aflags); pgf->abstract.aflags = aflags; } PGF_API_END } @@ -2514,7 +2363,7 @@ PgfLiteral pgf_get_concrete_flag(PgfDB *db, PgfConcrRevision revision, PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref concr = PgfDB::revision2concr(revision); + ref concr = db->revision2concr(revision); ref flag = namespace_lookup(concr->cflags, name); @@ -2538,16 +2387,14 @@ void pgf_set_concrete_flag(PgfDB *db, PgfConcrRevision revision, PgfDBUnmarshaller u(m); - ref concr = PgfDB::revision2concr(revision); + ref concr = db->revision2concr(revision); ref flag = PgfDB::malloc(name->size+1); - flag->ref_count = 1; memcpy(&flag->name, name, sizeof(PgfText)+name->size+1); PgfLiteral lit = m->match_lit(&u, value); flag->value = lit; Namespace cflags = namespace_insert(concr->cflags, flag); - namespace_release(concr->cflags); concr->cflags = cflags; } PGF_API_END } @@ -2561,7 +2408,7 @@ pgf_graphviz_abstract_tree(PgfDB *db, PgfRevision revision, PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref pgf = PgfDB::revision2pgf(revision); + ref pgf = db->revision2pgf(revision); PgfAbstractGraphvizOutput out(&pgf->abstract, opts, m); return out.generate_graphviz(expr); @@ -2580,7 +2427,7 @@ pgf_graphviz_parse_tree(PgfDB *db, PgfConcrRevision revision, PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); - ref concr = PgfDB::revision2concr(revision); + ref concr = db->revision2concr(revision); PgfLinearizationGraphvizOutput out; PgfLinearizer linearizer(ctxt, concr, m); diff --git a/src/runtime/c/pgf/pgf.h b/src/runtime/c/pgf/pgf.h index f04d456fa..cd85b940c 100644 --- a/src/runtime/c/pgf/pgf.h +++ b/src/runtime/c/pgf/pgf.h @@ -462,18 +462,19 @@ void pgf_check_type(PgfDB *db, PgfRevision revision, PgfExn *err); PGF_API_DECL -PgfRevision pgf_clone_revision(PgfDB *db, PgfRevision revision, - PgfText *name, - PgfExn *err); - -PGF_API_DECL -void pgf_commit_revision(PgfDB *db, PgfRevision revision, - PgfExn *err); - -PGF_API_DECL -PgfRevision pgf_checkout_revision(PgfDB *db, PgfText *name, +PgfRevision pgf_start_transaction(PgfDB *db, PgfRevision revision, PgfExn *err); +PGF_API_DECL +void pgf_commit_transaction(PgfDB *db, PgfRevision revision, + PgfExn *err); + +PGF_API_DECL +void pgf_rollback_transaction(PgfDB *db, PgfRevision revision); + +PGF_API_DECL +PgfRevision pgf_checkout_revision(PgfDB *db, PgfExn *err); + PGF_API_DECL void pgf_create_function(PgfDB *db, PgfRevision revision, PgfText *name, diff --git a/src/runtime/c/pgf/phrasetable.cxx b/src/runtime/c/pgf/phrasetable.cxx index fded45661..38fa7da64 100644 --- a/src/runtime/c/pgf/phrasetable.cxx +++ b/src/runtime/c/pgf/phrasetable.cxx @@ -72,24 +72,6 @@ void PgfPhrasetableIds::end() pairs = NULL; } -void PgfPhrasetableEntry::add_ref() -{ - seq->ref_count++; - if (backrefs != 0) - backrefs->ref_count++; -} - -void PgfPhrasetableEntry::release_ref() -{ - if (!(--seq->ref_count)) { - PgfSequence::release(seq); - } - - if (backrefs != 0 && !(--backrefs->ref_count)) { - PgfSequenceBackrefs::release(backrefs); - } -} - static int lparam_cmp(PgfLParam *p1, PgfLParam *p2) { @@ -247,65 +229,57 @@ int sequence_cmp(ref seq1, ref seq2) PGF_INTERNAL PgfPhrasetable phrasetable_internalize(PgfPhrasetable table, + ref seq, object container, size_t seq_index, - ref *pseq) + ref *pentry) { if (table == 0) { PgfPhrasetableEntry entry; - entry.seq = *pseq; - entry.backrefs = PgfDB::malloc(sizeof(PgfSequenceBackref)); - entry.backrefs->ref_count = 1; - entry.backrefs->list.len = 1; - entry.backrefs->list.data[0].container = container; - entry.backrefs->list.data[0].seq_index = seq_index; - entry.seq->ref_count++; - return Node::new_node(entry); + entry.seq = seq; + entry.backrefs = vector_new(1); + entry.backrefs->data[0].container = container; + entry.backrefs->data[0].seq_index = seq_index; + PgfPhrasetable new_table = Node::new_node(entry); + *pentry = ref::from_ptr(&new_table->value); + return new_table; } - int cmp = sequence_cmp(*pseq,table->value.seq); + int cmp = sequence_cmp(seq,table->value.seq); if (cmp < 0) { PgfPhrasetable left = phrasetable_internalize(table->left, + seq, container, seq_index, - pseq); - PgfPhrasetable node = Node::balanceL(table->value,left,table->right); - phrasetable_release(left); - return node; + pentry); + table = Node::upd_node(table,left,table->right); + return Node::balanceL(table); } else if (cmp > 0) { PgfPhrasetable right = phrasetable_internalize(table->right, + seq, container, seq_index, - pseq); - PgfPhrasetable node = Node::balanceR(table->value, table->left, right); - phrasetable_release(right); - return node; + pentry); + table = Node::upd_node(table, table->left, right); + return Node::balanceR(table); } else { - if (!(--(*pseq)->ref_count)) { - PgfSequence::release(*pseq); - } - - table->value.seq->ref_count++; - *pseq = table->value.seq; - - if (table->left != 0) - table->left->ref_count++; - if (table->right != 0) - table->right->ref_count++; + PgfSequence::release(seq); size_t len = (table->value.backrefs) - ? table->value.backrefs->list.len + ? table->value.backrefs->len : 0; - PgfPhrasetableEntry entry; - entry.seq = table->value.seq; - entry.backrefs = PgfDB::malloc((len+1)*sizeof(PgfSequenceBackref)); - entry.backrefs->ref_count = 1; - entry.backrefs->list.len = len+1; - memcpy(entry.backrefs->list.data, table->value.backrefs->list.data, len*sizeof(PgfSequenceBackref)); - entry.backrefs->list.data[len].container = container; - entry.backrefs->list.data[len].seq_index = seq_index; - entry.seq->ref_count++; - return Node::new_node(entry,table->left,table->right); + + ref> backrefs = + vector_copy(table->value.backrefs, len+1); + backrefs->data[len].container = container; + backrefs->data[len].seq_index = seq_index; + + PgfPhrasetable new_table = + Node::upd_node(table, table->left, table->right); + Vector::release(new_table->value.backrefs); + new_table->value.backrefs = backrefs; + *pentry = ref::from_ptr(&new_table->value); + return new_table; } } @@ -322,13 +296,12 @@ ref phrasetable_relink(PgfPhrasetable table, else if (seq_id == left_sz) { size_t len = (table->value.backrefs == 0) ? 0 - : table->value.backrefs->list.len; + : table->value.backrefs->len; - ref backrefs = - vector_resize(table->value.backrefs, &PgfSequenceBackrefs::list, len+1); - backrefs->ref_count = 1; - backrefs->list.data[len].container = container; - backrefs->list.data[len].seq_index = seq_index; + ref> backrefs = + vector_unsafe_resize(table->value.backrefs, len+1); + backrefs->data[len].container = container; + backrefs->data[len].seq_index = seq_index; table->value.backrefs = backrefs; return table->value.seq; @@ -355,68 +328,66 @@ PgfPhrasetable phrasetable_delete(PgfPhrasetable table, seq); if (left == table->left) return table; - PgfPhrasetable node = Node::balanceR(table->value,left,table->right); - phrasetable_release(left); - return node; + table = Node::upd_node(table,left,table->right); + return Node::balanceR(table); } else if (cmp > 0) { PgfPhrasetable right = phrasetable_delete(table->right, container, seq_index, seq); if (right == table->right) return table; - PgfPhrasetable node = Node::balanceL(table->value,table->left,right); - phrasetable_release(right); - return node; + table = Node::upd_node(table,table->left,right); + return Node::balanceL(table); } else { - PgfPhrasetableEntry entry; - - size_t len = table->value.backrefs->list.len; + size_t len = table->value.backrefs->len; if (len > 1) { - entry.backrefs = - PgfDB::malloc((len-1)*sizeof(PgfSequenceBackref)); - entry.backrefs->ref_count = 1; - entry.backrefs->list.len = len-1; + ref> backrefs = + vector_new(len-1); size_t i = 0; while (i < len) { - PgfSequenceBackref *backref = - vector_elem(&table->value.backrefs->list, i); + ref backref = + vector_elem(table->value.backrefs, i); if (backref->container == container && backref->seq_index == seq_index) { break; } - *vector_elem(&entry.backrefs->list, i) = *backref; + *vector_elem(backrefs, i) = *backref; i++; } i++; while (i < len) { - PgfSequenceBackref *backref = - vector_elem(&table->value.backrefs->list, i); - *vector_elem(&entry.backrefs->list, i-1) = *backref; + ref backref = + vector_elem(table->value.backrefs, i); + *vector_elem(backrefs, i-1) = *backref; i++; } - entry.seq = table->value.seq; - table->value.seq->ref_count++; - return Node::new_node(entry, table->left, table->right); + PgfPhrasetable new_table = + Node::upd_node(table, table->left, table->right); + Vector::release(new_table->value.backrefs); + new_table->value.backrefs = backrefs; + return new_table; } else { + PgfSequence::release(table->value.seq); + Vector::release(table->value.backrefs); if (table->left == 0) { - if (table->right != 0) - table->right->ref_count++; + Node::release(table); return table->right; } else if (table->right == 0) { - if (table->left != 0) - table->left->ref_count++; + Node::release(table); return table->left; } else if (table->left->sz > table->right->sz) { - PgfPhrasetable new_left = Node::pop_last(table->left, &entry); - PgfPhrasetable node = Node::balanceR(entry, new_left, table->right); - phrasetable_release(new_left); - return node; + PgfPhrasetable node; + PgfPhrasetable left = Node::pop_last(table->left, &node); + node = Node::upd_node(node, left, table->right); + Node::release(table); + return Node::balanceR(node); } else { - PgfPhrasetable new_right = Node::pop_first(table->right, &entry); - PgfPhrasetable node = Node::balanceL(entry, table->left, new_right); - phrasetable_release(new_right); - return node; + PgfPhrasetable node; + PgfPhrasetable right = Node::pop_first(table->right, &node); + node = Node::upd_node(node, table->left, right); + Node::release(table); + return Node::balanceL(node); } } } @@ -448,8 +419,8 @@ void phrasetable_iter(PgfConcr *concr, return; if (table->value.backrefs != 0 && res == 0 && callback != 0) { - for (size_t i = 0; i < table->value.backrefs->list.len; i++) { - PgfSequenceBackref backref = *vector_elem(&table->value.backrefs->list,i); + for (size_t i = 0; i < table->value.backrefs->len; i++) { + PgfSequenceBackref backref = *vector_elem(table->value.backrefs,i); switch (ref::get_tag(backref.container)) { case PgfConcrLin::tag: { ref lin = ref::untagged(backref.container); @@ -481,5 +452,9 @@ void phrasetable_iter(PgfConcr *concr, PGF_INTERNAL void phrasetable_release(PgfPhrasetable table) { + if (table == 0) + return; + phrasetable_release(table->left); + phrasetable_release(table->right); Node::release(table); } diff --git a/src/runtime/c/pgf/phrasetable.h b/src/runtime/c/pgf/phrasetable.h index 987ba9d7f..a60f4e02b 100644 --- a/src/runtime/c/pgf/phrasetable.h +++ b/src/runtime/c/pgf/phrasetable.h @@ -2,14 +2,11 @@ #define PHRASETABLE_H struct PgfSequence; -struct PgfSequenceBackrefs; +struct PgfSequenceBackref; struct PGF_INTERNAL_DECL PgfPhrasetableEntry { ref seq; - ref backrefs; - - void add_ref(); - void release_ref(); + ref> backrefs; }; class PgfSequenceItor; @@ -52,9 +49,10 @@ private: PGF_INTERNAL_DECL PgfPhrasetable phrasetable_internalize(PgfPhrasetable table, + ref seq, object container, size_t seq_index, - ref *seq); + ref *pentry); PGF_INTERNAL_DECL ref phrasetable_relink(PgfPhrasetable table, diff --git a/src/runtime/c/pgf/reader.cxx b/src/runtime/c/pgf/reader.cxx index ef283c762..ef5843899 100644 --- a/src/runtime/c/pgf/reader.cxx +++ b/src/runtime/c/pgf/reader.cxx @@ -115,7 +115,11 @@ Namespace PgfReader::read_namespace(ref (PgfReader::*read_value)(), size_t ref value = (this->*read_value)(); Namespace right = read_namespace(read_value, len-half-1); - return Node>::new_node(value, left, right); + Namespace node = Node>::new_node(value); + node->sz = 1+Node>::size(left)+Node>::size(right); + node->left = left; + node->right = right; + return node; } template @@ -166,7 +170,7 @@ PgfLiteral PgfReader::read_literal() case PgfLiteralStr::tag: { ref lit_str = read_text(&PgfLiteralStr::val); - lit = ref::tagged(lit_str); + lit = lit_str.tagged(); break; } case PgfLiteralInt::tag: { @@ -177,14 +181,14 @@ PgfLiteral PgfReader::read_literal() for (size_t i = 0; i < size; i++) { lit_int->val[i] = (uintmax_t) read_uint(); } - lit = ref::tagged(lit_int); + lit = lit_int.tagged(); break; } case PgfLiteralFlt::tag: { ref lit_flt = current_db->malloc(); lit_flt->val = read_double(); - lit = ref::tagged(lit_flt); + lit = lit_flt.tagged(); break; } default: @@ -196,7 +200,6 @@ PgfLiteral PgfReader::read_literal() ref PgfReader::read_flag() { ref flag = read_name(&PgfFlag::name); - flag->ref_count = 1; flag->value = read_literal(); return flag; } @@ -213,7 +216,7 @@ PgfExpr PgfReader::read_expr() eabs->bind_type = bind_type; PgfExpr body = read_expr(); eabs->body = body; - expr = ref::tagged(eabs); + expr = eabs.tagged(); break; } case PgfExprApp::tag: { @@ -222,31 +225,31 @@ PgfExpr PgfReader::read_expr() ref eapp = PgfDB::malloc(); eapp->fun = fun; eapp->arg = arg; - expr = ref::tagged(eapp); + expr = eapp.tagged(); break; } case PgfExprLit::tag: { PgfExpr lit = read_literal(); ref elit = PgfDB::malloc(); elit->lit = lit; - expr = ref::tagged(elit); + expr = elit.tagged(); break; } case PgfExprMeta::tag: { ref emeta = PgfDB::malloc(); emeta->id = read_int(); - expr = ref::tagged(emeta); + expr = emeta.tagged(); break; } case PgfExprFun::tag: { ref efun = read_name(&PgfExprFun::name); - expr = ref::tagged(efun); + expr = efun.tagged(); break; } case PgfExprVar::tag: { ref evar = PgfDB::malloc(); evar->var = read_int(); - expr = ref::tagged(evar); + expr = evar.tagged(); break; } case PgfExprTyped::tag: { @@ -255,14 +258,14 @@ PgfExpr PgfReader::read_expr() ref etyped = PgfDB::malloc(); etyped->expr = expr; etyped->type = type; - expr = ref::tagged(etyped); + expr = etyped.tagged(); break; } case PgfExprImplArg::tag: { auto expr = read_expr(); ref eimpl = current_db->malloc(); eimpl->expr = expr; - expr = ref::tagged(eimpl); + expr = eimpl.tagged(); break; } default: @@ -297,7 +300,6 @@ ref PgfReader::read_absfun() { ref absfun = read_name(&PgfAbsFun::name); - absfun->ref_count = 1; ref efun = ref::from_ptr((PgfExprFun*) &absfun->name); absfun->type = read_type(); @@ -323,7 +325,6 @@ ref PgfReader::read_absfun() ref PgfReader::read_abscat() { ref abscat = read_name(&PgfAbsCat::name); - abscat->ref_count = 1; abscat->context = read_vector(&PgfReader::read_hypo); abscat->prob = - log(read_double()); return abscat; @@ -345,7 +346,7 @@ void PgfReader::merge_abstract(ref abstract) ref name = read_name(); int cmp = textcmp(&(*abstract->name), &(*name)); - PgfDB::free(name); + text_db_release(name); if (cmp != 0) throw pgf_error("The abstract syntax names doesn't match"); @@ -437,24 +438,24 @@ PgfSymbol PgfReader::read_symbol() switch (tag) { case PgfSymbolCat::tag: { ref sym_cat = read_symbol_idx(); - sym = ref::tagged(sym_cat); + sym = sym_cat.tagged(); break; } case PgfSymbolLit::tag: { ref sym_lit = read_symbol_idx(); - sym = ref::tagged(sym_lit); + sym = sym_lit.tagged(); break; } case PgfSymbolVar::tag: { ref sym_var = PgfDB::malloc(); sym_var->d = read_int(); sym_var->r = read_int(); - sym = ref::tagged(sym_var); + sym = sym_var.tagged(); break; } case PgfSymbolKS::tag: { ref sym_ks = read_text(&PgfSymbolKS::token); - sym = ref::tagged(sym_ks); + sym = sym_ks.tagged(); break; } case PgfSymbolKP::tag: { @@ -473,31 +474,31 @@ PgfSymbol PgfReader::read_symbol() auto default_form = read_seq(); sym_kp->default_form = default_form; - sym = ref::tagged(sym_kp); + sym = sym_kp.tagged(); break; } case PgfSymbolBIND::tag: { - sym = ref::tagged(0); + sym = ref(0).tagged(); break; } case PgfSymbolSOFTBIND::tag: { - sym = ref::tagged(0); + sym = ref(0).tagged(); break; } case PgfSymbolNE::tag: { - sym = ref::tagged(0); + sym = ref(0).tagged(); break; } case PgfSymbolSOFTSPACE::tag: { - sym = ref::tagged(0); + sym = ref(0).tagged(); break; } case PgfSymbolCAPIT::tag: { - sym = ref::tagged(0); + sym = ref(0).tagged(); break; } case PgfSymbolALLCAPIT::tag: { - sym = ref::tagged(0); + sym = ref(0).tagged(); break; } default: @@ -512,7 +513,6 @@ ref PgfReader::read_seq() size_t n_syms = read_len(); ref seq = PgfDB::malloc(n_syms*sizeof(PgfSymbol)); - seq->ref_count = 1; seq->syms.len = n_syms; for (size_t i = 0; i < n_syms; i++) { @@ -553,7 +553,11 @@ PgfPhrasetable PgfReader::read_phrasetable(size_t len) value.backrefs = 0; PgfPhrasetable right = read_phrasetable(len-half-1); - return Node::new_node(value, left, right); + PgfPhrasetable table = Node::new_node(value); + table->sz = 1+Node::size(left)+Node::size(right); + table->left = left; + table->right = right; + return table; } PgfPhrasetable PgfReader::read_phrasetable() @@ -565,31 +569,28 @@ PgfPhrasetable PgfReader::read_phrasetable() ref PgfReader::read_lincat() { ref lincat = read_name(&PgfConcrLincat::name); - lincat->ref_count = 1; lincat->abscat = namespace_lookup(abstract->cats, &lincat->name); lincat->fields = read_vector(&PgfReader::read_text2); lincat->n_lindefs = read_len(); lincat->args = read_vector(&PgfReader::read_parg); lincat->res = read_vector(&PgfReader::read_presult2); - lincat->seqs = read_seq_ids(ref::tagged(lincat)); + lincat->seqs = read_seq_ids(lincat.tagged()); return lincat; } ref PgfReader::read_lin() { ref lin = read_name(&PgfConcrLin::name); - lin->ref_count = 1; lin->absfun = namespace_lookup(abstract->funs, &lin->name); lin->args = read_vector(&PgfReader::read_parg); lin->res = read_vector(&PgfReader::read_presult2); - lin->seqs = read_seq_ids(ref::tagged(lin)); + lin->seqs = read_seq_ids(lin.tagged()); return lin; } ref PgfReader::read_printname() { ref printname = read_name(&PgfConcrPrintname::name); - printname->ref_count = 1; printname->printname = read_text(); return printname; } @@ -597,8 +598,6 @@ ref PgfReader::read_printname() ref PgfReader::read_concrete() { concrete = read_name(&PgfConcr::name); - concrete->ref_count = 1; - concrete->ref_count_ex = 0; concrete->cflags = read_namespace(&PgfReader::read_flag); concrete->phrasetable = read_phrasetable(); concrete->lincats = read_namespace(&PgfReader::read_lincat); @@ -611,9 +610,8 @@ ref PgfReader::read_concrete() ref PgfReader::read_pgf() { - ref pgf = PgfDB::malloc(master_size+1); + ref pgf = PgfDB::malloc(); - pgf->ref_count = 1; pgf->major_version = read_u16be(); pgf->minor_version = read_u16be(); @@ -628,12 +626,6 @@ ref PgfReader::read_pgf() pgf->concretes = read_namespace(&PgfReader::read_concrete); - pgf->prev = 0; - pgf->next = 0; - - pgf->name.size = master_size; - memcpy(&pgf->name.text, master_text, master_size+1); - return pgf; } @@ -654,9 +646,7 @@ void PgfReader::merge_pgf(ref pgf) size_t len = read_len(); for (size_t i = 0; i < len; i++) { ref concr = PgfReader::read_concrete(); - Namespace concrs = + pgf->concretes = namespace_insert(pgf->concretes, concr); - namespace_release(pgf->concretes); - pgf->concretes = concrs; } } diff --git a/src/runtime/c/pgf/text.cxx b/src/runtime/c/pgf/text.cxx index 83a3461ff..76b219e2f 100644 --- a/src/runtime/c/pgf/text.cxx +++ b/src/runtime/c/pgf/text.cxx @@ -92,6 +92,12 @@ ref textdup_db(PgfText *t1) return t2; } +PGF_INTERNAL +void text_db_release(ref text) +{ + PgfDB::free(text,text->size+1); +} + PGF_API uint32_t pgf_utf8_decode(const uint8_t **src_inout) { diff --git a/src/runtime/c/pgf/text.h b/src/runtime/c/pgf/text.h index 471e0b12a..8028432b9 100644 --- a/src/runtime/c/pgf/text.h +++ b/src/runtime/c/pgf/text.h @@ -23,6 +23,9 @@ PgfText* textdup(PgfText *t1); PGF_INTERNAL_DECL ref textdup_db(PgfText *t1); +PGF_INTERNAL +void text_db_release(ref text); + PGF_API uint32_t pgf_utf8_decode(const uint8_t** src_inout); diff --git a/src/runtime/c/pgf/vector.h b/src/runtime/c/pgf/vector.h index 7bc012923..fd7e36585 100644 --- a/src/runtime/c/pgf/vector.h +++ b/src/runtime/c/pgf/vector.h @@ -5,6 +5,11 @@ template struct PGF_INTERNAL Vector { size_t len; A data[]; + +public: + static void release(ref vec) { + PgfDB::free(vec, vec->len*sizeof(A)); + } }; template inline PGF_INTERNAL @@ -18,7 +23,6 @@ ref> vector_new(size_t len) template inline PGF_INTERNAL ref vector_new(Vector C::* field, size_t len) { - ptrdiff_t offset = (ptrdiff_t) &(((C*) NULL)->*field); ref res = PgfDB::malloc(len*sizeof(A)).as_object(); (res->*field).len = len; return res; @@ -27,19 +31,53 @@ ref vector_new(Vector C::* field, size_t len) PGF_INTERNAL_DECL size_t get_next_padovan(size_t min); +/* Resize a vector by creating a new one and copying the old content. + * The new vector is now also safe to update */ template inline PGF_INTERNAL -ref> vector_resize(ref> r, size_t len) +ref> vector_copy(ref> vec, size_t len) { - ref> res = PgfDB::realloc>(r,get_next_padovan(len)*sizeof(A)).as_object(); + size_t size = len*sizeof(A); + ref> res = PgfDB::malloc>(size); + res->len = len; + memcpy(res->data, vec->data, size); + return res; +} + +/* Resize a vector by changing its length. If there is no enough space + * the implementation will create a copy, but whenever possible it will + * return the reference of the original vector. In the later case, it + * changes the length in-place which means that the function is safe + * only if the vector was created during the current transaction. */ +template inline PGF_INTERNAL +ref> vector_unsafe_resize(ref> vec, size_t len) +{ + size_t old_len = get_next_padovan(vec->len); + size_t new_len = get_next_padovan(len); + + if (old_len == new_len) + return vec; + + ref> res = PgfDB::realloc>(vec,old_len*sizeof(A),new_len*sizeof(A)).as_object(); res->len = len; return res; } +/* Resize a vector embedded in another structure, by changing its length. + * If there is no enough space the implementation will copy the structure, + * but whenever possible it will return a reference to + * the original structure. In the later case, it changes + * the vector's length in-place which means that the function is safe + * only if the structure was created during the current transaction. */ template inline PGF_INTERNAL -ref vector_resize(ref r, Vector C::* field, size_t len) +ref vector_unsafe_resize(ref r, Vector C::* field, size_t len) { - ptrdiff_t offset = (ptrdiff_t) &(((C*) NULL)->*field); - ref res = PgfDB::realloc(r,get_next_padovan(len)*sizeof(A)).as_object(); + size_t old_len = get_next_padovan((r->*field).len); + size_t new_len = get_next_padovan(len); + + if (old_len == new_len) + return r; + + ref res = PgfDB::realloc(r,old_len*sizeof(A),new_len*sizeof(A)).as_object(); (res->*field).len = len; return res; } diff --git a/src/runtime/c/pgf/writer.cxx b/src/runtime/c/pgf/writer.cxx index 4c9b9131c..2666fae68 100644 --- a/src/runtime/c/pgf/writer.cxx +++ b/src/runtime/c/pgf/writer.cxx @@ -421,7 +421,7 @@ void PgfWriter::write_concrete(ref concr) void PgfWriter::write_pgf(ref pgf) { write_u16be(pgf->major_version); - write_u16be(pgf->minor_version); + write_u16be(pgf->minor_version); write_namespace(pgf->gflags, &PgfWriter::write_flag); diff --git a/src/runtime/haskell/PGF2/FFI.hsc b/src/runtime/haskell/PGF2/FFI.hsc index 6c0b26844..8ae50cbcd 100644 --- a/src/runtime/haskell/PGF2/FFI.hsc +++ b/src/runtime/haskell/PGF2/FFI.hsc @@ -73,8 +73,6 @@ foreign import ccall pgf_merge_pgf :: Ptr PgfDB -> Ptr PGF -> CString -> Ptr Pgf foreign import ccall pgf_write_pgf :: CString -> Ptr PgfDB -> Ptr PGF -> Ptr PgfExn -> IO () -foreign import ccall "pgf_free_revision" pgf_free_revision_ :: Ptr PgfDB -> Ptr PGF -> IO () - foreign import ccall "&pgf_free_revision" pgf_free_revision :: FinalizerEnvPtr PgfDB PGF foreign import ccall "pgf_free_concr_revision" pgf_free_concr_revision_ :: Ptr PgfDB -> Ptr Concr -> IO () @@ -177,11 +175,13 @@ foreign import ccall pgf_infer_expr :: Ptr PgfDB -> Ptr PGF -> Ptr (StablePtr Ex foreign import ccall pgf_check_type :: Ptr PgfDB -> Ptr PGF -> Ptr (StablePtr Type) -> Ptr PgfMarshaller -> Ptr PgfUnmarshaller -> Ptr PgfExn -> IO () -foreign import ccall pgf_clone_revision :: Ptr PgfDB -> Ptr PGF -> Ptr PgfText -> Ptr PgfExn -> IO (Ptr PGF) +foreign import ccall pgf_start_transaction :: Ptr PgfDB -> Ptr PGF -> Ptr PgfExn -> IO (Ptr PGF) -foreign import ccall pgf_commit_revision :: Ptr PgfDB -> Ptr PGF -> Ptr PgfExn -> IO () +foreign import ccall pgf_commit_transaction :: Ptr PgfDB -> Ptr PGF -> Ptr PgfExn -> IO () -foreign import ccall pgf_checkout_revision :: Ptr PgfDB -> Ptr PgfText -> Ptr PgfExn -> IO (Ptr PGF) +foreign import ccall pgf_rollback_transaction :: Ptr PgfDB -> Ptr PGF -> IO () + +foreign import ccall pgf_checkout_revision :: Ptr PgfDB -> Ptr PgfExn -> IO (Ptr PGF) foreign import ccall pgf_create_function :: Ptr PgfDB -> Ptr PGF -> Ptr PgfText -> StablePtr Type -> CSize -> Ptr CChar -> (#type prob_t) -> Ptr PgfMarshaller -> Ptr PgfExn -> IO () diff --git a/src/runtime/haskell/PGF2/Transactions.hsc b/src/runtime/haskell/PGF2/Transactions.hsc index a37599be1..aafb5bd26 100644 --- a/src/runtime/haskell/PGF2/Transactions.hsc +++ b/src/runtime/haskell/PGF2/Transactions.hsc @@ -3,7 +3,6 @@ module PGF2.Transactions -- abstract syntax , modifyPGF - , branchPGF , checkoutPGF , createFunction , dropFunction @@ -81,53 +80,39 @@ instance Monad (Transaction k) where the new function @foo@. -} modifyPGF :: PGF -> Transaction PGF a -> IO PGF -modifyPGF = branchPGF_ nullPtr - -{- | @branchPGF gr branch_name t@ is similar to @modifyPGF gr t@, - except that it stores the result as a branch with the given name. --} -branchPGF :: PGF -> String -> Transaction PGF a -> IO PGF -branchPGF p name t = - withText name $ \c_name -> - branchPGF_ c_name p t - -branchPGF_ :: Ptr PgfText -> PGF -> Transaction PGF a -> IO PGF -branchPGF_ c_name p (Transaction f) = +modifyPGF p (Transaction f) = withForeignPtr (a_revision p) $ \c_revision -> - withPgfExn "branchPGF" $ \c_exn -> + withPgfExn "modifyPGF" $ \c_exn -> mask $ \restore -> do - c_revision <- pgf_clone_revision (a_db p) c_revision c_name c_exn + c_revision <- pgf_start_transaction (a_db p) c_revision c_exn ex_type <- (#peek PgfExn, type) c_exn if (ex_type :: (#type PgfExnType)) == (#const PGF_EXN_NONE) then do ((restore (f (a_db p) c_revision c_revision c_exn)) `catch` (\e -> do - pgf_free_revision_ (a_db p) c_revision + pgf_rollback_transaction (a_db p) c_revision throwIO (e :: SomeException))) ex_type <- (#peek PgfExn, type) c_exn if (ex_type :: (#type PgfExnType)) == (#const PGF_EXN_NONE) - then do pgf_commit_revision (a_db p) c_revision c_exn + then do pgf_commit_transaction (a_db p) c_revision c_exn ex_type <- (#peek PgfExn, type) c_exn if (ex_type :: (#type PgfExnType)) == (#const PGF_EXN_NONE) then do fptr <- newForeignPtrEnv pgf_free_revision (a_db p) c_revision langs <- getConcretes (a_db p) fptr return (PGF (a_db p) fptr langs) - else do pgf_free_revision_ (a_db p) c_revision + else do pgf_rollback_transaction (a_db p) c_revision return p - else do pgf_free_revision_ (a_db p) c_revision + else do pgf_rollback_transaction (a_db p) c_revision return p else return p {- | Retrieves the branch with the given name -} -checkoutPGF :: PGF -> String -> IO (Maybe PGF) -checkoutPGF p name = - withText name $ \c_name -> do - c_revision <- withPgfExn "checkoutPGF" (pgf_checkout_revision (a_db p) c_name) - if c_revision == nullPtr - then return Nothing - else do fptr <- newForeignPtrEnv pgf_free_revision (a_db p) c_revision - langs <- getConcretes (a_db p) fptr - return (Just (PGF (a_db p) fptr langs)) +checkoutPGF :: PGF -> IO PGF +checkoutPGF p = do + c_revision <- withPgfExn "checkoutPGF" (pgf_checkout_revision (a_db p)) + fptr <- newForeignPtrEnv pgf_free_revision (a_db p) c_revision + langs <- getConcretes (a_db p) fptr + return (PGF (a_db p) fptr langs) createFunction :: Fun -> Type -> Int -> [[Instr]] -> Float -> Transaction PGF () createFunction name ty arity bytecode prob = Transaction $ \c_db _ c_revision c_exn -> diff --git a/src/runtime/haskell/tests/transactions.hs b/src/runtime/haskell/tests/transactions.hs index 84a3e1c34..4e0a03954 100644 --- a/src/runtime/haskell/tests/transactions.hs +++ b/src/runtime/haskell/tests/transactions.hs @@ -9,13 +9,12 @@ main = do gr1 <- readPGF "tests/basic.pgf" let Just ty = readType "(N -> N) -> P (s z)" - gr2 <- modifyPGF gr1 (createFunction "foo" ty 0 [] pi >> - createCategory "Q" [(Explicit,"x",ty)] pi) - gr3 <- branchPGF gr1 "bar_branch" (createFunction "bar" ty 0 [] pi >> - createCategory "R" [(Explicit,"x",ty)] pi) + print 1 + gr2 <- modifyPGF gr1 (createFunction "foo" ty 0 [] pi >> + createCategory "Q" [(Explicit,"x",ty)] pi) + print 2 - Just gr4 <- checkoutPGF gr1 "master" - Just gr5 <- checkoutPGF gr1 "bar_branch" + gr4 <- checkoutPGF gr1 gr6 <- modifyPGF gr1 (dropFunction "ind" >> dropCategory "S") @@ -28,14 +27,10 @@ main = do TestList $ [TestCase (assertEqual "original functions" ["c","floatLit","ind","intLit","nat","s","stringLit","z"] (functions gr1)) ,TestCase (assertEqual "extended functions" ["c","floatLit","foo","ind","intLit","nat","s","stringLit","z"] (functions gr2)) - ,TestCase (assertEqual "branched functions" ["bar","c","floatLit","ind","intLit","nat","s","stringLit","z"] (functions gr3)) ,TestCase (assertEqual "checked-out extended functions" ["c","floatLit","foo","ind","intLit","nat","s","stringLit","z"] (functions gr4)) - ,TestCase (assertEqual "checked-out branched functions" ["bar","c","floatLit","ind","intLit","nat","s","stringLit","z"] (functions gr5)) ,TestCase (assertEqual "original categories" ["Float","Int","N","P","S","String"] (categories gr1)) ,TestCase (assertEqual "extended categories" ["Float","Int","N","P","Q","S","String"] (categories gr2)) - ,TestCase (assertEqual "branched categories" ["Float","Int","N","P","R","S","String"] (categories gr3)) ,TestCase (assertEqual "Q context" (Just [(Explicit,"x",ty)]) (categoryContext gr2 "Q")) - ,TestCase (assertEqual "R context" (Just [(Explicit,"x",ty)]) (categoryContext gr3 "R")) ,TestCase (assertEqual "reduced functions" ["c","floatLit","intLit","nat","s","stringLit","z"] (functions gr6)) ,TestCase (assertEqual "reduced categories" ["Float","Int","N","P","String"] (categories gr6)) ,TestCase (assertEqual "old function type" Nothing (functionType gr1 "foo")) diff --git a/src/runtime/javascript/ffi.ts b/src/runtime/javascript/ffi.ts index d83e3b6af..bfa5a3601 100644 --- a/src/runtime/javascript/ffi.ts +++ b/src/runtime/javascript/ffi.ts @@ -129,7 +129,7 @@ export const runtime = ffi.Library('libpgf', { pgf_print_context: [PgfTextPtr, [size_t, PgfTypeHypoPtr, PgfPrintContextPtr, ref.types.int, PgfMarshallerPtr]], pgf_read_type: [PgfType, [PgfTextPtr, PgfUnmarshallerPtr]], - pgf_clone_revision: [PgfRevision, [PgfDBPtr, PgfRevision, PgfTextPtr, PgfExnPtr]], + pgf_clone_revision: [PgfRevision, [PgfDBPtr, PgfRevision, PgfExnPtr]], pgf_commit_revision: [ref.types.void, [PgfDBPtr, PgfRevision, PgfExnPtr]], pgf_checkout_revision: [PgfRevision, [PgfDBPtr, PgfTextPtr, PgfExnPtr]], pgf_create_function: [ref.types.void, [PgfDBPtr, PgfRevision, PgfTextPtr, PgfType, size_t, prob_t, PgfMarshallerPtr, PgfExnPtr]], diff --git a/src/runtime/python/tests/test_transactions.py b/src/runtime/python/tests/test_transactions.py index 8453b8810..7d7b60aee 100644 --- a/src/runtime/python/tests/test_transactions.py +++ b/src/runtime/python/tests/test_transactions.py @@ -27,18 +27,6 @@ def gr3(gr1): t.createCategory("R", [(BIND_TYPE_EXPLICIT, "x", ty)], prob) yield gr -@pytest.fixture(scope="function") -def gr4(gr2): - gr = gr2 - gr.checkoutBranch("master") - yield gr - -@pytest.fixture(scope="function") -def gr5(gr3): - gr = gr3 - gr.checkoutBranch("bar_branch") - yield gr - @pytest.fixture(scope="function") def gr6(gr1): gr = gr1 @@ -47,12 +35,6 @@ def gr6(gr1): t.dropCategory("S") yield gr -# general - -def test_checkout_non_existant(gr1): - with pytest.raises(KeyError): - gr1.checkoutBranch("abc") - # gr1 def test_original_functions(gr1): @@ -118,14 +100,6 @@ def test_branched_category_context(gr3): def test_branched_function_type(gr3): assert gr3.functionType("bar") == ty -# gr4, 5 - -def test_branched_functions(gr4): - assert gr4.functions == ["c", "foo", "ind", "s", "z"] - -def test_branched_functions(gr5): - assert gr5.functions == ["bar", 'c', 'floatLit', 'ind', 'intLit', 'nat', 's', 'stringLit', 'z'] - # gr6 def test_reduced_functions(gr6): diff --git a/src/runtime/python/transactions.c b/src/runtime/python/transactions.c index 6e2f353a9..2690a9c0e 100644 --- a/src/runtime/python/transactions.c +++ b/src/runtime/python/transactions.c @@ -10,16 +10,12 @@ PyObject * PGF_checkoutBranch(PGFObject *self, PyObject *args) { - const char *s = NULL; - Py_ssize_t size; - if (!PyArg_ParseTuple(args, "s#", &s, &size)) + if (!PyArg_ParseTuple(args, "")) return NULL; - PgfText *name = CString_AsPgfText(s, size); - PgfExn err; - PgfRevision rev = pgf_checkout_revision(self->db, name, &err); - FreePgfText(name); + PgfRevision rev = pgf_checkout_revision(self->db, &err); + if (handleError(err) != PGF_EXN_NONE) { return NULL; } @@ -38,21 +34,13 @@ PGF_checkoutBranch(PGFObject *self, PyObject *args) TransactionObject * PGF_newTransaction(PGFObject *self, PyObject *args) { - PgfText *name = NULL; const char *s = NULL; Py_ssize_t size; if (!PyArg_ParseTuple(args, "|s#", &s, &size)) return NULL; - if (s != NULL) { - name = CString_AsPgfText(s, size); - } - PgfExn err; - PgfRevision rev = pgf_clone_revision(self->db, self->revision, name, &err); - if (name != NULL) { - FreePgfText(name); - } + PgfRevision rev = pgf_start_transaction(self->db, self->revision, &err); if (handleError(err) != PGF_EXN_NONE) { return NULL; } @@ -123,7 +111,7 @@ static PyObject * Transaction_commit(TransactionObject *self, PyObject *args) { PgfExn err; - pgf_commit_revision(self->pgf->db, self->revision, &err); + pgf_commit_transaction(self->pgf->db, self->revision, &err); if (handleError(err) != PGF_EXN_NONE) { return NULL; }