From 17129a2f190d006f88fb3bc92aafb61f31e164d8 Mon Sep 17 00:00:00 2001 From: Jan 'Moskyt' Matejka Date: Mon, 16 Jul 2012 17:25:30 +0200 Subject: [PATCH] Fastbuf: fbmulti now uses transparently the underlying buffer --- ucw/fastbuf.h | 5 ++ ucw/fb-multi.c | 169 +++++++++++++++++++++++++++++++++++-------------- 2 files changed, 126 insertions(+), 48 deletions(-) diff --git a/ucw/fastbuf.h b/ucw/fastbuf.h index 40b60dca..0c0ea427 100644 --- a/ucw/fastbuf.h +++ b/ucw/fastbuf.h @@ -513,6 +513,11 @@ static inline void fbatomic_commit(struct fastbuf *b) * If you want to remove a fastbuf from the chain, just call @fbmulti_remove * where the second parameter is a pointer to the removed fastbuf. If you pass * NULL, all the underlying fastbufs are removed. + * + * When a fastbuf is removed from the chain, the overall position may change: + * If bstop pointed into it, after removal it points to the boundary of the + * previous and next fastbufs. Length of the removed fastbuf is subtracted from + * the overall offset of all the fastbufs after the removed fb in the chain. ***/ struct fastbuf *fbmulti_create(uns bufsize, ...) SENTINEL_CHECK; diff --git a/ucw/fb-multi.c b/ucw/fb-multi.c index 8071aa0c..e5835574 100644 --- a/ucw/fb-multi.c +++ b/ucw/fb-multi.c @@ -28,7 +28,7 @@ struct fb_multi { struct subbuf { cnode n; - ucw_off_t begin, end; + ucw_off_t begin, end, offset; int allow_close; struct fastbuf *fb; }; @@ -36,11 +36,25 @@ struct subbuf { static void fbmulti_subbuf_get_end(struct subbuf *s) { - if (s->fb->seek) - { - bseek(s->fb, 0, SEEK_END); - s->end = s->begin + btell(s->fb); - } + ASSERT(s->fb->seek); + bseek(s->fb, 0, SEEK_END); + s->end = s->begin + btell(s->fb); +} + +static void +fbmulti_get_ptrs(struct fastbuf *f) +{ + f->buffer = FB_MULTI(f)->cur->fb->buffer; + f->bptr = FB_MULTI(f)->cur->fb->bptr; + f->bstop = FB_MULTI(f)->cur->fb->bstop; + f->bufend = FB_MULTI(f)->cur->fb->bufend; + f->pos = FB_MULTI(f)->cur->begin + FB_MULTI(f)->cur->fb->pos - FB_MULTI(f)->cur->offset; +} + +static void +fbmulti_set_ptrs(struct fastbuf *f) +{ + FB_MULTI(f)->cur->fb->bptr = f->bptr; } static int @@ -49,34 +63,73 @@ fbmulti_subbuf_next(struct fastbuf *f) struct subbuf *next = clist_next(FB_MULTI(f)->subbufs, &FB_MULTI(f)->cur->n); if (next == NULL) return 0; - + + // Check the end of current buf if (f->seek) + { + FB_MULTI(f)->cur->fb->seek(FB_MULTI(f)->cur->fb, FB_MULTI(f)->cur->end - FB_MULTI(f)->cur->begin, SEEK_SET); + fbmulti_get_ptrs(f); + ASSERT(FB_MULTI(f)->cur->end == f->pos); + } + else + FB_MULTI(f)->cur->end = f->pos; + + // Set the beginning of the next buf + if (next->fb->seek) { bsetpos(next->fb, 0); - next->begin = FB_MULTI(f)->cur->end; + next->offset = 0; + } + else + { + ASSERT(!f->seek); + next->offset = btell(next->fb); } + next->begin = FB_MULTI(f)->cur->end; + + // Set the pointers FB_MULTI(f)->cur = next; + fbmulti_get_ptrs(f); + return 1; } static int -fbmulti_refill(struct fastbuf *f) +fbmulti_subbuf_prev(struct fastbuf *f) { - if (f->bufend == f->bstop) - f->bptr = f->bstop = f->buffer; + // Called only when seeking, assuming everything seekable + struct subbuf *prev = clist_prev(FB_MULTI(f)->subbufs, &FB_MULTI(f)->cur->n); + ASSERT(prev != NULL); - uns len = bread(FB_MULTI(f)->cur->fb, f->bstop, (f->bufend - f->bstop)); - f->bstop += len; - f->pos += len; + // Set pos to beginning, flush offset + bsetpos(prev->fb, 0); + prev->offset = 0; + + // Set the pointers + FB_MULTI(f)->cur = prev; + fbmulti_get_ptrs(f); + + return 1; +} + +static int +fbmulti_refill(struct fastbuf *f) +{ + fbmulti_set_ptrs(f); + // Refill the subbuf + uns len = FB_MULTI(f)->cur->fb->refill(FB_MULTI(f)->cur->fb); if (len) - return len; + { + fbmulti_get_ptrs(f); + return len; + } // Current buf returned EOF // Update the information on end of this buffer fbmulti_subbuf_get_end(FB_MULTI(f)->cur); - // Take the next one if exists + // Take the next one if exists and redo if (fbmulti_subbuf_next(f)) return fbmulti_refill(f); else @@ -86,56 +139,43 @@ fbmulti_refill(struct fastbuf *f) static void fbmulti_get_len(struct fastbuf *f) { + ucw_off_t pos = btell(f); ASSERT(f->seek); FB_MULTI(f)->len = 0; - + CLIST_FOR_EACH(struct subbuf *, n, *(FB_MULTI(f)->subbufs)) { n->begin = FB_MULTI(f)->len; fbmulti_subbuf_get_end(n); FB_MULTI(f)->len = n->end; } + f->seek(f, pos, SEEK_SET); // XXX: f->seek is needed here instead of bsetpos as the FE assumptions about f's state may be completely wrong. } static int fbmulti_seek(struct fastbuf *f, ucw_off_t pos, int whence) { + fbmulti_set_ptrs(f); switch(whence) { case SEEK_SET: - if (f->pos > pos) - { - FB_MULTI(f)->cur = clist_head(FB_MULTI(f)->subbufs); - FB_MULTI(f)->cur->begin = 0; - f->pos = 0; - return fbmulti_seek(f, pos, SEEK_SET); - } + if (pos > FB_MULTI(f)->len) + bthrow(f, "seek", "Seek out of range"); - do - { - fbmulti_subbuf_get_end(FB_MULTI(f)->cur); - if (pos < FB_MULTI(f)->cur->end) - break; + while (pos > FB_MULTI(f)->cur->end) // Moving forward + ASSERT(fbmulti_subbuf_next(f)); - if (!fbmulti_subbuf_next(f)) - { - if (pos == FB_MULTI(f)->cur->end) - break; - else - bthrow(f, "seek", "Seek out of range"); - } + while (pos < FB_MULTI(f)->cur->begin) // Moving backwards + ASSERT(fbmulti_subbuf_prev(f)); - } - while (1); + // Now cur is the right buffer. + FB_MULTI(f)->cur->fb->seek(FB_MULTI(f)->cur->fb, (pos - FB_MULTI(f)->cur->begin), SEEK_SET); - bsetpos(FB_MULTI(f)->cur->fb, (pos - FB_MULTI(f)->cur->begin)); - f->pos = pos; - f->bptr = f->bstop = f->buffer; + fbmulti_get_ptrs(f); return 1; break; case SEEK_END: - fbmulti_get_len(f); return fbmulti_seek(f, FB_MULTI(f)->len+pos, SEEK_SET); break; @@ -190,14 +230,21 @@ fbmulti_create(uns bufsize, ...) va_end(args); + fbmulti_update_capability(fb_out); + FB_MULTI(fb_out)->cur = clist_head(subbufs); + bsetpos(FB_MULTI(fb_out)->cur->fb, 0); + + fbmulti_get_ptrs(fb_out); + + // If seekable, get the length of each subbuf, the total length and boundaries + if (fb_out->seek) + { + fbmulti_get_len(fb_out); + } - fb_out->buffer = mp_alloc(mp, bufsize); - fb_out->bptr = fb_out->bstop = fb_out->buffer; - fb_out->bufend = fb_out->buffer + bufsize; fb_out->name = FB_MULTI_NAME; - fbmulti_update_capability(fb_out); fb_out->close = fbmulti_close; return fb_out; @@ -216,23 +263,49 @@ fbmulti_append(struct fastbuf *f, struct fastbuf *fb, int allow_close) void fbmulti_remove(struct fastbuf *f, struct fastbuf *fb) { + bflush(f); + uns pos = f->pos; if (fb) { CLIST_FOR_EACH(struct subbuf *, n, *(FB_MULTI(f)->subbufs)) if (fb == n->fb) { - // TODO: fix seek positions + // Move the pointers to another buffer if this one was the active. + if (FB_MULTI(f)->cur == n) + { + pos = n->begin; + if (!fbmulti_subbuf_next(f)) + { + struct subbuf *prev = clist_prev(FB_MULTI(f)->subbufs, &FB_MULTI(f)->cur->n); + if (prev == NULL) + goto cleanup; + + FB_MULTI(f)->cur = prev; + fbmulti_get_ptrs(f); + } + } + + if (n->end < pos) + pos -= (n->end - n->begin); + clist_remove(&(n->n)); fbmulti_update_capability(f); + fbmulti_get_len(f); + fbmulti_get_ptrs(f); return; - } + }; die("Given fastbuf %p not in given fbmulti %p.", fb, f); } else clist_init(FB_MULTI(f)->subbufs); +cleanup: + // The fbmulti is empty now, do some cleanup fbmulti_update_capability(f); + fbmulti_get_len(f); + f->buffer = f->bufend = f->bptr = f->bstop = NULL; + f->pos = 0; } static void fbmulti_flatten_internal(struct fastbuf *f, clist *c, int allow_close) -- 2.39.2