struct fb_bucket {
struct fastbuf fb;
- int can_overwrite;
sh_off_t start_pos;
uns bucket_size;
byte buffer[0];
}
}
-static int
-obuck_bconfig(struct fastbuf *f, uns item, int value)
-{
- switch (item)
- {
- case BCONFIG_CAN_OVERWRITE: ;
- int old_value = FB_BUCKET(f)->can_overwrite;
- if (value >= 0 && value <= 2)
- FB_BUCKET(f)->can_overwrite = value;
- return old_value;
- default:
- return -1;
- }
-}
-
struct fastbuf *
obuck_fetch(void)
{
b->spout = NULL;
b->seek = NULL;
b->close = obuck_fb_close;
- b->config = obuck_bconfig;
+ b->config = NULL;
+ b->can_overwrite_buffer = 2;
FB_BUCKET(b)->start_pos = bucket_find_pos;
FB_BUCKET(b)->bucket_size = obuck_hdr.length;
obuck_fb_count++;
b->seek = NULL;
b->close = NULL;
b->config = NULL;
+ b->can_overwrite_buffer = 0;
FB_BUCKET(b)->start_pos = start;
FB_BUCKET(b)->bucket_size = 0;
- FB_BUCKET(b)->can_overwrite = 2;
bwrite(b, &obuck_create_hdr, sizeof(obuck_create_hdr));
return b;
* as after the data you've read.
* - The spout/refill hooks can change not only bptr and bstop, but also
* the location of the buffer; fb-mem.c takes advantage of it.
+ * - In some cases, the user of the bdirect interface can be allowed to modify
+ * the data in the buffer to avoid unnecessary copying. If the back-end
+ * allows such modifications, it can set can_overwrite_buffer accordingly:
+ * * 0 if no modification is allowed,
+ * * 1 if the user can modify the buffer on the condition that
+ * the modifications will be undone before calling the next
+ * fastbuf operation
+ * * 2 if the user is allowed to overwrite the data in the buffer
+ * if bdirect_read_commit_modified() is called afterwards.
+ * In this case, the back-end must be prepared for trimming
+ * of the buffer which is done by the commit function.
*/
struct fastbuf {
void (*seek)(struct fastbuf *, sh_off_t, int); /* Slow path for bseek(), buffer already flushed */
void (*close)(struct fastbuf *); /* Close the stream */
int (*config)(struct fastbuf *, uns, int); /* Configure the stream */
+ int can_overwrite_buffer; /* Can the buffer be altered? (see discussion above) 0=never, 1=temporarily, 2=permanently */
};
/* FastIO on standard files (specify buffer size 0 to enable mmaping) */
-struct fastbuf *bopen(byte *name, uns mode, uns buffer);
-struct fastbuf *bopen_tmp(uns buffer);
-struct fastbuf *bfdopen(int fd, uns buffer);
-struct fastbuf *bfdopen_shared(int fd, uns buffer);
+struct fastbuf *bopen(byte *name, uns mode, uns buflen);
+struct fastbuf *bopen_tmp(uns buflen);
+struct fastbuf *bfdopen(int fd, uns buflen);
+struct fastbuf *bfdopen_shared(int fd, uns buflen);
/* FastIO on in-memory streams */
int bconfig(struct fastbuf *f, uns type, int data);
#define BCONFIG_IS_TEMP_FILE 0
-#define BCONFIG_CAN_OVERWRITE 1
- /* Specifies whether the caller is allowed to perform the following optimized
- * 0-copy write operation:
- * - get the buffer by bdirect_read_prepare()
- * - modify the buffer, e.g. by putting \0's inside
- * - call bflush() to let the fastbuf know
- * Values:
- * 0: read-only memory
- * 1: you can write into read-write memory, if you restore the original value
- * 2: you can rewrite the original content */
/* Universal functions working on all fastbuf's */
f->bptr = pos;
}
+static inline void
+bdirect_read_commit_modified(struct fastbuf *f, byte *pos)
+{
+ f->bptr = pos;
+ f->buffer = pos; /* Avoid seeking backwards in the buffer */
+}
+
static inline uns
bdirect_write_prepare(struct fastbuf *f, byte **buf)
{
#include "lib/lib.h"
#include "lib/fastbuf.h"
-static int
-fbbuf_config(struct fastbuf *f UNUSED, uns item, int value UNUSED)
-{
- switch (item)
- {
- case BCONFIG_CAN_OVERWRITE:
- // XXX: should we enable changing the value?
- return 1;
- default:
- return -1;
- }
-}
-
static int
fbbuf_refill(struct fastbuf *f UNUSED)
{
f->spout = NULL;
f->seek = NULL;
f->close = NULL;
- f->config = fbbuf_config;
+ f->config = NULL;
+ f->can_overwrite_buffer = 1;
}
static void
f->spout = fbbuf_spout;
f->seek = NULL;
f->close = NULL;
- f->config = fbbuf_config;
+ f->config = NULL;
+ f->can_overwrite_buffer = 0;
}
/*
* Sherlock Library -- Fast Buffered I/O on Files
*
- * (c) 1997--2002 Martin Mares <mj@ucw.cz>
+ * (c) 1997--2004 Martin Mares <mj@ucw.cz>
* (c) 2004 Robert Spalek <robert@ucw.cz>
*
* This software may be freely distributed and used according to the terms
struct fastbuf fb;
int fd; /* File descriptor, -1 if not a real file */
int is_temp_file; /* 0=normal file, 1=temporary file, delete on close, -1=shared FD */
- int can_overwrite;
};
#define FB_FILE(f) ((struct fb_file *)(f)->is_fastbuf)
+#define FB_BUFFER(f) (byte *)(FB_FILE(f) + 1)
static int
bfd_refill(struct fastbuf *f)
{
+ f->bptr = f->buffer = FB_BUFFER(f);
int l = read(FB_FILE(f)->fd, f->buffer, f->bufend-f->buffer);
if (l < 0)
die("Error reading %s: %m", f->name);
- f->bptr = f->buffer;
f->bstop = f->buffer + l;
f->pos += l;
return l;
bfd_spout(struct fastbuf *f)
{
int l = f->bptr - f->buffer;
- char *c = f->buffer;
+ byte *c = f->buffer;
f->pos += l;
while (l)
l -= z;
c += z;
}
- f->bptr = f->buffer;
+ f->bptr = f->buffer = FB_BUFFER(f);
}
static void
case BCONFIG_IS_TEMP_FILE:
FB_FILE(f)->is_temp_file = value;
return 0;
- case BCONFIG_CAN_OVERWRITE: ;
- int old_value = FB_FILE(f)->can_overwrite;
- if (value >= 0 && value <= 2)
- FB_FILE(f)->can_overwrite = value;
- return old_value;
default:
return -1;
}
struct fastbuf *f = &F->fb;
bzero(F, sizeof(*F));
- f->buffer = (char *)(F+1);
+ f->buffer = (byte *)(F+1);
f->bptr = f->bstop = f->buffer;
f->bufend = f->buffer + buflen;
f->name = f->bufend;
f->seek = bfd_seek;
f->close = bfd_close;
f->config = bfd_config;
- F->can_overwrite = 2;
+ f->can_overwrite_buffer = 2;
return f;
}
struct fastbuf *
-bopen(byte *name, uns mode, uns buffer)
+bopen(byte *name, uns mode, uns buflen)
{
struct fastbuf *b;
int fd;
- if (!buffer)
+ if (!buflen)
return bopen_mm(name, mode);
fd = sh_open(name, mode, 0666);
if (fd < 0)
die("Unable to %s file %s: %m",
(mode & O_CREAT) ? "create" : "open", name);
- b = bfdopen_internal(fd, buffer, name);
+ b = bfdopen_internal(fd, buflen, name);
if (mode & O_APPEND)
bfd_seek(b, 0, SEEK_END);
return b;
}
struct fastbuf *
-bfdopen(int fd, uns buffer)
+bfdopen(int fd, uns buflen)
{
byte x[32];
sprintf(x, "fd%d", fd);
- return bfdopen_internal(fd, buffer, x);
+ return bfdopen_internal(fd, buflen, x);
}
struct fastbuf *
-bfdopen_shared(int fd, uns buffer)
+bfdopen_shared(int fd, uns buflen)
{
- struct fastbuf *f = bfdopen(fd, buffer);
+ struct fastbuf *f = bfdopen(fd, buflen);
FB_FILE(f)->is_temp_file = -1;
return f;
}
struct fastbuf fb;
int fd; /* File descriptor */
int limit;
- int can_overwrite;
};
#define FB_LIMFD(f) ((struct fb_limfd *)(f)->is_fastbuf)
xfree(f);
}
-static int
-bfl_config(struct fastbuf *f, uns item, int value)
-{
- switch (item)
- {
- case BCONFIG_CAN_OVERWRITE: ;
- int old_value = FB_LIMFD(f)->can_overwrite;
- if (value >= 0 && value <= 2)
- FB_LIMFD(f)->can_overwrite = value;
- return old_value;
- default:
- return -1;
- }
-}
-
struct fastbuf *
bopen_limited_fd(int fd, uns buflen, uns limit)
{
F->limit = limit;
f->refill = bfl_refill;
f->close = bfl_close;
- f->config = bfl_config;
- F->can_overwrite = 2;
+ f->can_overwrite_buffer = 2;
return f;
}
struct fastbuf fb;
struct memstream *stream;
struct msblock *block;
- int can_overwrite;
};
#define FB_MEM(f) ((struct fb_mem *)(f)->is_fastbuf)
xfree(f);
}
-static int
-fbmem_config(struct fastbuf *f, uns item, int value)
-{
- switch (item)
- {
- case BCONFIG_CAN_OVERWRITE: ;
- int old_value = FB_MEM(f)->can_overwrite;
- if (value >= 0 && value <= 1)
- FB_MEM(f)->can_overwrite = value;
- return old_value;
- default:
- return -1;
- }
-}
-
struct fastbuf *
fbmem_create(unsigned blocksize)
{
f->name = "<fbmem-write>";
f->spout = fbmem_spout;
f->close = fbmem_close;
- f->config = fbmem_config;
return f;
}
f->refill = fbmem_refill;
f->seek = fbmem_seek;
f->close = fbmem_close;
- f->config = fbmem_config;
- FB_MEM(f)->can_overwrite = 1;
+ f->can_overwrite_buffer = 1;
return f;
}
case BCONFIG_IS_TEMP_FILE:
FB_MMAP(f)->is_temp_file = value;
return 0;
- case BCONFIG_CAN_OVERWRITE:
- return 0; /* cannot use 1, because the pages would become dirty */
default:
return -1;
}
}
struct fastbuf *
-bopen_tmp(uns bufsize)
+bopen_tmp(uns buflen)
{
byte buf[256];
struct fastbuf *f;
static uns temp_counter;
sprintf(buf, temp_template, (int) getpid(), temp_counter++);
- f = bopen(buf, O_RDWR | O_CREAT | O_TRUNC, bufsize);
+ f = bopen(buf, O_RDWR | O_CREAT | O_TRUNC, buflen);
bconfig(f, BCONFIG_IS_TEMP_FILE, 1);
return f;
}