]> mj.ucw.cz Git - libucw.git/commitdiff
A better implementation of overwritable buffers.
authorMartin Mares <mj@ucw.cz>
Mon, 28 Jun 2004 15:06:40 +0000 (15:06 +0000)
committerMartin Mares <mj@ucw.cz>
Mon, 28 Jun 2004 15:06:40 +0000 (15:06 +0000)
lib/bucket.c
lib/fastbuf.h
lib/fb-buffer.c
lib/fb-file.c
lib/fb-limfd.c
lib/fb-mem.c
lib/fb-mmap.c
lib/fb-temp.c

index 4a5533cfa6ef19e485e8a50d6d43429799b540f1..fa4f5dedd8a84dffd4394c110dd7dd234f90864a 100644 (file)
@@ -131,7 +131,6 @@ obuck_unlock(void)
 
 struct fb_bucket {
   struct fastbuf fb;
-  int can_overwrite;
   sh_off_t start_pos;
   uns bucket_size;
   byte buffer[0];
@@ -302,21 +301,6 @@ obuck_find_next(struct obuck_header *hdrp, int full)
     }
 }
 
-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)
 {
@@ -333,7 +317,8 @@ 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++;
@@ -373,9 +358,9 @@ obuck_create(u32 type)
   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;
index 9e974cf54ea4539b7c6d9f29d19b970f42c17246..45ce06916f0c388831a57d3293104a810a684c61 100644 (file)
  *     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 {
@@ -64,14 +75,15 @@ 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 */
 
@@ -101,16 +113,6 @@ fbbuf_count_written(struct fastbuf *f)
 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 */
 
@@ -358,6 +360,13 @@ bdirect_read_commit(struct fastbuf *f, byte *pos)
   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)
 {
index 2f52665f1bfbb879d69b9adaec550499b99a09e7..5a248efdf85ee1c332c54a16a6942bea7ea73ef5 100644 (file)
 #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)
 {
@@ -41,7 +28,8 @@ fbbuf_init_read(struct fastbuf *f, byte *buf, uns size)
   f->spout = NULL;
   f->seek = NULL;
   f->close = NULL;
-  f->config = fbbuf_config;
+  f->config = NULL;
+  f->can_overwrite_buffer = 1;
 }
 
 static void
@@ -61,5 +49,6 @@ fbbuf_init_write(struct fastbuf *f, byte *buf, uns size)
   f->spout = fbbuf_spout;
   f->seek = NULL;
   f->close = NULL;
-  f->config = fbbuf_config;
+  f->config = NULL;
+  f->can_overwrite_buffer = 0;
 }
index c33698e9d0d815738ef39eb0143dde933832549a..169f25e1a027ac858600b3824a7015a12994fbc7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     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
@@ -21,17 +21,17 @@ struct fb_file {
   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;
@@ -41,7 +41,7 @@ static void
 bfd_spout(struct fastbuf *f)
 {
   int l = f->bptr - f->buffer;
-  char *c = f->buffer;
+  byte *c = f->buffer;
 
   f->pos += l;
   while (l)
@@ -52,7 +52,7 @@ bfd_spout(struct fastbuf *f)
       l -= z;
       c += z;
     }
-  f->bptr = f->buffer;
+  f->bptr = f->buffer = FB_BUFFER(f);
 }
 
 static void
@@ -91,11 +91,6 @@ bfd_config(struct fastbuf *f, uns item, int value)
     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;
     }
@@ -109,7 +104,7 @@ bfdopen_internal(int fd, uns buflen, byte *name)
   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;
@@ -120,41 +115,41 @@ bfdopen_internal(int fd, uns buflen, byte *name)
   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;
 }
index 7e07e328f94a0d6de2bac582d9641fb412d86511..745445a2bad9f6d35a982465d59d2332355ba51b 100644 (file)
@@ -18,7 +18,6 @@ struct fb_limfd {
   struct fastbuf fb;
   int fd;                              /* File descriptor */
   int limit;
-  int can_overwrite;
 };
 #define FB_LIMFD(f) ((struct fb_limfd *)(f)->is_fastbuf)
 
@@ -41,21 +40,6 @@ bfl_close(struct fastbuf *f)
   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)
 {
@@ -71,8 +55,7 @@ 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;
 }
 
index 82fe251e9ec28413e155e7149c85bccac78873fd..89390f1b6999527fcb3ac86266f6edbd05d0855c 100644 (file)
@@ -30,7 +30,6 @@ struct fb_mem {
   struct fastbuf fb;
   struct memstream *stream;
   struct msblock *block;
-  int can_overwrite;
 };
 #define FB_MEM(f) ((struct fb_mem *)(f)->is_fastbuf)
 
@@ -151,21 +150,6 @@ fbmem_close(struct fastbuf *f)
   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)
 {
@@ -179,7 +163,6 @@ fbmem_create(unsigned blocksize)
   f->name = "<fbmem-write>";
   f->spout = fbmem_spout;
   f->close = fbmem_close;
-  f->config = fbmem_config;
   return f;
 }
 
@@ -197,8 +180,7 @@ fbmem_clone_read(struct fastbuf *b)
   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;
 }
 
index bbd3a11eacc6e1017bed271b867f933160feefa9..b6f827751fcf7f8b5152f8694806437c7074c5fb 100644 (file)
@@ -160,8 +160,6 @@ bfmm_config(struct fastbuf *f, uns item, int value)
     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;
     }
index a537dd934f7b7541068b006014f0c559bedf6f79..f7b14483e172bca0b172e5c1b5373093a50e45e6 100644 (file)
@@ -28,14 +28,14 @@ static void CONSTRUCTOR temp_init_config(void)
 }
 
 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;
 }