Example #1
0
EXPORTED int mappedfile_writelock(struct mappedfile *mf)
{
    int r;
    struct stat sbuf;
    const char *lockfailaction;

    assert(mf->lock_status == MF_UNLOCKED);
    assert(mf->fd != -1);
    assert(mf->is_rw);
    assert(!mf->dirty);

    r = lock_reopen(mf->fd, mf->fname, &sbuf, &lockfailaction);
    if (r < 0) {
	syslog(LOG_ERR, "IOERROR: %s %s: %m", lockfailaction, mf->fname);
	return r;
    }
    mf->lock_status = MF_WRITELOCKED;

    /* XXX - can we guarantee the fd isn't reused? */
    if (mf->map_ino != sbuf.st_ino) {
	buf_free(&mf->map_buf);
    }

    _ensure_mapped(mf, sbuf.st_size, /*update*/0);

    return 0;
}
Example #2
0
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;
}
Example #3
0
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;
}