#include <assert.h>
#include <ccan/likely/likely.h>
-void tdb_munmap(struct tdb_context *tdb)
+void tdb_munmap(struct tdb_file *file)
{
- if (tdb->flags & TDB_INTERNAL)
+ if (file->fd == -1)
return;
- if (tdb->map_ptr) {
- munmap(tdb->map_ptr, tdb->map_size);
- tdb->map_ptr = NULL;
+ if (file->map_ptr) {
+ munmap(file->map_ptr, file->map_size);
+ file->map_ptr = NULL;
}
}
if (tdb->flags & TDB_NOMMAP)
return;
- tdb->map_ptr = mmap(NULL, tdb->map_size, tdb->mmap_flags,
- MAP_SHARED, tdb->fd, 0);
+ tdb->file->map_ptr = mmap(NULL, tdb->file->map_size, tdb->mmap_flags,
+ MAP_SHARED, tdb->file->fd, 0);
/*
* NB. When mmap fails it returns MAP_FAILED *NOT* NULL !!!!
*/
- if (tdb->map_ptr == MAP_FAILED) {
- tdb->map_ptr = NULL;
+ if (tdb->file->map_ptr == MAP_FAILED) {
+ tdb->file->map_ptr = NULL;
tdb_logerr(tdb, TDB_SUCCESS, TDB_LOG_WARNING,
"tdb_mmap failed for size %lld (%s)",
- (long long)tdb->map_size, strerror(errno));
+ (long long)tdb->file->map_size, strerror(errno));
}
}
|| (tdb->flags & TDB_NOLOCK)
|| tdb_has_expansion_lock(tdb));
- if (len <= tdb->map_size)
+ if (len <= tdb->file->map_size)
return 0;
if (tdb->flags & TDB_INTERNAL) {
if (!probe) {
"tdb_oob len %lld beyond internal"
" malloc size %lld",
(long long)len,
- (long long)tdb->map_size);
+ (long long)tdb->file->map_size);
}
return TDB_ERR_IO;
}
return ecode;
}
- if (fstat(tdb->fd, &st) != 0) {
+ if (fstat(tdb->file->fd, &st) != 0) {
tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
"Failed to fstat file: %s", strerror(errno));
tdb_unlock_expand(tdb, F_RDLCK);
}
/* Unmap, update size, remap */
- tdb_munmap(tdb);
+ tdb_munmap(tdb->file);
- tdb->map_size = st.st_size;
+ tdb->file->map_size = st.st_size;
tdb_mmap(tdb);
return TDB_SUCCESS;
}
"Write to read-only database");
}
- /* FIXME: Bogus optimization? */
- if (len == 0) {
- return TDB_SUCCESS;
- }
-
ecode = tdb->methods->oob(tdb, off + len, 0);
if (ecode != TDB_SUCCESS) {
return ecode;
}
- if (tdb->map_ptr) {
- memcpy(off + (char *)tdb->map_ptr, buf, len);
+ if (tdb->file->map_ptr) {
+ memcpy(off + (char *)tdb->file->map_ptr, buf, len);
} else {
ssize_t ret;
- ret = pwrite(tdb->fd, buf, len, off);
- if (ret < len) {
+ ret = pwrite(tdb->file->fd, buf, len, off);
+ if (ret != len) {
/* This shouldn't happen: we avoid sparse files. */
if (ret >= 0)
errno = ENOSPC;
return ecode;
}
- if (tdb->map_ptr) {
- memcpy(buf, off + (char *)tdb->map_ptr, len);
+ if (tdb->file->map_ptr) {
+ memcpy(buf, off + (char *)tdb->file->map_ptr, len);
} else {
- ssize_t r = pread(tdb->fd, buf, len, off);
+ ssize_t r = pread(tdb->file->fd, buf, len, off);
if (r != len) {
return tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
"tdb_read failed with %zi at %zu "
"len=%zu (%s) map_size=%zu",
r, (size_t)off, (size_t)len,
strerror(errno),
- (size_t)tdb->map_size);
+ (size_t)tdb->file->map_size);
}
}
return TDB_SUCCESS;
{
while (len) {
size_t n = len > size ? size : len;
- ssize_t ret = pwrite(tdb->fd, buf, n, off);
- if (ret < n) {
+ ssize_t ret = pwrite(tdb->file->fd, buf, n, off);
+ if (ret != n) {
if (ret >= 0)
errno = ENOSPC;
}
if (tdb->flags & TDB_INTERNAL) {
- char *new = realloc(tdb->map_ptr, tdb->map_size + addition);
+ char *new = realloc(tdb->file->map_ptr,
+ tdb->file->map_size + addition);
if (!new) {
return tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
"No memory to expand database");
}
- tdb->map_ptr = new;
- tdb->map_size += addition;
+ tdb->file->map_ptr = new;
+ tdb->file->map_size += addition;
} else {
/* Unmap before trying to write; old TDB claimed OpenBSD had
* problem with this otherwise. */
- tdb_munmap(tdb);
+ tdb_munmap(tdb->file);
/* If this fails, we try to fill anyway. */
- if (ftruncate(tdb->fd, tdb->map_size + addition))
+ if (ftruncate(tdb->file->fd, tdb->file->map_size + addition))
;
/* now fill the file with something. This ensures that the
file isn't sparse, which would be very bad if we ran out of
disk. This must be done with write, not via mmap */
memset(buf, 0x43, sizeof(buf));
- ecode = fill(tdb, buf, sizeof(buf), tdb->map_size, addition);
+ ecode = fill(tdb, buf, sizeof(buf), tdb->file->map_size,
+ addition);
if (ecode != TDB_SUCCESS)
return ecode;
- tdb->map_size += addition;
+ tdb->file->map_size += addition;
tdb_mmap(tdb);
}
return TDB_SUCCESS;
{
enum TDB_ERROR ecode;
- if (unlikely(!tdb->map_ptr))
+ if (unlikely(!tdb->file->map_ptr))
return NULL;
ecode = tdb_oob(tdb, off + len, true);
if (unlikely(ecode != TDB_SUCCESS))
return TDB_ERR_PTR(ecode);
- return (char *)tdb->map_ptr + off;
+ return (char *)tdb->file->map_ptr + off;
+}
+
+void tdb_inc_seqnum(struct tdb_context *tdb)
+{
+ tdb_off_t seq;
+
+ if (likely(!(tdb->flags & TDB_CONVERT))) {
+ int64_t *direct;
+
+ direct = tdb->methods->direct(tdb,
+ offsetof(struct tdb_header,
+ seqnum),
+ sizeof(*direct), true);
+ if (likely(direct)) {
+ /* Don't let it go negative, even briefly */
+ if (unlikely((*direct) + 1) < 0)
+ *direct = 0;
+ (*direct)++;
+ return;
+ }
+ }
+
+ seq = tdb_read_off(tdb, offsetof(struct tdb_header, seqnum));
+ if (!TDB_OFF_IS_ERR(seq)) {
+ seq++;
+ if (unlikely((int64_t)seq < 0))
+ seq = 0;
+ tdb_write_off(tdb, offsetof(struct tdb_header, seqnum), seq);
+ }
}
void add_stat_(struct tdb_context *tdb, uint64_t *s, size_t val)