int main(void) { check(mdb_env_create(&env)); check(mdb_env_set_mapsize(env, 1048576UL*1024UL*3UL)); check(mdb_env_set_maxreaders(env, 126)); check(mdb_env_set_maxdbs(env, 1)); if(! access(DB_PATH, X_OK)) { system("rm -rf " DB_PATH); } check(mkdir(DB_PATH, 0777)); check(mdb_env_open(env, DB_PATH, MDB_MAPASYNC|MDB_NOSYNC|MDB_NOMETASYNC, 0644)); new_txn(); check(mdb_dbi_open(txn, NULL, 0, &dbi)); put("a"); put("b"); put("baa"); put("d"); new_txn(); check(mdb_cursor_open(txn, dbi, &c1)); check(mdb_cursor_get(c1, &keyv, &valv, MDB_LAST)); check(mdb_cursor_del(c1, 0)); check(mdb_cursor_del(c1, 0)); new_txn(); }
static int mystore(struct dbengine *db, const char *key, size_t keylen, const char *data, size_t datalen, struct txn **mytid, int overwrite) { int r = 0; char fnamebuf[1024]; int offset; unsigned long len; const char *lockfailaction; int writefd; struct iovec iov[10]; int niov; struct stat sbuf; struct buf keybuf = BUF_INITIALIZER; struct buf databuf = BUF_INITIALIZER; /* lock file, if needed */ if (!mytid || !*mytid) { r = lock_reopen(db->fd, db->fname, &sbuf, &lockfailaction); if (r < 0) { syslog(LOG_ERR, "IOERROR: %s %s: %m", lockfailaction, db->fname); return CYRUSDB_IOERROR; } if (sbuf.st_ino != db->ino) { db->ino = sbuf.st_ino; map_free(&db->base, &db->len); map_refresh(db->fd, 0, &db->base, &db->len, sbuf.st_size, db->fname, 0); db->size = sbuf.st_size; } if (mytid) { *mytid = new_txn(); } } encode(key, keylen, &keybuf); /* find entry, if it exists */ offset = bsearch_mem_mbox(keybuf.s, db->base, db->size, 0, &len); /* overwrite? */ if (len && !overwrite) { if (mytid) abort_txn(db, *mytid); buf_free(&keybuf); buf_free(&databuf); return CYRUSDB_EXISTS; } /* write new file */ if (mytid && (*mytid)->fnamenew) { strlcpy(fnamebuf, (*mytid)->fnamenew, sizeof(fnamebuf)); } else { strlcpy(fnamebuf, db->fname, sizeof(fnamebuf)); strlcat(fnamebuf, ".NEW", sizeof(fnamebuf)); } unlink(fnamebuf); r = writefd = open(fnamebuf, O_RDWR | O_CREAT, 0666); if (r < 0) { syslog(LOG_ERR, "opening %s for writing failed: %m", fnamebuf); if (mytid) abort_txn(db, *mytid); buf_free(&keybuf); buf_free(&databuf); return CYRUSDB_IOERROR; } niov = 0; if (offset) { WRITEV_ADD_TO_IOVEC(iov, niov, (char *) db->base, offset); } if (data) { /* new entry */ encode(data, datalen, &databuf); WRITEV_ADD_TO_IOVEC(iov, niov, keybuf.s, keybuf.len); WRITEV_ADD_TO_IOVEC(iov, niov, "\t", 1); WRITEV_ADD_TO_IOVEC(iov, niov, databuf.s, databuf.len); WRITEV_ADD_TO_IOVEC(iov, niov, "\n", 1); } if (db->size - (offset + len) > 0) { WRITEV_ADD_TO_IOVEC(iov, niov, (char *) db->base + offset + len, db->size - (offset + len)); } /* do the write */ r = retry_writev(writefd, iov, niov); if (r == -1) { syslog(LOG_ERR, "IOERROR: writing %s: %m", fnamebuf); close(writefd); if (mytid) abort_txn(db, *mytid); buf_free(&keybuf); buf_free(&databuf); return CYRUSDB_IOERROR; } r = 0; if (mytid) { /* setup so further accesses will be against fname.NEW */ if (fstat(writefd, &sbuf) == -1) { /* xxx ? */ } if (!(*mytid)->fnamenew) (*mytid)->fnamenew = xstrdup(fnamebuf); if ((*mytid)->fd) close((*mytid)->fd); (*mytid)->fd = writefd; map_free(&db->base, &db->len); map_refresh(writefd, 0, &db->base, &db->len, sbuf.st_size, fnamebuf, 0); db->size = sbuf.st_size; } else { /* commit immediately */ if (fsync(writefd) || fstat(writefd, &sbuf) == -1 || rename(fnamebuf, db->fname) == -1) { syslog(LOG_ERR, "IOERROR: writing %s: %m", fnamebuf); close(writefd); buf_free(&keybuf); buf_free(&databuf); return CYRUSDB_IOERROR; } close(db->fd); db->fd = writefd; /* release lock */ r = lock_unlock(db->fd, db->fname); if (r == -1) { syslog(LOG_ERR, "IOERROR: unlocking db %s: %m", db->fname); r = CYRUSDB_IOERROR; } db->ino = sbuf.st_ino; map_free(&db->base, &db->len); map_refresh(writefd, 0, &db->base, &db->len, sbuf.st_size, db->fname, 0); db->size = sbuf.st_size; } buf_free(&keybuf); buf_free(&databuf); return r; }
static int starttxn_or_refetch(struct dbengine *db, struct txn **mytid) { int r = 0; struct stat sbuf; assert(db); if (mytid && !*mytid) { const char *lockfailaction; /* start txn; grab lock */ r = lock_reopen(db->fd, db->fname, &sbuf, &lockfailaction); if (r < 0) { syslog(LOG_ERR, "IOERROR: %s %s: %m", lockfailaction, db->fname); return CYRUSDB_IOERROR; } *mytid = new_txn(); if (db->ino != sbuf.st_ino) { map_free(&db->base, &db->len); } map_refresh(db->fd, 0, &db->base, &db->len, sbuf.st_size, db->fname, 0); /* we now have the latest & greatest open */ db->size = sbuf.st_size; db->ino = sbuf.st_ino; } if (!mytid) { /* no txn, but let's try to be reasonably up-to-date */ if (stat(db->fname, &sbuf) == -1) { syslog(LOG_ERR, "IOERROR: stating flat %s: %m", db->fname); return CYRUSDB_IOERROR; } if (sbuf.st_ino != db->ino) { /* reopen */ int newfd = open(db->fname, O_RDWR); if (newfd == -1) { /* fail! */ syslog(LOG_ERR, "couldn't reopen %s: %m", db->fname); return CYRUSDB_IOERROR; } dup2(newfd, db->fd); close(newfd); if (stat(db->fname, &sbuf) == -1) { syslog(LOG_ERR, "IOERROR: stating flat %s: %m", db->fname); return CYRUSDB_IOERROR; } db->ino = sbuf.st_ino; map_free(&db->base, &db->len); } map_refresh(db->fd, 0, &db->base, &db->len, sbuf.st_size, db->fname, 0); db->size = sbuf.st_size; } return 0; }