X-Git-Url: http://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Ftdb2%2Fio.c;h=676f4942bf604c879b767e8a296eca0f319d2dae;hp=a973adde65df7658c50a001c75fbc931bb852153;hb=2ecf943a99c427b10a998f0285dd184b1a25ac65;hpb=1a24a8708494668c07e5c02284bfc2ef3b09603b diff --git a/ccan/tdb2/io.c b/ccan/tdb2/io.c index a973adde..676f4942 100644 --- a/ccan/tdb2/io.c +++ b/ccan/tdb2/io.c @@ -26,6 +26,7 @@ License along with this library; if not, see . */ #include "private.h" +#include #include void tdb_munmap(struct tdb_context *tdb) @@ -47,8 +48,7 @@ void tdb_mmap(struct tdb_context *tdb) if (tdb->flags & TDB_NOMMAP) return; - tdb->map_ptr = mmap(NULL, tdb->map_size, - PROT_READ|(tdb->read_only? 0:PROT_WRITE), + tdb->map_ptr = mmap(NULL, tdb->map_size, tdb->mmap_flags, MAP_SHARED, tdb->fd, 0); /* @@ -72,6 +72,11 @@ static int tdb_oob(struct tdb_context *tdb, tdb_off_t len, bool probe) struct stat st; int ret; + /* We can't hold pointers during this: we could unmap! */ + assert(!tdb->direct_access + || (tdb->flags & TDB_NOLOCK) + || tdb_has_expansion_lock(tdb)); + if (len <= tdb->map_size) return 0; if (tdb->flags & TDB_INTERNAL) { @@ -118,27 +123,13 @@ static int tdb_oob(struct tdb_context *tdb, tdb_off_t len, bool probe) return 0; } -static void *tdb_direct(struct tdb_context *tdb, tdb_off_t off, size_t len) -{ - if (unlikely(!tdb->map_ptr)) - return NULL; - - /* FIXME: We can do a subset of this! */ - if (tdb->transaction) - return NULL; - - if (unlikely(tdb_oob(tdb, off + len, true) == -1)) - return NULL; - return (char *)tdb->map_ptr + off; -} - /* Either make a copy into pad and return that, or return ptr into mmap. */ /* Note: pad has to be a real object, so we can't get here if len * overflows size_t */ void *tdb_get(struct tdb_context *tdb, tdb_off_t off, void *pad, size_t len) { if (likely(!(tdb->flags & TDB_CONVERT))) { - void *ret = tdb_direct(tdb, off, len); + void *ret = tdb->methods->direct(tdb, off, len); if (ret) return ret; } @@ -156,25 +147,25 @@ void *tdb_convert(const struct tdb_context *tdb, void *buf, tdb_len_t size) return buf; } -/* Return first non-zero offset in num offset array, or num. */ /* FIXME: Return the off? */ -uint64_t tdb_find_nonzero_off(struct tdb_context *tdb, tdb_off_t off, - uint64_t num) +uint64_t tdb_find_nonzero_off(struct tdb_context *tdb, + tdb_off_t base, uint64_t start, uint64_t end) { uint64_t i; const uint64_t *val; /* Zero vs non-zero is the same unconverted: minor optimization. */ - val = tdb_access_read(tdb, off, num * sizeof(tdb_off_t), false); + val = tdb_access_read(tdb, base + start * sizeof(tdb_off_t), + (end - start) * sizeof(tdb_off_t), false); if (!val) - return num; + return end; - for (i = 0; i < num; i++) { + for (i = 0; i < (end - start); i++) { if (val[i]) break; } tdb_access_release(tdb, val); - return i; + return start + i; } /* Return first zero offset in num offset array, or num. */ @@ -200,7 +191,7 @@ uint64_t tdb_find_zero_off(struct tdb_context *tdb, tdb_off_t off, int zero_out(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len) { char buf[8192] = { 0 }; - void *p = tdb_direct(tdb, off, len); + void *p = tdb->methods->direct(tdb, off, len); if (p) { memset(p, 0, len); return 0; @@ -306,7 +297,8 @@ static int tdb_write(struct tdb_context *tdb, tdb_off_t off, tdb->ecode = TDB_ERR_IO; tdb->log(tdb, TDB_DEBUG_FATAL, tdb->log_priv, "tdb_write failed at %llu len=%llu (%s)\n", - off, len, strerror(errno)); + (long long)off, (long long)len, + strerror(errno)); return -1; } } @@ -375,44 +367,29 @@ int tdb_write_off(struct tdb_context *tdb, tdb_off_t off, tdb_off_t val) return tdb_write_convert(tdb, off, &val, sizeof(val)); } -/* read a lump of data, allocating the space for it */ -void *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t len) +static void *_tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, + tdb_len_t len, unsigned int prefix) { void *buf; /* some systems don't like zero length malloc */ - buf = malloc(len ? len : 1); + buf = malloc(prefix + len ? prefix + len : 1); if (unlikely(!buf)) { tdb->ecode = TDB_ERR_OOM; tdb->log(tdb, TDB_DEBUG_ERROR, tdb->log_priv, "tdb_alloc_read malloc failed len=%lld\n", - (long long)len); - } else if (unlikely(tdb->methods->read(tdb, offset, buf, len))) { + (long long)prefix + len); + } else if (unlikely(tdb->methods->read(tdb, offset, buf+prefix, len))) { free(buf); buf = NULL; } return buf; } -uint64_t hash_record(struct tdb_context *tdb, tdb_off_t off) +/* read a lump of data, allocating the space for it */ +void *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t len) { - struct tdb_used_record pad, *r; - const void *key; - uint64_t klen, hash; - - r = tdb_get(tdb, off, &pad, sizeof(pad)); - if (!r) - /* FIXME */ - return 0; - - klen = rec_key_length(r); - key = tdb_access_read(tdb, off + sizeof(pad), klen, false); - if (!key) - return 0; - - hash = tdb_hash(tdb, key, klen); - tdb_access_release(tdb, key); - return hash; + return _tdb_alloc_read(tdb, offset, len, 0); } static int fill(struct tdb_context *tdb, @@ -474,19 +451,57 @@ static int tdb_expand_file(struct tdb_context *tdb, tdb_len_t addition) return 0; } +/* This is only neded for tdb_access_commit, but used everywhere to simplify. */ +struct tdb_access_hdr { + tdb_off_t off; + tdb_len_t len; + bool convert; +}; + const void *tdb_access_read(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len, bool convert) { - const void *ret = NULL; + const void *ret = NULL; if (likely(!(tdb->flags & TDB_CONVERT))) - ret = tdb_direct(tdb, off, len); + ret = tdb->methods->direct(tdb, off, len); if (!ret) { - ret = tdb_alloc_read(tdb, off, len); - if (convert) - tdb_convert(tdb, (void *)ret, len); - } + struct tdb_access_hdr *hdr; + hdr = _tdb_alloc_read(tdb, off, len, sizeof(*hdr)); + if (hdr) { + ret = hdr + 1; + if (convert) + tdb_convert(tdb, (void *)ret, len); + } + } else + tdb->direct_access++; + + return ret; +} + +void *tdb_access_write(struct tdb_context *tdb, + tdb_off_t off, tdb_len_t len, bool convert) +{ + void *ret = NULL; + + if (likely(!(tdb->flags & TDB_CONVERT))) + ret = tdb->methods->direct(tdb, off, len); + + if (!ret) { + struct tdb_access_hdr *hdr; + hdr = _tdb_alloc_read(tdb, off, len, sizeof(*hdr)); + if (hdr) { + hdr->off = off; + hdr->len = len; + hdr->convert = convert; + ret = hdr + 1; + if (convert) + tdb_convert(tdb, (void *)ret, len); + } + } else + tdb->direct_access++; + return ret; } @@ -495,7 +510,30 @@ void tdb_access_release(struct tdb_context *tdb, const void *p) if (!tdb->map_ptr || (char *)p < (char *)tdb->map_ptr || (char *)p >= (char *)tdb->map_ptr + tdb->map_size) - free((void *)p); + free((struct tdb_access_hdr *)p - 1); + else + tdb->direct_access--; +} + +int tdb_access_commit(struct tdb_context *tdb, void *p) +{ + int ret = 0; + + if (!tdb->map_ptr + || (char *)p < (char *)tdb->map_ptr + || (char *)p >= (char *)tdb->map_ptr + tdb->map_size) { + struct tdb_access_hdr *hdr; + + hdr = (struct tdb_access_hdr *)p - 1; + if (hdr->convert) + ret = tdb_write_convert(tdb, hdr->off, p, hdr->len); + else + ret = tdb_write(tdb, hdr->off, p, hdr->len); + free(hdr); + } else + tdb->direct_access--; + + return ret; } #if 0 @@ -606,11 +644,22 @@ int tdb_rec_write(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record * } #endif +static void *tdb_direct(struct tdb_context *tdb, tdb_off_t off, size_t len) +{ + if (unlikely(!tdb->map_ptr)) + return NULL; + + if (unlikely(tdb_oob(tdb, off + len, true) == -1)) + return NULL; + return (char *)tdb->map_ptr + off; +} + static const struct tdb_methods io_methods = { tdb_read, tdb_write, tdb_oob, tdb_expand_file, + tdb_direct, }; /*