#include "lib/bucket.h"
#include "lib/fastbuf.h"
#include "lib/lfs.h"
+#include "lib/conf.h"
#include <string.h>
#include <fcntl.h>
static struct fastbuf *obuck_fb;
static struct obuck_header obuck_hdr;
static sh_off_t bucket_start;
-static char *obuck_name = "db/objects"; /* FIXME */
+
+/*** Configuration ***/
+
+byte *obuck_name = "not/configured";
+static int obuck_io_buflen = 65536;
+
+static struct cfitem obuck_config[] = {
+ { "Buckets", CT_SECTION, NULL },
+ { "BucketFile", CT_STRING, &obuck_name },
+ { "BufSize", CT_INT, &obuck_io_buflen },
+ { NULL, CT_STOP, NULL }
+};
+
+static void CONSTRUCTOR obuck_init_config(void)
+{
+ cf_register(obuck_config);
+}
/*** Internal operations ***/
static void
obuck_broken(char *msg)
{
- die("Object pool corrupted: %s (pos=%Lx)", msg, (long long) bucket_start); /* FIXME */
+ die("Object pool corrupted: %s (pos=%Lx)", msg, (long long) bucket_start);
+}
+
+/*
+ * Unfortunately we cannot use flock() here since it happily permits
+ * locking a shared fd (e.g., after fork()) multiple times. The fcntl
+ * locks are very ugly and they don't support 64-bit offsets, but we
+ * can work around the problem by always locking the first header
+ * in the file.
+ */
+
+static inline void
+obuck_do_lock(int type)
+{
+ struct flock fl;
+
+ fl.l_type = type;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = sizeof(struct obuck_header);
+ if (fcntl(obuck_fd, F_SETLKW, &fl) < 0)
+ die("fcntl lock: %m");
}
static inline void
obuck_lock_read(void)
{
- flock(obuck_fd, LOCK_SH);
+ obuck_do_lock(F_RDLCK);
}
static inline void
obuck_lock_write(void)
{
- flock(obuck_fd, LOCK_EX);
+ obuck_do_lock(F_WRLCK);
}
static inline void
obuck_unlock(void)
{
- flock(obuck_fd, LOCK_UN);
+ obuck_do_lock(F_UNLCK);
}
/*** FastIO emulation ***/
if (!limit)
return 0;
- l = pread(f->fd, f->buffer, size, f->fdpos);
+ l = sh_pread(f->fd, f->buffer, size, f->fdpos);
if (l < 0)
die("Error reading bucket: %m");
if ((unsigned) l != size)
while (l)
{
- int z = pwrite(f->fd, c, l, f->fdpos);
+ int z = sh_pwrite(f->fd, c, l, f->fdpos);
if (z <= 0)
die("Error writing bucket: %m");
f->fdpos += z;
obuck_init(int writeable)
{
struct fastbuf *b;
- int buflen = 65536;
sh_off_t size;
- obuck_fd = open(obuck_name, (writeable ? O_RDWR | O_CREAT : O_RDONLY), 0666);
- obuck_fb = b = xmalloc(sizeof(struct fastbuf) + buflen + OBUCK_ALIGN + 4);
- bzero(b, sizeof(struct fastbuf));
- b->buflen = buflen;
+ obuck_fd = sh_open(obuck_name, (writeable ? O_RDWR | O_CREAT : O_RDONLY), 0666);
+ if (obuck_fd < 0)
+ die("Unable to open bucket file %s: %m", obuck_name);
+ obuck_fb = b = xmalloc_zero(sizeof(struct fastbuf) + obuck_io_buflen + OBUCK_ALIGN + 4);
+ b->buflen = obuck_io_buflen;
b->buffer = (char *)(b+1);
b->bptr = b->bstop = b->buffer;
- b->bufend = b->buffer + buflen;
+ b->bufend = b->buffer + obuck_io_buflen;
b->name = "bucket";
b->fd = obuck_fd;
b->refill = obuck_fb_refill;
/* If the bucket pool is not empty, check consistency of its end */
u32 check;
bucket_start = size - 4; /* for error reporting */
- if (pread(obuck_fd, &check, 4, size-4) != 4 ||
+ if (sh_pread(obuck_fd, &check, 4, size-4) != 4 ||
check != OBUCK_TRAILER)
obuck_broken("Missing trailer of last object");
}
bclose(obuck_fb);
}
-void /* FIXME: Call somewhere :) */
+void
obuck_sync(void)
{
bflush(obuck_fb);
{
struct fastbuf *b = obuck_fb;
- bucket_start = ((sh_off_t) oid) << OBUCK_SHIFT;
+ bucket_start = obuck_get_pos(oid);
bflush(b);
- if (pread(obuck_fd, &obuck_hdr, sizeof(obuck_hdr), bucket_start) != sizeof(obuck_hdr))
+ if (sh_pread(obuck_fd, &obuck_hdr, sizeof(obuck_hdr), bucket_start) != sizeof(obuck_hdr))
obuck_broken("Short header read");
b->fdpos = bucket_start + sizeof(obuck_hdr);
if (obuck_hdr.magic != OBUCK_MAGIC)
{
oid_t oid = hdrp->oid;
+ ASSERT(oid < OBUCK_OID_FIRST_SPECIAL);
obuck_lock_read();
obuck_get(oid);
obuck_unlock();
}
int
-obuck_find_first(struct obuck_header *hdrp)
+obuck_find_first(struct obuck_header *hdrp, int full)
{
bucket_start = 0;
obuck_hdr.magic = 0;
- return obuck_find_next(hdrp);
+ return obuck_find_next(hdrp, full);
}
int
-obuck_find_next(struct obuck_header *hdrp)
+obuck_find_next(struct obuck_header *hdrp, int full)
{
int c;
struct fastbuf *b = obuck_fb;
4 + OBUCK_ALIGN - 1) & ~((sh_off_t)(OBUCK_ALIGN - 1));
bflush(b);
obuck_lock_read();
- c = pread(obuck_fd, &obuck_hdr, sizeof(obuck_hdr), bucket_start);
+ c = sh_pread(obuck_fd, &obuck_hdr, sizeof(obuck_hdr), bucket_start);
obuck_unlock();
if (!c)
return 0;
b->fdpos = bucket_start + sizeof(obuck_hdr);
if (obuck_hdr.magic != OBUCK_MAGIC)
obuck_broken("Missing magic number");
- if (obuck_hdr.oid != OBUCK_OID_DELETED)
+ if (obuck_hdr.oid != OBUCK_OID_DELETED || full)
{
memcpy(hdrp, &obuck_hdr, sizeof(obuck_hdr));
return 1;
bucket_start = sh_seek(obuck_fd, 0, SEEK_END);
if (bucket_start & (OBUCK_ALIGN - 1))
obuck_broken("Misaligned file");
- obuck_hdr.magic = 0;
+ obuck_hdr.magic = OBUCK_INCOMPLETE_MAGIC;
obuck_hdr.oid = bucket_start >> OBUCK_SHIFT;
obuck_hdr.length = obuck_hdr.orig_length = 0;
obuck_fb->fdpos = obuck_fb->pos = bucket_start;
bputl(obuck_fb, OBUCK_TRAILER);
bflush(obuck_fb);
ASSERT(!(btell(obuck_fb) & (OBUCK_ALIGN - 1)));
- pwrite(obuck_fd, &obuck_hdr, sizeof(obuck_hdr), bucket_start);
+ sh_pwrite(obuck_fd, &obuck_hdr, sizeof(obuck_hdr), bucket_start);
obuck_unlock();
memcpy(hdrp, &obuck_hdr, sizeof(obuck_hdr));
}
obuck_lock_write();
obuck_get(oid);
obuck_hdr.oid = OBUCK_OID_DELETED;
- pwrite(obuck_fd, &obuck_hdr, sizeof(obuck_hdr), bucket_start);
+ sh_pwrite(obuck_fd, &obuck_hdr, sizeof(obuck_hdr), bucket_start);
obuck_unlock();
}
#ifdef TEST
-#define COUNT 100
+#define COUNT 5000
#define MAXLEN 10000
#define KILLPERC 13
#define LEN(i) ((259309*(i))%MAXLEN)
-int main(void)
+int main(int argc, char **argv)
{
int ids[COUNT];
unsigned int i, j, cnt;
struct obuck_header h;
struct fastbuf *b;
+
+ log_init(NULL);
+ if (cf_getopt(argc, argv, CF_SHORT_OPTS, CF_NO_LONG_OPTS, NULL) >= 0 ||
+ optind < argc)
+ die("This program has no command-line arguments.");
+
unlink(obuck_name);
obuck_init(1);
for(j=0; j<COUNT; j++)
die("EOF mismatch");
obuck_fetch_end(b);
}
- if (obuck_find_first(&h))
+ if (obuck_find_first(&h, 0))
do
{
printf("<<< %08x\t%d\n", h.oid, h.orig_length);
cnt--;
}
- while (obuck_find_next(&h));
+ while (obuck_find_next(&h, 0));
if (cnt)
die("Walk mismatch");
obuck_cleanup();