+static bool need_buffer_pool_merge(struct btr_node *btrn)
+{
+ struct btr_buffer_reference *br = get_first_input_br(btrn);
+
+ if (!br)
+ return false;
+ if (br->wrap_count != 0)
+ return true;
+ if (br->btrb->pool)
+ return true;
+ return false;
+}
+
+static void merge_input_pool(struct btr_node *btrn, size_t dest_size)
+{
+ struct btr_buffer_reference *br, *wbr = NULL;
+ int num_refs; /* including wrap buffer */
+ char *buf, *buf1 = NULL, *buf2 = NULL;
+ size_t sz, sz1 = 0, sz2 = 0, wsz;
+
+ br = get_first_input_br(btrn);
+ if (!br || br_available_bytes(br) >= dest_size)
+ return;
+ num_refs = 0;
+ FOR_EACH_BUFFER_REF(br, btrn) {
+ num_refs++;
+ sz = btr_get_buffer_by_reference(br, &buf);
+ if (sz == 0)
+ break;
+ if (br->wrap_count != 0) {
+ assert(!wbr);
+ assert(num_refs == 1);
+ wbr = br;
+ if (sz >= dest_size)
+ return;
+ continue;
+ }
+ if (!buf1) {
+ buf1 = buf;
+ sz1 = sz;
+ goto next;
+ }
+ if (buf1 + sz1 == buf) {
+ sz1 += sz;
+ goto next;
+ }
+ if (!buf2) {
+ buf2 = buf;
+ sz2 = sz;
+ goto next;
+ }
+ assert(buf2 + sz2 == buf);
+ sz2 += sz;
+next:
+ if (sz1 + sz2 >= dest_size)
+ break;
+ }
+ if (!buf2) /* nothing to do */
+ return;
+ assert(buf1 && sz2 > 0);
+ /*
+ * If the second buffer is large, we only take the first part of it to
+ * avoid having to memcpy() huge buffers.
+ */
+ sz2 = PARA_MIN(sz2, (size_t)(64 * 1024));
+ if (!wbr) {
+ /* Make a new wrap buffer combining buf1 and buf2. */
+ sz = sz1 + sz2;
+ buf = para_malloc(sz);
+ PARA_DEBUG_LOG("merging input buffers: (%p:%zu, %p:%zu) -> %p:%zu\n",
+ buf1, sz1, buf2, sz2, buf, sz);
+ memcpy(buf, buf1, sz1);
+ memcpy(buf + sz1, buf2, sz2);
+ br = para_calloc(sizeof(*br));
+ br->btrb = new_btrb(buf, sz);
+ br->btrb->refcount = 1;
+ br->consumed = 0;
+ /* This is a wrap buffer */
+ br->wrap_count = sz1;
+ para_list_add(&br->node, &btrn->input_queue);
+ return;
+ }
+ PARA_DEBUG_LOG("increasing wrap buffer, sz1: %zu, sz2: %zu\n", sz1, sz2);
+ /*
+ * We already have a wrap buffer, but it is too small. It might be
+ * partially used.
+ */
+ wsz = br_available_bytes(wbr);
+ if (wbr->wrap_count == sz1 && wbr->btrb->size >= sz1 + sz2) /* nothing we can do about it */
+ return;
+ sz = sz1 + sz2 - wbr->btrb->size; /* amount of new data */
+ wbr->btrb->size += sz;
+ wbr->btrb->buf = para_realloc(wbr->btrb->buf, wbr->btrb->size);
+ /* copy the new data to the end of the reallocated buffer */
+ assert(sz2 >= sz);
+ memcpy(wbr->btrb->buf + wbr->btrb->size - sz, buf2 + sz2 - sz, sz);
+}
+