diff options
Diffstat (limited to 'db.go')
-rw-r--r-- | db.go | 1452 |
1 files changed, 649 insertions, 803 deletions
@@ -1,5 +1,12 @@ package bolt +import ( + "os" + "sync" + "syscall" + "unsafe" +) + const ( NoSync = iota NoMetaSync @@ -8,59 +15,54 @@ const ( IntegerDupKey ) -var DatabaseAlreadyOpenedError = &Error{"Database already open"} +var DatabaseAlreadyOpenedError = &Error{"Database already open", nil} // TODO: #define MDB_FATAL_ERROR 0x80000000U /** Failed to update the meta page. Probably an I/O error. */ // TODO: #define MDB_ENV_ACTIVE 0x20000000U /** Some fields are initialized. */ // TODO: #define MDB_ENV_TXKEY 0x10000000U /** me_txkey is set */ // TODO: #define MDB_LIVE_READER 0x08000000U /** Have liveness lock in reader table */ -type DB interface { - syncEnabled bool - metaSyncEnabled bool -} - -type db struct { +type DB struct { sync.Mutex opened bool - file os.File - metafile os.File - buf []byte + file *os.File + metafile *os.File + data []byte + buf []byte + meta0 *meta + meta1 *meta pageSize int - readers []*reader - buckets []*bucket - xbuckets []*bucketx /**< array of static DB info */ - bucketFlags []int /**< array of flags from MDB_db.md_flags */ - path string - mmap []byte - mmapSize int /**< size of the data memory map */ - size int /**< current file size */ - meta1 []byte - meta2 []byte - pbuf []byte - transaction *transaction /**< current write transaction */ - maxPageNumber int /**< me_mapsize / me_psize */ - pageState pageStage /**< state of old pages from freeDB */ - dpages []*page /**< list of malloc'd blocks for re-use */ - freePages []int /** IDL of pages that became unused in a write txn */ - dirtyPages []int /** ID2L of pages written during a write txn. Length MDB_IDL_UM_SIZE. */ - maxFreeOnePage int /** Max number of freelist items that can fit in a single overflow page */ - maxNodeSize int /** Max size of a node on a page */ - maxKeySize int /**< max size of a key */ -} - - -func NewDB() DB { - return &db{} -} - -func (db *db) Path() string { + readers []*reader + buckets []*Bucket + // xbuckets []*bucketx /**< array of static DB info */ + bucketFlags []int /**< array of flags from MDB_db.md_flags */ + path string + mmapSize int /**< size of the data memory map */ + size int /**< current file size */ + pbuf []byte + transaction *transaction /**< current write transaction */ + maxPageNumber int /**< me_mapsize / me_psize */ + pageState pageState /**< state of old pages from freeDB */ + dpages []*page /**< list of malloc'd blocks for re-use */ + freePages []int /** IDL of pages that became unused in a write txn */ + dirtyPages []int /** ID2L of pages written during a write txn. Length MDB_IDL_UM_SIZE. */ + maxFreeOnePage int /** Max number of freelist items that can fit in a single overflow page */ + maxPageDataSize int + maxNodeSize int /** Max size of a node on a page */ + maxKeySize int /**< max size of a key */ +} + +func NewDB() *DB { + return &DB{} +} + +func (db *DB) Path() string { return db.path } -func (db *db) Open(path string, mode os.FileMode) error { +func (db *DB) Open(path string, mode os.FileMode) error { var err error db.Lock() defer db.Unlock() @@ -72,24 +74,24 @@ func (db *db) Open(path string, mode os.FileMode) error { // Open data file and separate sync handler for metadata writes. db.path = path - if db.file, err = os.OpenFile(db.path, O_RDWR | O_CREAT, mode); err != nil { + if db.file, err = os.OpenFile(db.path, os.O_RDWR|os.O_CREATE, mode); err != nil { db.close() return err } - if db.metafile, err = os.OpenFile(db.path, O_RDWR | O_SYNC, mode); err != nil { + if db.metafile, err = os.OpenFile(db.path, os.O_RDWR|os.O_SYNC, mode); err != nil { db.close() return err } // Read enough data to get both meta pages. var m, m0, m1 *meta - var buf [headerSize + unsafe.Sizeof(meta)]byte - if _, err := db.file.ReadAt(buf, 0); err == nil { + var buf [pageHeaderSize + int(unsafe.Sizeof(meta{}))]byte + if _, err := db.file.ReadAt(buf[:], 0); err == nil { if m0, _ = db.page(buf[:], 0).meta(); m0 != nil { - db.pageSize = m0.free.pad + db.pageSize = int(m0.free.pad) } } - if _, err := db.file.ReadAt(buf, db.pageSize); err == nil { + if _, err := db.file.ReadAt(buf[:], int64(db.pageSize)); err == nil { m1, _ = db.page(buf[:], 0).meta() } if m0 != nil && m1 != nil { @@ -102,27 +104,16 @@ func (db *db) Open(path string, mode os.FileMode) error { // Initialize the page size for new environments. if m == nil { - db.pageSize = os.Getpagesize() - if db.pageSize > maxPageSize { - db.pageSize = maxPageSize + if err := db.init(); err != nil { + return err } } - // TODO: Check mapsize. - /* - // Was a mapsize configured? - if (!env->me_mapsize) { - // If this is a new environment, take the default, - // else use the size recorded in the existing env. - env->me_mapsize = newenv ? DEFAULT_MAPSIZE : meta.mm_mapsize; - } else if (env->me_mapsize < meta.mm_mapsize) { - // If the configured size is smaller, make sure it's - // still big enough. Silently round up to minimum if not. - size_t minsize = (meta.mm_last_pg + 1) * meta.mm_psize; - if (env->me_mapsize < minsize) - env->me_mapsize = minsize; - } - */ + // Initialize db fields. + db.buf = make([]byte, db.pageSize) + db.maxPageDataSize = ((db.pageSize - pageHeaderSize) / int(unsafe.Sizeof(pgno(0)))) - 1 + db.maxNodeSize = (((db.pageSize - pageHeaderSize) / minKeyCount) & -2) - int(unsafe.Sizeof(indx(0))) + // TODO?: env->me_maxpg = env->me_mapsize / env->me_psize; // Memory map the data file. if err := db.mmap(); err != nil { @@ -130,725 +121,584 @@ func (db *db) Open(path string, mode os.FileMode) error { return err } - // Initialize the buffer. - db.buf = make([]byte, db.pageSize) + // TODO: Initialize meta. + // if (newenv) { + // i = mdb_env_init_meta(env, &meta); + // if (i != MDB_SUCCESS) { + // return i; + // } + // } // Mark the database as opened and return. db.opened = true return nil } -// Read the meta pages and return the latest. -func (db *db) readMeta() *meta { - m := &meta{} - m.read() +// int mdb_env_map(MDB_env *env, void *addr, int newsize) +func (db *DB) mmap() error { + var err error - /* - if ((i = mdb_env_read_header(env, &meta)) != 0) { - if (i != ENOENT) - return i; - DPUTS("new mdbenv"); - newenv = 1; - env->me_psize = env->me_os_psize; - if (env->me_psize > MAX_PAGESIZE) - env->me_psize = MAX_PAGESIZE; + // Determine the map size based on the file size. + var size int + if info, err := os.Stat(db.file.Name()); err != nil { + return err + } else if info.Size() < int64(db.pageSize*2) { + return &Error{"file size too small", nil} } else { - env->me_psize = meta.mm_psize; + size = int(info.Size()) } + // Memory-map the data file as a byte slice. + if db.data, err = syscall.Mmap(int(db.file.Fd()), 0, size, syscall.PROT_READ, syscall.MAP_SHARED); err != nil { + return err + } - rc = mdb_env_map(env, meta.mm_address, newenv); - if (rc) - return rc; + // TODO?: If nordahead, then: madvise(env->me_map, env->me_mapsize, MADV_RANDOM); - if (newenv) { - if (flags & MDB_FIXEDMAP) - meta.mm_address = env->me_map; - i = mdb_env_init_meta(env, &meta); - if (i != MDB_SUCCESS) { - return i; - } + // Save references to the meta pages. + if db.meta0, err = db.page(db.data, 0).meta(); err != nil { + return &Error{"meta0 error", err} } - - env->me_maxfree_1pg = (env->me_psize - PAGEHDRSZ) / sizeof(pgno_t) - 1; - env->me_nodemax = (((env->me_psize - PAGEHDRSZ) / MDB_MINKEYS) & -2) - - sizeof(indx_t); -#if !(MDB_MAXKEYSIZE) - env->me_maxkey = env->me_nodemax - (NODESIZE + sizeof(MDB_db)); -#endif - env->me_maxpg = env->me_mapsize / env->me_psize; - -#if MDB_DEBUG - { - int toggle = mdb_env_pick_meta(env); - MDB_db *db = &env->me_metas[toggle]->mm_dbs[MAIN_DBI]; - - DPRINTF(("opened database version %u, pagesize %u", - env->me_metas[0]->mm_version, env->me_psize)); - DPRINTF(("using meta page %d", toggle)); - DPRINTF(("depth: %u", db->md_depth)); - DPRINTF(("entries: %"Z"u", db->md_entries)); - DPRINTF(("branch pages: %"Z"u", db->md_branch_pages)); - DPRINTF(("leaf pages: %"Z"u", db->md_leaf_pages)); - DPRINTF(("overflow pages: %"Z"u", db->md_overflow_pages)); - DPRINTF(("root: %"Z"u", db->md_root)); + if db.meta1, err = db.page(db.data, 1).meta(); err != nil { + return &Error{"meta1 error", err} } -#endif - return MDB_SUCCESS; - */ return nil } -// page retrieves a page reference from a given byte array based on the current page size. -func (db *db) page(b []byte, id int) *page { - return (*page)(unsafe.Pointer(b[id * db.pageSize])) -} - - - - - -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ CONVERTED ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // +// init creates a new database file and initializes its meta pages. +func (db *DB) init() error { + // Set the page size to the OS page size unless that is larger than max page size. + db.pageSize = os.Getpagesize() + if db.pageSize > maxPageSize { + db.pageSize = maxPageSize + } + // Create two meta pages on a buffer. + buf := make([]byte, db.pageSize*2) + for i := 0; i < 2; i++ { + p := db.page(buf[:], i) + p.id = pgno(i) + p.initMeta(db.pageSize) + } + // Write the buffer to our data file. + if _, err := db.metafile.WriteAt(buf, 0); err != nil { + return err + } + return nil +} +func (db *DB) close() { + // TODO +} +// page retrieves a page reference from a given byte array based on the current page size. +func (db *DB) page(b []byte, id int) *page { + return (*page)(unsafe.Pointer(&b[id*db.pageSize])) +} +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ CONVERTED ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // -func (db *db) freePage(p *page) { +func (db *DB) freePage(p *page) { /* - mp->mp_next = env->me_dpages; - VGMEMP_FREE(env, mp); - env->me_dpages = mp; + mp->mp_next = env->me_dpages; + VGMEMP_FREE(env, mp); + env->me_dpages = mp; */ } -func (db *db) freeDirtyPage(p *page) { +func (db *DB) freeDirtyPage(p *page) { /* - if (!IS_OVERFLOW(dp) || dp->mp_pages == 1) { - mdb_page_free(env, dp); - } else { - // large pages just get freed directly - VGMEMP_FREE(env, dp); - free(dp); - } + if (!IS_OVERFLOW(dp) || dp->mp_pages == 1) { + mdb_page_free(env, dp); + } else { + // large pages just get freed directly + VGMEMP_FREE(env, dp); + free(dp); + } */ } -func (db *db) freeAllDirtyPages(p *page) { +func (db *DB) freeAllDirtyPages(p *page) { /* - MDB_env *env = txn->mt_env; - MDB_ID2L dl = txn->mt_u.dirty_list; - unsigned i, n = dl[0].mid; + MDB_env *env = txn->mt_env; + MDB_ID2L dl = txn->mt_u.dirty_list; + unsigned i, n = dl[0].mid; - for (i = 1; i <= n; i++) { - mdb_dpage_free(env, dl[i].mptr); - } - dl[0].mid = 0; + for (i = 1; i <= n; i++) { + mdb_dpage_free(env, dl[i].mptr); + } + dl[0].mid = 0; */ } -func (db *db) sync(force bool) error { +func (db *DB) sync(force bool) error { /* - int rc = 0; - if (force || !F_ISSET(env->me_flags, MDB_NOSYNC)) { - if (env->me_flags & MDB_WRITEMAP) { - int flags = ((env->me_flags & MDB_MAPASYNC) && !force) - ? MS_ASYNC : MS_SYNC; - if (MDB_MSYNC(env->me_map, env->me_mapsize, flags)) - rc = ErrCode(); -#ifdef _WIN32 - else if (flags == MS_SYNC && MDB_FDATASYNC(env->me_fd)) - rc = ErrCode(); -#endif - } else { - if (MDB_FDATASYNC(env->me_fd)) - rc = ErrCode(); - } - } - return rc; + int rc = 0; + if (force || !F_ISSET(env->me_flags, MDB_NOSYNC)) { + if (env->me_flags & MDB_WRITEMAP) { + int flags = ((env->me_flags & MDB_MAPASYNC) && !force) + ? MS_ASYNC : MS_SYNC; + if (MDB_MSYNC(env->me_map, env->me_mapsize, flags)) + rc = ErrCode(); + #ifdef _WIN32 + else if (flags == MS_SYNC && MDB_FDATASYNC(env->me_fd)) + rc = ErrCode(); + #endif + } else { + if (MDB_FDATASYNC(env->me_fd)) + rc = ErrCode(); + } + } + return rc; */ return nil } -func (db *db) Transaction(parent *transaction, flags int) (*transaction, error) { +func (db *DB) Transaction(parent *transaction, flags int) (*transaction, error) { /* - MDB_txn *txn; - MDB_ntxn *ntxn; - int rc, size, tsize = sizeof(MDB_txn); + MDB_txn *txn; + MDB_ntxn *ntxn; + int rc, size, tsize = sizeof(MDB_txn); - if (env->me_flags & MDB_FATAL_ERROR) { - DPUTS("environment had fatal error, must shutdown!"); - return MDB_PANIC; - } - if ((env->me_flags & MDB_RDONLY) && !(flags & MDB_RDONLY)) - return EACCES; - if (parent) { - // Nested transactions: Max 1 child, write txns only, no writemap - if (parent->mt_child || - (flags & MDB_RDONLY) || - (parent->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_ERROR)) || - (env->me_flags & MDB_WRITEMAP)) - { - return (parent->mt_flags & MDB_TXN_RDONLY) ? EINVAL : MDB_BAD_TXN; + if (env->me_flags & MDB_FATAL_ERROR) { + DPUTS("environment had fatal error, must shutdown!"); + return MDB_PANIC; } - tsize = sizeof(MDB_ntxn); - } - size = tsize + env->me_maxdbs * (sizeof(MDB_db)+1); - if (!(flags & MDB_RDONLY)) - size += env->me_maxdbs * sizeof(MDB_cursor *); - - if ((txn = calloc(1, size)) == NULL) { - DPRINTF(("calloc: %s", strerror(ErrCode()))); - return ENOMEM; - } - txn->mt_dbs = (MDB_db *) ((char *)txn + tsize); - if (flags & MDB_RDONLY) { - txn->mt_flags |= MDB_TXN_RDONLY; - txn->mt_dbflags = (unsigned char *)(txn->mt_dbs + env->me_maxdbs); - } else { - txn->mt_cursors = (MDB_cursor **)(txn->mt_dbs + env->me_maxdbs); - txn->mt_dbflags = (unsigned char *)(txn->mt_cursors + env->me_maxdbs); - } - txn->mt_env = env; + if ((env->me_flags & MDB_RDONLY) && !(flags & MDB_RDONLY)) + return EACCES; + if (parent) { + // Nested transactions: Max 1 child, write txns only, no writemap + if (parent->mt_child || + (flags & MDB_RDONLY) || + (parent->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_ERROR)) || + (env->me_flags & MDB_WRITEMAP)) + { + return (parent->mt_flags & MDB_TXN_RDONLY) ? EINVAL : MDB_BAD_TXN; + } + tsize = sizeof(MDB_ntxn); + } + size = tsize + env->me_maxdbs * (sizeof(MDB_db)+1); + if (!(flags & MDB_RDONLY)) + size += env->me_maxdbs * sizeof(MDB_cursor *); - if (parent) { - unsigned int i; - txn->mt_u.dirty_list = malloc(sizeof(MDB_ID2)*MDB_IDL_UM_SIZE); - if (!txn->mt_u.dirty_list || - !(txn->mt_free_pgs = mdb_midl_alloc(MDB_IDL_UM_MAX))) - { - free(txn->mt_u.dirty_list); - free(txn); + if ((txn = calloc(1, size)) == NULL) { + DPRINTF(("calloc: %s", strerror(ErrCode()))); return ENOMEM; } - txn->mt_txnid = parent->mt_txnid; - txn->mt_dirty_room = parent->mt_dirty_room; - txn->mt_u.dirty_list[0].mid = 0; - txn->mt_spill_pgs = NULL; - txn->mt_next_pgno = parent->mt_next_pgno; - parent->mt_child = txn; - txn->mt_parent = parent; - txn->mt_numdbs = parent->mt_numdbs; - txn->mt_flags = parent->mt_flags; - txn->mt_dbxs = parent->mt_dbxs; - memcpy(txn->mt_dbs, parent->mt_dbs, txn->mt_numdbs * sizeof(MDB_db)); - // Copy parent's mt_dbflags, but clear DB_NEW - for (i=0; i<txn->mt_numdbs; i++) - txn->mt_dbflags[i] = parent->mt_dbflags[i] & ~DB_NEW; - rc = 0; - ntxn = (MDB_ntxn *)txn; - ntxn->mnt_pgstate = env->me_pgstate; // save parent me_pghead & co - if (env->me_pghead) { - size = MDB_IDL_SIZEOF(env->me_pghead); - env->me_pghead = mdb_midl_alloc(env->me_pghead[0]); - if (env->me_pghead) - memcpy(env->me_pghead, ntxn->mnt_pgstate.mf_pghead, size); - else - rc = ENOMEM; + txn->mt_dbs = (MDB_db *) ((char *)txn + tsize); + if (flags & MDB_RDONLY) { + txn->mt_flags |= MDB_TXN_RDONLY; + txn->mt_dbflags = (unsigned char *)(txn->mt_dbs + env->me_maxdbs); + } else { + txn->mt_cursors = (MDB_cursor **)(txn->mt_dbs + env->me_maxdbs); + txn->mt_dbflags = (unsigned char *)(txn->mt_cursors + env->me_maxdbs); + } + txn->mt_env = env; + + if (parent) { + unsigned int i; + txn->mt_u.dirty_list = malloc(sizeof(MDB_ID2)*MDB_IDL_UM_SIZE); + if (!txn->mt_u.dirty_list || + !(txn->mt_free_pgs = mdb_midl_alloc(MDB_IDL_UM_MAX))) + { + free(txn->mt_u.dirty_list); + free(txn); + return ENOMEM; + } + txn->mt_txnid = parent->mt_txnid; + txn->mt_dirty_room = parent->mt_dirty_room; + txn->mt_u.dirty_list[0].mid = 0; + txn->mt_spill_pgs = NULL; + txn->mt_next_pgno = parent->mt_next_pgno; + parent->mt_child = txn; + txn->mt_parent = parent; + txn->mt_numdbs = parent->mt_numdbs; + txn->mt_flags = parent->mt_flags; + txn->mt_dbxs = parent->mt_dbxs; + memcpy(txn->mt_dbs, parent->mt_dbs, txn->mt_numdbs * sizeof(MDB_db)); + // Copy parent's mt_dbflags, but clear DB_NEW + for (i=0; i<txn->mt_numdbs; i++) + txn->mt_dbflags[i] = parent->mt_dbflags[i] & ~DB_NEW; + rc = 0; + ntxn = (MDB_ntxn *)txn; + ntxn->mnt_pgstate = env->me_pgstate; // save parent me_pghead & co + if (env->me_pghead) { + size = MDB_IDL_SIZEOF(env->me_pghead); + env->me_pghead = mdb_midl_alloc(env->me_pghead[0]); + if (env->me_pghead) + memcpy(env->me_pghead, ntxn->mnt_pgstate.mf_pghead, size); + else + rc = ENOMEM; + } + if (!rc) + rc = mdb_cursor_shadow(parent, txn); + if (rc) + mdb_txn_reset0(txn, "beginchild-fail"); + } else { + rc = mdb_txn_renew0(txn); } - if (!rc) - rc = mdb_cursor_shadow(parent, txn); if (rc) - mdb_txn_reset0(txn, "beginchild-fail"); - } else { - rc = mdb_txn_renew0(txn); - } - if (rc) - free(txn); - else { - *ret = txn; - DPRINTF(("begin txn %"Z"u%c %p on mdbenv %p, root page %"Z"u", - txn->mt_txnid, (txn->mt_flags & MDB_TXN_RDONLY) ? 'r' : 'w', - (void *) txn, (void *) env, txn->mt_dbs[MAIN_DBI].md_root)); - } - - return rc; - */ - return nil -} + free(txn); + else { + *ret = txn; + DPRINTF(("begin txn %"Z"u%c %p on mdbenv %p, root page %"Z"u", + txn->mt_txnid, (txn->mt_flags & MDB_TXN_RDONLY) ? 'r' : 'w', + (void *) txn, (void *) env, txn->mt_dbs[MAIN_DBI].md_root)); + } -// Write the environment parameters of a freshly created DB environment. -// @param[in] env the environment handle -// @param[out] meta address of where to store the meta information -// @return 0 on success, non-zero on failure. -func (db *db) initMeta(meta *meta) error { - /* - MDB_page *p, *q; - int rc; - unsigned int psize; -#ifdef _WIN32 - DWORD len; - OVERLAPPED ov; - memset(&ov, 0, sizeof(ov)); -#define DO_PWRITE(rc, fd, ptr, size, len, pos) do { \ - ov.Offset = pos; \ - rc = WriteFile(fd, ptr, size, &len, &ov); } while(0) -#else - int len; -#define DO_PWRITE(rc, fd, ptr, size, len, pos) do { \ - len = pwrite(fd, ptr, size, pos); \ - rc = (len >= 0); } while(0) -#endif - - DPUTS("writing new meta page"); - - psize = env->me_psize; - - meta->mm_magic = MDB_MAGIC; - meta->mm_version = MDB_DATA_VERSION; - meta->mm_mapsize = env->me_mapsize; - meta->mm_psize = psize; - meta->mm_last_pg = 1; - meta->mm_flags = env->me_flags & 0xffff; - meta->mm_flags |= MDB_INTEGERKEY; - meta->mm_dbs[0].md_root = P_INVALID; - meta->mm_dbs[1].md_root = P_INVALID; - - p = calloc(2, psize); - p->mp_pgno = 0; - p->mp_flags = P_META; - *(MDB_meta *)METADATA(p) = *meta; - - q = (MDB_page *)((char *)p + psize); - q->mp_pgno = 1; - q->mp_flags = P_META; - *(MDB_meta *)METADATA(q) = *meta; - - DO_PWRITE(rc, env->me_fd, p, psize * 2, len, 0); - if (!rc) - rc = ErrCode(); - else if ((unsigned) len == psize * 2) - rc = MDB_SUCCESS; - else - rc = ENOSPC; - free(p); - return rc; + return rc; */ - return nil + return nil, nil } // Check both meta pages to see which one is newer. // @param[in] env the environment handle // @return meta toggle (0 or 1). -func (db *db) pickMeta() int { +func (db *DB) pickMeta() int { /* - return (env->me_metas[0]->mm_txnid < env->me_metas[1]->mm_txnid); + return (env->me_metas[0]->mm_txnid < env->me_metas[1]->mm_txnid); */ return 0 } -func (db *db) Create() error { +func (db *DB) Create() error { /* - MDB_env *e; - - e = calloc(1, sizeof(MDB_env)); - if (!e) - return ENOMEM; - - e->me_maxreaders = DEFAULT_READERS; - e->me_maxdbs = e->me_numdbs = 2; - e->me_fd = INVALID_HANDLE_VALUE; - e->me_lfd = INVALID_HANDLE_VALUE; - e->me_mfd = INVALID_HANDLE_VALUE; -#ifdef MDB_USE_POSIX_SEM - e->me_rmutex = SEM_FAILED; - e->me_wmutex = SEM_FAILED; -#endif - e->me_pid = getpid(); - GET_PAGESIZE(e->me_os_psize); - VGMEMP_CREATE(e,0,0); - *env = e; - return MDB_SUCCESS; + MDB_env *e; + + e = calloc(1, sizeof(MDB_env)); + if (!e) + return ENOMEM; + + e->me_maxreaders = DEFAULT_READERS; + e->me_maxdbs = e->me_numdbs = 2; + e->me_fd = INVALID_HANDLE_VALUE; + e->me_lfd = INVALID_HANDLE_VALUE; + e->me_mfd = INVALID_HANDLE_VALUE; + #ifdef MDB_USE_POSIX_SEM + e->me_rmutex = SEM_FAILED; + e->me_wmutex = SEM_FAILED; + #endif + e->me_pid = getpid(); + GET_PAGESIZE(e->me_os_psize); + VGMEMP_CREATE(e,0,0); + *env = e; + return MDB_SUCCESS; */ return nil } -// int mdb_env_map(MDB_env *env, void *addr, int newsize) -func (db *db) mmap(newsize int) error { +func (db *DB) setMapSize(size int) error { /* - MDB_page *p; - unsigned int flags = env->me_flags; -#ifdef _WIN32 - int rc; - HANDLE mh; - LONG sizelo, sizehi; - sizelo = env->me_mapsize & 0xffffffff; - sizehi = env->me_mapsize >> 16 >> 16; // only needed on Win64 - - // Windows won't create mappings for zero length files. - // Just allocate the maxsize right now. - if (newsize) { - if (SetFilePointer(env->me_fd, sizelo, &sizehi, 0) != (DWORD)sizelo - || !SetEndOfFile(env->me_fd) - || SetFilePointer(env->me_fd, 0, NULL, 0) != 0) - return ErrCode(); - } - mh = CreateFileMapping(env->me_fd, NULL, flags & MDB_WRITEMAP ? - PAGE_READWRITE : PAGE_READONLY, - sizehi, sizelo, NULL); - if (!mh) - return ErrCode(); - env->me_map = MapViewOfFileEx(mh, flags & MDB_WRITEMAP ? - FILE_MAP_WRITE : FILE_MAP_READ, - 0, 0, env->me_mapsize, addr); - rc = env->me_map ? 0 : ErrCode(); - CloseHandle(mh); - if (rc) - return rc; -#else - int prot = PROT_READ; - if (flags & MDB_WRITEMAP) { - prot |= PROT_WRITE; - if (ftruncate(env->me_fd, env->me_mapsize) < 0) - return ErrCode(); - } - env->me_map = mmap(addr, env->me_mapsize, prot, MAP_SHARED, - env->me_fd, 0); - if (env->me_map == MAP_FAILED) { - env->me_map = NULL; - return ErrCode(); - } - - if (flags & MDB_NORDAHEAD) { - // Turn off readahead. It's harmful when the DB is larger than RAM. -#ifdef MADV_RANDOM - madvise(env->me_map, env->me_mapsize, MADV_RANDOM); -#else -#ifdef POSIX_MADV_RANDOM - posix_madvise(env->me_map, env->me_mapsize, POSIX_MADV_RANDOM); -#endif // POSIX_MADV_RANDOM -#endif // MADV_RANDOM - } -#endif // _WIN32 - - // Can happen because the address argument to mmap() is just a - // hint. mmap() can pick another, e.g. if the range is in use. - // The MAP_FIXED flag would prevent that, but then mmap could - // instead unmap existing pages to make room for the new map. - if (addr && env->me_map != addr) - return EBUSY; // TODO: Make a new MDB_* error code? - - p = (MDB_page *)env->me_map; - env->me_metas[0] = METADATA(p); - env->me_metas[1] = (MDB_meta *)((char *)env->me_metas[0] + env->me_psize); - - return MDB_SUCCESS; - */ - return nil -} - -func (db *db) setMapSize(size int) error { - /* - // If env is already open, caller is responsible for making - // sure there are no active txns. - if (env->me_map) { - int rc; - void *old; - if (env->me_txn) - return EINVAL; - if (!size) - size = env->me_metas[mdb_env_pick_meta(env)]->mm_mapsize; - else if (size < env->me_mapsize) { - // If the configured size is smaller, make sure it's - // still big enough. Silently round up to minimum if not. - size_t minsize = (env->me_metas[mdb_env_pick_meta(env)]->mm_last_pg + 1) * env->me_psize; - if (size < minsize) - size = minsize; + // If env is already open, caller is responsible for making + // sure there are no active txns. + if (env->me_map) { + int rc; + void *old; + if (env->me_txn) + return EINVAL; + if (!size) + size = env->me_metas[mdb_env_pick_meta(env)]->mm_mapsize; + else if (size < env->me_mapsize) { + // If the configured size is smaller, make sure it's + // still big enough. Silently round up to minimum if not. + size_t minsize = (env->me_metas[mdb_env_pick_meta(env)]->mm_last_pg + 1) * env->me_psize; + if (size < minsize) + size = minsize; + } + munmap(env->me_map, env->me_mapsize); + env->me_mapsize = size; + old = (env->me_flags & MDB_FIXEDMAP) ? env->me_map : NULL; + rc = mdb_env_map(env, old, 1); + if (rc) + return rc; } - munmap(env->me_map, env->me_mapsize); env->me_mapsize = size; - old = (env->me_flags & MDB_FIXEDMAP) ? env->me_map : NULL; - rc = mdb_env_map(env, old, 1); - if (rc) - return rc; - } - env->me_mapsize = size; - if (env->me_psize) - env->me_maxpg = env->me_mapsize / env->me_psize; - return MDB_SUCCESS; + if (env->me_psize) + env->me_maxpg = env->me_mapsize / env->me_psize; + return MDB_SUCCESS; */ return nil } -func (db *db) setMaxBucketCount(count int) error { +func (db *DB) setMaxBucketCount(count int) error { /* - if (env->me_map) - return EINVAL; - env->me_maxdbs = dbs + 2; // Named databases + main and free DB - return MDB_SUCCESS; + if (env->me_map) + return EINVAL; + env->me_maxdbs = dbs + 2; // Named databases + main and free DB + return MDB_SUCCESS; */ return nil } -func (db *db) setMaxReaderCount(count int) error { +func (db *DB) setMaxReaderCount(count int) error { /* - if (env->me_map || readers < 1) - return EINVAL; - env->me_maxreaders = readers; - return MDB_SUCCESS; + if (env->me_map || readers < 1) + return EINVAL; + env->me_maxreaders = readers; + return MDB_SUCCESS; */ + return nil } -func (db *db) getMaxReaderCount(count int) (int, error) { +func (db *DB) getMaxReaderCount(count int) (int, error) { /* - if (!env || !readers) - return EINVAL; - *readers = env->me_maxreaders; - return MDB_SUCCESS; + if (!env || !readers) + return EINVAL; + *readers = env->me_maxreaders; + return MDB_SUCCESS; */ return 0, nil } - // Destroy resources from mdb_env_open(), clear our readers & DBIs -func (db *db) close0(excl) { +func (db *DB) close0(excl int) { /* - int i; - - if (!(env->me_flags & MDB_ENV_ACTIVE)) - return; - - // Doing this here since me_dbxs may not exist during mdb_env_close - for (i = env->me_maxdbs; --i > MAIN_DBI; ) - free(env->me_dbxs[i].md_name.mv_data); - - free(env->me_pbuf); - free(env->me_dbflags); - free(env->me_dbxs); - free(env->me_path); - free(env->me_dirty_list); - mdb_midl_free(env->me_free_pgs); - - if (env->me_flags & MDB_ENV_TXKEY) { - pthread_key_delete(env->me_txkey); -#ifdef _WIN32 - // Delete our key from the global list - for (i=0; i<mdb_tls_nkeys; i++) - if (mdb_tls_keys[i] == env->me_txkey) { - mdb_tls_keys[i] = mdb_tls_keys[mdb_tls_nkeys-1]; - mdb_tls_nkeys--; - break; + int i; + + if (!(env->me_flags & MDB_ENV_ACTIVE)) + return; + + // Doing this here since me_dbxs may not exist during mdb_env_close + for (i = env->me_maxdbs; --i > MAIN_DBI; ) + free(env->me_dbxs[i].md_name.mv_data); + + free(env->me_pbuf); + free(env->me_dbflags); + free(env->me_dbxs); + free(env->me_path); + free(env->me_dirty_list); + mdb_midl_free(env->me_free_pgs); + + if (env->me_flags & MDB_ENV_TXKEY) { + pthread_key_delete(env->me_txkey); + #ifdef _WIN32 + // Delete our key from the global list + for (i=0; i<mdb_tls_nkeys; i++) + if (mdb_tls_keys[i] == env->me_txkey) { + mdb_tls_keys[i] = mdb_tls_keys[mdb_tls_nkeys-1]; + mdb_tls_nkeys--; + break; + } + #endif } -#endif - } - if (env->me_map) { - munmap(env->me_map, env->me_mapsize); - } - if (env->me_mfd != env->me_fd && env->me_mfd != INVALID_HANDLE_VALUE) - (void) close(env->me_mfd); - if (env->me_fd != INVALID_HANDLE_VALUE) - (void) close(env->me_fd); - if (env->me_txns) { - MDB_PID_T pid = env->me_pid; - // Clearing readers is done in this function because - // me_txkey with its destructor must be disabled first. - for (i = env->me_numreaders; --i >= 0; ) - if (env->me_txns->mti_readers[i].mr_pid == pid) - env->me_txns->mti_readers[i].mr_pid = 0; -#ifdef _WIN32 - if (env->me_rmutex) { - CloseHandle(env->me_rmutex); - if (env->me_wmutex) CloseHandle(env->me_wmutex); - } - // Windows automatically destroys the mutexes when - // the last handle closes. -#elif defined(MDB_USE_POSIX_SEM) - if (env->me_rmutex != SEM_FAILED) { - sem_close(env->me_rmutex); - if (env->me_wmutex != SEM_FAILED) - sem_close(env->me_wmutex); - // If we have the filelock: If we are the - // only remaining user, clean up semaphores. - if (excl == 0) - mdb_env_excl_lock(env, &excl); - if (excl > 0) { - sem_unlink(env->me_txns->mti_rmname); - sem_unlink(env->me_txns->mti_wmname); + if (env->me_map) { + munmap(env->me_map, env->me_mapsize); + } + if (env->me_mfd != env->me_fd && env->me_mfd != INVALID_HANDLE_VALUE) + (void) close(env->me_mfd); + if (env->me_fd != INVALID_HANDLE_VALUE) + (void) close(env->me_fd); + if (env->me_txns) { + MDB_PID_T pid = env->me_pid; + // Clearing readers is done in this function because + // me_txkey with its destructor must be disabled first. + for (i = env->me_numreaders; --i >= 0; ) + if (env->me_txns->mti_readers[i].mr_pid == pid) + env->me_txns->mti_readers[i].mr_pid = 0; + #ifdef _WIN32 + if (env->me_rmutex) { + CloseHandle(env->me_rmutex); + if (env->me_wmutex) CloseHandle(env->me_wmutex); + } + // Windows automatically destroys the mutexes when + // the last handle closes. + #elif defined(MDB_USE_POSIX_SEM) + if (env->me_rmutex != SEM_FAILED) { + sem_close(env->me_rmutex); + if (env->me_wmutex != SEM_FAILED) + sem_close(env->me_wmutex); + // If we have the filelock: If we are the + // only remaining user, clean up semaphores. + if (excl == 0) + mdb_env_excl_lock(env, &excl); + if (excl > 0) { + sem_unlink(env->me_txns->mti_rmname); + sem_unlink(env->me_txns->mti_wmname); + } + } + #endif + munmap((void *)env->me_txns, (env->me_maxreaders-1)*sizeof(MDB_reader)+sizeof(MDB_txninfo)); + } + if (env->me_lfd != INVALID_HANDLE_VALUE) { + #ifdef _WIN32 + if (excl >= 0) { + // Unlock the lockfile. Windows would have unlocked it + // after closing anyway, but not necessarily at once. + UnlockFile(env->me_lfd, 0, 0, 1, 0); + } + #endif + (void) close(env->me_lfd); } - } -#endif - munmap((void *)env->me_txns, (env->me_maxreaders-1)*sizeof(MDB_reader)+sizeof(MDB_txninfo)); - } - if (env->me_lfd != INVALID_HANDLE_VALUE) { -#ifdef _WIN32 - if (excl >= 0) { - // Unlock the lockfile. Windows would have unlocked it - // after closing anyway, but not necessarily at once. - UnlockFile(env->me_lfd, 0, 0, 1, 0); - } -#endif - (void) close(env->me_lfd); - } - env->me_flags &= ~(MDB_ENV_ACTIVE|MDB_ENV_TXKEY); + env->me_flags &= ~(MDB_ENV_ACTIVE|MDB_ENV_TXKEY); */ } -func (db *db) copyfd(handle int) error { +func (db *DB) copyfd(handle int) error { /* - MDB_txn *txn = NULL; - int rc; - size_t wsize; - char *ptr; -#ifdef _WIN32 - DWORD len, w2; -#define DO_WRITE(rc, fd, ptr, w2, len) rc = WriteFile(fd, ptr, w2, &len, NULL) -#else - ssize_t len; - size_t w2; -#define DO_WRITE(rc, fd, ptr, w2, len) len = write(fd, ptr, w2); rc = (len >= 0) -#endif - - // Do the lock/unlock of the reader mutex before starting the - // write txn. Otherwise other read txns could block writers. - rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn); - if (rc) - return rc; - - if (env->me_txns) { - // We must start the actual read txn after blocking writers - mdb_txn_reset0(txn, "reset-stage1"); - - // Temporarily block writers until we snapshot the meta pages - LOCK_MUTEX_W(env); - - rc = mdb_txn_renew0(txn); - if (rc) { - UNLOCK_MUTEX_W(env); - goto leave; - } - } - - wsize = env->me_psize * 2; - ptr = env->me_map; - w2 = wsize; - while (w2 > 0) { - DO_WRITE(rc, fd, ptr, w2, len); - if (!rc) { - rc = ErrCode(); - break; - } else if (len > 0) { - rc = MDB_SUCCESS; - ptr += len; - w2 -= len; - continue; - } else { - // Non-blocking or async handles are not supported - rc = EIO; - break; - } - } - if (env->me_txns) - UNLOCK_MUTEX_W(env); - - if (rc) - goto leave; + MDB_txn *txn = NULL; + int rc; + size_t wsize; + char *ptr; + #ifdef _WIN32 + DWORD len, w2; + #define DO_WRITE(rc, fd, ptr, w2, len) rc = WriteFile(fd, ptr, w2, &len, NULL) + #else + ssize_t len; + size_t w2; + #define DO_WRITE(rc, fd, ptr, w2, len) len = write(fd, ptr, w2); rc = (len >= 0) + #endif + + // Do the lock/unlock of the reader mutex before starting the + // write txn. Otherwise other read txns could block writers. + rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn); + if (rc) + return rc; + + if (env->me_txns) { + // We must start the actual read txn after blocking writers + mdb_txn_reset0(txn, "reset-stage1"); + + // Temporarily block writers until we snapshot the meta pages + LOCK_MUTEX_W(env); + + rc = mdb_txn_renew0(txn); + if (rc) { + UNLOCK_MUTEX_W(env); + goto leave; + } + } - wsize = txn->mt_next_pgno * env->me_psize - wsize; - while (wsize > 0) { - if (wsize > MAX_WRITE) - w2 = MAX_WRITE; - else + wsize = env->me_psize * 2; + ptr = env->me_map; w2 = wsize; - DO_WRITE(rc, fd, ptr, w2, len); - if (!rc) { - rc = ErrCode(); - break; - } else if (len > 0) { - rc = MDB_SUCCESS; - ptr += len; - wsize -= len; - continue; - } else { - rc = EIO; - break; - } - } - -leave: - mdb_txn_abort(txn); - return rc; -} + while (w2 > 0) { + DO_WRITE(rc, fd, ptr, w2, len); + if (!rc) { + rc = ErrCode(); + break; + } else if (len > 0) { + rc = MDB_SUCCESS; + ptr += len; + w2 -= len; + continue; + } else { + // Non-blocking or async handles are not supported + rc = EIO; + break; + } + } + if (env->me_txns) + UNLOCK_MUTEX_W(env); + + if (rc) + goto leave; + + wsize = txn->mt_next_pgno * env->me_psize - wsize; + while (wsize > 0) { + if (wsize > MAX_WRITE) + w2 = MAX_WRITE; + else + w2 = wsize; + DO_WRITE(rc, fd, ptr, w2, len); + if (!rc) { + rc = ErrCode(); + break; + } else if (len > 0) { + rc = MDB_SUCCESS; + ptr += len; + wsize -= len; + continue; + } else { + rc = EIO; + break; + } + } -int -mdb_env_copy(MDB_env *env, const char *path) -{ - int rc, len; - char *lpath; - HANDLE newfd = INVALID_HANDLE_VALUE; + leave: + mdb_txn_abort(txn); + return rc; + } - if (env->me_flags & MDB_NOSUBDIR) { - lpath = (char *)path; - } else { - len = strlen(path); - len += sizeof(DATANAME); - lpath = malloc(len); - if (!lpath) - return ENOMEM; - sprintf(lpath, "%s" DATANAME, path); - } + int + mdb_env_copy(MDB_env *env, const char *path) + { + int rc, len; + char *lpath; + HANDLE newfd = INVALID_HANDLE_VALUE; + + if (env->me_flags & MDB_NOSUBDIR) { + lpath = (char *)path; + } else { + len = strlen(path); + len += sizeof(DATANAME); + lpath = malloc(len); + if (!lpath) + return ENOMEM; + sprintf(lpath, "%s" DATANAME, path); + } - // The destination path must exist, but the destination file must not. - // We don't want the OS to cache the writes, since the source data is - // already in the OS cache. -#ifdef _WIN32 - newfd = CreateFile(lpath, GENERIC_WRITE, 0, NULL, CREATE_NEW, - FILE_FLAG_NO_BUFFERING|FILE_FLAG_WRITE_THROUGH, NULL); -#else - newfd = open(lpath, O_WRONLY|O_CREAT|O_EXCL, 0666); -#endif - if (newfd == INVALID_HANDLE_VALUE) { - rc = ErrCode(); - goto leave; - } + // The destination path must exist, but the destination file must not. + // We don't want the OS to cache the writes, since the source data is + // already in the OS cache. + #ifdef _WIN32 + newfd = CreateFile(lpath, GENERIC_WRITE, 0, NULL, CREATE_NEW, + FILE_FLAG_NO_BUFFERING|FILE_FLAG_WRITE_THROUGH, NULL); + #else + newfd = open(lpath, O_WRONLY|O_CREAT|O_EXCL, 0666); + #endif + if (newfd == INVALID_HANDLE_VALUE) { + rc = ErrCode(); + goto leave; + } -#ifdef O_DIRECT - // Set O_DIRECT if the file system supports it - if ((rc = fcntl(newfd, F_GETFL)) != -1) - (void) fcntl(newfd, F_SETFL, rc | O_DIRECT); -#endif -#ifdef F_NOCACHE // __APPLE__ - rc = fcntl(newfd, F_NOCACHE, 1); - if (rc) { - rc = ErrCode(); - goto leave; - } -#endif + #ifdef O_DIRECT + // Set O_DIRECT if the file system supports it + if ((rc = fcntl(newfd, F_GETFL)) != -1) + (void) fcntl(newfd, F_SETFL, rc | O_DIRECT); + #endif + #ifdef F_NOCACHE // __APPLE__ + rc = fcntl(newfd, F_NOCACHE, 1); + if (rc) { + rc = ErrCode(); + goto leave; + } + #endif - rc = mdb_env_copyfd(env, newfd); + rc = mdb_env_copyfd(env, newfd); -leave: - if (!(env->me_flags & MDB_NOSUBDIR)) - free(lpath); - if (newfd != INVALID_HANDLE_VALUE) - if (close(newfd) < 0 && rc == MDB_SUCCESS) - rc = ErrCode(); + leave: + if (!(env->me_flags & MDB_NOSUBDIR)) + free(lpath); + if (newfd != INVALID_HANDLE_VALUE) + if (close(newfd) < 0 && rc == MDB_SUCCESS) + rc = ErrCode(); - return rc; + return rc; */ return nil } -func (db *db) Close() { +func (db *DB) Close() { /* - MDB_page *dp; + MDB_page *dp; - if (env == NULL) - return; + if (env == NULL) + return; - VGMEMP_DESTROY(env); - while ((dp = env->me_dpages) != NULL) { - VGMEMP_DEFINED(&dp->mp_next, sizeof(dp->mp_next)); - env->me_dpages = dp->mp_next; - free(dp); - } + VGMEMP_DESTROY(env); + while ((dp = env->me_dpages) != NULL) { + VGMEMP_DEFINED(&dp->mp_next, sizeof(dp->mp_next)); + env->me_dpages = dp->mp_next; + free(dp); + } - mdb_env_close0(env, 0); - free(env); + mdb_env_close0(env, 0); + free(env); */ } @@ -862,17 +712,17 @@ func (db *db) Close() { // @param[in] key The key for the node. // @param[in] data The data for the node. // @return The number of bytes needed to store the node. -func (db *db) LeafSize(key []byte, data []byte) int { +func (db *DB) LeafSize(key []byte, data []byte) int { /* - size_t sz; + size_t sz; - sz = LEAFSIZE(key, data); - if (sz > env->me_nodemax) { - // put on overflow page - sz -= data->mv_size - sizeof(pgno_t); - } + sz = LEAFSIZE(key, data); + if (sz > env->me_nodemax) { + // put on overflow page + sz -= data->mv_size - sizeof(pgno_t); + } - return EVEN(sz + sizeof(indx_t)); + return EVEN(sz + sizeof(indx_t)); */ return 0 } @@ -886,183 +736,179 @@ func (db *db) LeafSize(key []byte, data []byte) int { // @param[in] env The environment handle. // @param[in] key The key for the node. // @return The number of bytes needed to store the node. -func (db *db) BranchSize(key []byte) int { +func (db *DB) BranchSize(key []byte) int { /* - size_t sz; + size_t sz; - sz = INDXSIZE(key); - if (sz > env->me_nodemax) { - // put on overflow page - // not implemented - // sz -= key->size - sizeof(pgno_t); - } + sz = INDXSIZE(key); + if (sz > env->me_nodemax) { + // put on overflow page + // not implemented + // sz -= key->size - sizeof(pgno_t); + } - return sz + sizeof(indx_t); + return sz + sizeof(indx_t); */ return 0 } -func (db *db) SetFlags(flag int, onoff bool) error { +func (db *DB) SetFlags(flag int, onoff bool) error { /* - if ((flag & CHANGEABLE) != flag) - return EINVAL; - if (onoff) - env->me_flags |= flag; - else - env->me_flags &= ~flag; - return MDB_SUCCESS; + if ((flag & CHANGEABLE) != flag) + return EINVAL; + if (onoff) + env->me_flags |= flag; + else + env->me_flags &= ~flag; + return MDB_SUCCESS; */ return nil } -func (db *db) Flags() int { - return db.flags -} +func (db *DB) Stat() *Stat { + /* + int toggle; + if (env == NULL || arg == NULL) + return EINVAL; -func (db *db) Stat() *Stat - /* - int toggle; - - if (env == NULL || arg == NULL) - return EINVAL; - - toggle = mdb_env_pick_meta(env); - stat := &Stat{} - stat->ms_psize = env->me_psize; - stat->ms_depth = db->md_depth; - stat->ms_branch_pages = db->md_branch_pages; - stat->ms_leaf_pages = db->md_leaf_pages; - stat->ms_overflow_pages = db->md_overflow_pages; - stat->ms_entries = db->md_entries; - - //return mdb_stat0(env, &env->me_metas[toggle]->mm_dbs[MAIN_DBI], stat); - return stat + toggle = mdb_env_pick_meta(env); + stat := &Stat{} + stat->ms_psize = env->me_psize; + stat->ms_depth = db->md_depth; + stat->ms_branch_pages = db->md_branch_pages; + stat->ms_leaf_pages = db->md_leaf_pages; + stat->ms_overflow_pages = db->md_overflow_pages; + stat->ms_entries = db->md_entries; + + //return mdb_stat0(env, &env->me_metas[toggle]->mm_dbs[MAIN_DBI], stat); + return stat */ + return nil } -func (db *db) Info() *Info { +func (db *DB) Info() *Info { /* - int toggle; + int toggle; - if (env == NULL || arg == NULL) - return EINVAL; + if (env == NULL || arg == NULL) + return EINVAL; - toggle = mdb_env_pick_meta(env); - arg->me_mapaddr = (env->me_flags & MDB_FIXEDMAP) ? env->me_map : 0; - arg->me_mapsize = env->me_mapsize; - arg->me_maxreaders = env->me_maxreaders; + toggle = mdb_env_pick_meta(env); + arg->me_mapaddr = (env->me_flags & MDB_FIXEDMAP) ? env->me_map : 0; + arg->me_mapsize = env->me_mapsize; + arg->me_maxreaders = env->me_maxreaders; - // me_numreaders may be zero if this process never used any readers. Use - // the shared numreader count if it exists. - arg->me_numreaders = env->me_txns ? env->me_txns->mti_numreaders : env->me_numreaders; + // me_numreaders may be zero if this process never used any readers. Use + // the shared numreader count if it exists. + arg->me_numreaders = env->me_txns ? env->me_txns->mti_numreaders : env->me_numreaders; - arg->me_last_pgno = env->me_metas[toggle]->mm_last_pg; - arg->me_last_txnid = env->me_metas[toggle]->mm_txnid; - return MDB_SUCCESS; + arg->me_last_pgno = env->me_metas[toggle]->mm_last_pg; + arg->me_last_txnid = env->me_metas[toggle]->mm_txnid; + return MDB_SUCCESS; */ return nil } // TODO: Move to bucket.go -func (db *db) CloseBucket(b Bucket) { +func (db *DB) CloseBucket(b Bucket) { /* - char *ptr; - if (dbi <= MAIN_DBI || dbi >= env->me_maxdbs) - return; - ptr = env->me_dbxs[dbi].md_name.mv_data; - env->me_dbxs[dbi].md_name.mv_data = NULL; - env->me_dbxs[dbi].md_name.mv_size = 0; - env->me_dbflags[dbi] = 0; - free(ptr); + char *ptr; + if (dbi <= MAIN_DBI || dbi >= env->me_maxdbs) + return; + ptr = env->me_dbxs[dbi].md_name.mv_data; + env->me_dbxs[dbi].md_name.mv_data = NULL; + env->me_dbxs[dbi].md_name.mv_size = 0; + env->me_dbflags[dbi] = 0; + free(ptr); */ } //int mdb_reader_list(MDB_env *env, MDB_msg_func *func, void *ctx) -func (db *db) getReaderList() error { +func (db *DB) getReaderList() error { /* - unsigned int i, rdrs; - MDB_reader *mr; - char buf[64]; - int rc = 0, first = 1; - - if (!env || !func) - return -1; - if (!env->me_txns) { - return func("(no reader locks)\n", ctx); - } - rdrs = env->me_txns->mti_numreaders; - mr = env->me_txns->mti_readers; - for (i=0; i<rdrs; i++) { - if (mr[i].mr_pid) { - txnid_t txnid = mr[i].mr_txnid; - sprintf(buf, txnid == (txnid_t)-1 ? - "%10d %"Z"x -\n" : "%10d %"Z"x %"Z"u\n", - (int)mr[i].mr_pid, (size_t)mr[i].mr_tid, txnid); - if (first) { - first = 0; - rc = func(" pid thread txnid\n", ctx); + unsigned int i, rdrs; + MDB_reader *mr; + char buf[64]; + int rc = 0, first = 1; + + if (!env || !func) + return -1; + if (!env->me_txns) { + return func("(no reader locks)\n", ctx); + } + rdrs = env->me_txns->mti_numreaders; + mr = env->me_txns->mti_readers; + for (i=0; i<rdrs; i++) { + if (mr[i].mr_pid) { + txnid_t txnid = mr[i].mr_txnid; + sprintf(buf, txnid == (txnid_t)-1 ? + "%10d %"Z"x -\n" : "%10d %"Z"x %"Z"u\n", + (int)mr[i].mr_pid, (size_t)mr[i].mr_tid, txnid); + if (first) { + first = 0; + rc = func(" pid thread txnid\n", ctx); + if (rc < 0) + break; + } + rc = func(buf, ctx); if (rc < 0) break; } - rc = func(buf, ctx); - if (rc < 0) - break; } - } - if (first) { - rc = func("(no active readers)\n", ctx); - } - return rc; + if (first) { + rc = func("(no active readers)\n", ctx); + } + return rc; */ return nil } // (bool return is whether reader is dead) -func (db *db) checkReaders() (bool, error) { +func (db *DB) checkReaders() (bool, error) { /* - unsigned int i, j, rdrs; - MDB_reader *mr; - MDB_PID_T *pids, pid; - int count = 0; - - if (!env) - return EINVAL; - if (dead) - *dead = 0; - if (!env->me_txns) - return MDB_SUCCESS; - rdrs = env->me_txns->mti_numreaders; - pids = malloc((rdrs+1) * sizeof(MDB_PID_T)); - if (!pids) - return ENOMEM; - pids[0] = 0; - mr = env->me_txns->mti_readers; - for (i=0; i<rdrs; i++) { - if (mr[i].mr_pid && mr[i].mr_pid != env->me_pid) { - pid = mr[i].mr_pid; - if (mdb_pid_insert(pids, pid) == 0) { - if (!mdb_reader_pid(env, Pidcheck, pid)) { - LOCK_MUTEX_R(env); - // Recheck, a new process may have reused pid + unsigned int i, j, rdrs; + MDB_reader *mr; + MDB_PID_T *pids, pid; + int count = 0; + + if (!env) + return EINVAL; + if (dead) + *dead = 0; + if (!env->me_txns) + return MDB_SUCCESS; + rdrs = env->me_txns->mti_numreaders; + pids = malloc((rdrs+1) * sizeof(MDB_PID_T)); + if (!pids) + return ENOMEM; + pids[0] = 0; + mr = env->me_txns->mti_readers; + for (i=0; i<rdrs; i++) { + if (mr[i].mr_pid && mr[i].mr_pid != env->me_pid) { + pid = mr[i].mr_pid; + if (mdb_pid_insert(pids, pid) == 0) { if (!mdb_reader_pid(env, Pidcheck, pid)) { - for (j=i; j<rdrs; j++) - if (mr[j].mr_pid == pid) { - DPRINTF(("clear stale reader pid %u txn %"Z"d", - (unsigned) pid, mr[j].mr_txnid)); - mr[j].mr_pid = 0; - count++; - } + LOCK_MUTEX_R(env); + // Recheck, a new process may have reused pid + if (!mdb_reader_pid(env, Pidcheck, pid)) { + for (j=i; j<rdrs; j++) + if (mr[j].mr_pid == pid) { + DPRINTF(("clear stale reader pid %u txn %"Z"d", + (unsigned) pid, mr[j].mr_txnid)); + mr[j].mr_pid = 0; + count++; + } + } + UNLOCK_MUTEX_R(env); } - UNLOCK_MUTEX_R(env); } } } - } - free(pids); - if (dead) - *dead = count; - return MDB_SUCCESS; + free(pids); + if (dead) + *dead = count; + return MDB_SUCCESS; */ return false, nil } |