* Sebastian Hammer, Adam Dickmeiss
*
* $Log: isamc.c,v $
- * Revision 1.2 1996-10-29 16:44:56 adam
+ * Revision 1.3 1996-11-01 08:59:14 adam
+ * First version of isc_merge that supports update/delete.
+ *
+ * Revision 1.2 1996/10/29 16:44:56 adam
* Work on isc_merge.
*
* Revision 1.1 1996/10/29 13:40:48 adam
*
*/
+/*
+ * TODO:
+ * small/empty blocks aren't handled in isc_merge.
+ * delete/update optimization of same key.
+ * implementation of isc_numkeys
+ */
#include <stdlib.h>
#include <assert.h>
#include <string.h>
logf (LOG_LOG, "isc: max_buf_size %d", max_buf_size);
assert (is->no_files > 0);
- is->files = xmalloc (sizeof(*is->files)*i);
- is->r_buf = xmalloc (max_buf_size+128);
+ is->files = xmalloc (sizeof(*is->files)*is->no_files);
+ if (writeflag)
+ is->merge_buf = xmalloc (max_buf_size+128);
+ else
+ is->merge_buf = NULL;
for (i = 0; i<is->no_files; i++)
{
char fname[512];
is->files[i].head.lastblock = 1;
is->files[i].head.freelist = 0;
}
+ is->files[i].no_writes = 0;
+ is->files[i].no_reads = 0;
+ is->files[i].no_skip_writes = 0;
+ is->files[i].no_allocated = 0;
+ is->files[i].no_released = 0;
+ is->files[i].no_remap = 0;
}
return is;
}
{
int i;
+ if (is->method->debug)
+ logf (LOG_LOG, "isc: writes reads skipped alloc released remap");
for (i = 0; i<is->no_files; i++)
- if (is->files[i].bf)
- {
- if (is->files[i].head_is_dirty)
- bf_write (is->files[i].bf, 0, 0, sizeof(ISAMC_head),
- &is->files[i].head);
- bf_close (is->files[i].bf);
- }
+ {
+ assert (is->files[i].bf);
+ if (is->files[i].head_is_dirty)
+ bf_write (is->files[i].bf, 0, 0, sizeof(ISAMC_head),
+ &is->files[i].head);
+ if (is->method->debug)
+ logf (LOG_LOG, "isc:%8d%8d%8d%8d%8d%8d",
+ is->files[i].no_writes,
+ is->files[i].no_reads,
+ is->files[i].no_skip_writes,
+ is->files[i].no_allocated,
+ is->files[i].no_released,
+ is->files[i].no_remap);
+ bf_close (is->files[i].bf);
+ }
xfree (is->files);
- xfree (is->r_buf);
+ xfree (is->merge_buf);
xfree (is);
return 0;
}
int isc_read_block (ISAMC is, int cat, int pos, char *dst)
{
- if (is->method->debug > 1)
+ ++(is->files[cat].no_reads);
+ if (is->method->debug > 2)
logf (LOG_LOG, "isc: read_block %d %d", cat, pos);
return bf_read (is->files[cat].bf, pos, 0, 0, dst);
}
int isc_write_block (ISAMC is, int cat, int pos, char *src)
{
- if (is->method->debug > 1)
+ ++(is->files[cat].no_writes);
+ if (is->method->debug > 2)
logf (LOG_LOG, "isc: write_block %d %d", cat, pos);
return bf_write (is->files[cat].bf, pos, 0, 0, src);
}
{
int xoffset = offset + 2*sizeof(int);
if (is->method->debug > 2)
- logf (LOG_LOG, "isc: write_dblock. offset=%d nextpos=%d",
+ logf (LOG_LOG, "isc: write_dblock. size=%d nextpos=%d",
offset, nextpos);
memcpy (src - sizeof(int)*2, &nextpos, sizeof(int));
memcpy (src - sizeof(int), &xoffset, sizeof(int));
char buf[sizeof(int)];
is->files[cat].head_is_dirty = 1;
+ (is->files[cat].no_allocated)++;
if ((block = is->files[cat].head.freelist))
{
bf_read (is->files[cat].bf, block, 0, sizeof(int), buf);
else
block = (is->files[cat].head.lastblock)++;
if (is->method->debug > 2)
- logf (LOG_LOG, "isc: alloc_block in cat %d -> %d", cat, block);
+ logf (LOG_LOG, "isc: alloc_block in cat %d: %d", cat, block);
return block;
}
{
char buf[sizeof(int)];
+ (is->files[cat].no_released)++;
is->files[cat].head_is_dirty = 1;
memcpy (buf, &is->files[cat].head.freelist, sizeof(int));
is->files[cat].head.freelist = pos;
bf_write (is->files[cat].bf, pos, 0, sizeof(int), buf);
+ if (is->method->debug > 2)
+ logf (LOG_LOG, "isc: release_block in cat %d: %d", cat, pos);
}
-static void isc_flush_blocks (ISAMC is, int *r_ptr, int r_ptri, char *r_buf,
- int *nextpos, int *firstpos, int cat, int last)
-{
- int i;
-
- for (i = 1; i<r_ptri; i++)
- {
- int pos;
- if (*nextpos)
- pos = *nextpos;
- else
- pos = isc_alloc_block (is, cat);
- if (!*firstpos)
- *firstpos = pos;
- if (last && i == r_ptri-1)
- *nextpos = 0;
- else
- *nextpos = isc_alloc_block (is, cat);
- isc_write_dblock (is, cat, pos, r_buf + r_ptr[i-1], *nextpos,
- r_ptr[i] - r_ptr[i-1]);
- }
-}
-
-
-ISAMC_P isc_merge_first (ISAMC is, ISAMC_I data)
-{
- char i_item[128], *i_item_ptr;
- int i_more, i_mode, i;
-
- int firstpos = 0;
- int nextpos = 0;
- int cat = 0;
- char r_item_buf[128];
- int r_offset = 0;
- int r_ptr[100];
- int r_ptri = 0;
- void *r_clientData = (*is->method->code_start)(ISAMC_ENCODE);
- char *r_buf = is->r_buf + ISAMC_BLOCK_OFFSET;
-
- /* read first item from i */
- i_item_ptr = i_item;
- i_more = (*data->read_item)(data->clientData, &i_item_ptr, &i_mode);
- if (i_more)
- r_ptr[r_ptri++] = 0;
- while (i_more)
- {
- char *r_item = r_item_buf;
-
- memcpy (r_item, i_item, i_item_ptr - i_item);
-
- if (r_item) /* insert resulting item? */
- {
- char *r_out_ptr = r_buf + r_offset;
- int new_offset;
- int border = r_ptr[r_ptri-1] + is->method->filecat[cat].ifill
- -ISAMC_BLOCK_OFFSET;
-
- (*is->method->code_item)(ISAMC_ENCODE, r_clientData,
- &r_out_ptr, &r_item);
- new_offset = r_out_ptr - r_buf;
-
- if (border >= r_offset && border < new_offset)
- {
- /* Initial fill of current block category reached...
- Save offset in r_ptr
- */
- r_ptr[r_ptri++] = r_offset;
- if (cat == is->max_cat)
- {
- /* We are dealing with block of max size. Block(s)
- will be flushed. Note: the block(s) are surely not
- the last one(s).
- */
- if (is->method->debug > 1)
- logf (LOG_LOG, "isc: flush %d sections", r_ptri-1);
- isc_flush_blocks (is, r_ptr, r_ptri, r_buf,
- &nextpos, &firstpos, cat, 0);
- r_ptri = 0;
- r_ptr[r_ptri++] = 0;
- memcpy (r_buf, r_buf + r_offset, new_offset - r_offset);
- new_offset = (new_offset - r_offset);
- }
- }
- r_offset = new_offset;
- if (cat < is->max_cat &&
- r_ptri>is->method->filecat[cat].mblocks)
- {
- /* Max number blocks in current category reached ->
- must switch to next category (with larger block size)
- */
- int j = 1;
- cat++;
- /* r_ptr[0] = r_ptr[0] = 0 true anyway.. */
- for (i = 2; i < r_ptri; i++)
- {
- border = is->method->filecat[cat].ifill -
- ISAMC_BLOCK_OFFSET + r_ptr[j-1];
- if (r_ptr[i] > border && r_ptr[i-1] <= border)
- r_ptr[j++] = r_ptr[i-1];
- }
- r_ptri = j;
- }
- }
- i_item_ptr = i_item;
- i_more = (*data->read_item)(data->clientData, &i_item_ptr, &i_mode);
- }
- r_ptr[r_ptri++] = r_offset;
- /* flush rest of block(s) in r_buf */
- if (is->method->debug > 1)
- logf (LOG_LOG, "isc: flush rest, %d sections", r_ptri-1);
- isc_flush_blocks (is, r_ptr, r_ptri, r_buf, &nextpos, &firstpos, cat, 1);
- (*is->method->code_stop)(ISAMC_ENCODE, r_clientData);
- return cat + firstpos * 8;
-}
-
-ISAMC_P isc_merge (ISAMC is, ISAMC_P ipos, ISAMC_I data)
-{
- char i_item[128], *i_item_ptr;
- int i_more, i_mode, i;
-
- ISAMC_PP pp;
- char f_item[128], *f_item_ptr;
- int f_more;
- int block_ptr[100]; /* block pointer (0 if none) */
- int dirty_ptr[100]; /* dirty flag pointer (1 if dirty) */
-
- int firstpos = 0;
- int nextpos = 0;
- int cat = 0;
- char r_item_buf[128]; /* temporary result output */
- char *r_buf; /* block with resulting data */
- int r_offset = 0; /* current offset in r_buf */
- int r_ptr[100]; /* offset pointer */
- int r_ptri = 0; /* pointer */
- void *r_clientData; /* encode client data */
-
- if (ipos == 0)
- return isc_merge_first (is, data);
-
- r_clientData = (*is->method->code_start)(ISAMC_ENCODE);
- r_buf = is->r_buf + ISAMC_BLOCK_OFFSET;
-
- pp = isc_pp_open (is, ipos);
- f_item_ptr = f_item;
- f_more = isc_read_item (pp, &f_item_ptr);
- cat = pp->cat;
-
- /* read first item from i */
- i_item_ptr = i_item;
- i_more = (*data->read_item)(data->clientData, &i_item_ptr, &i_mode);
- block_ptr[r_ptri] = pp->pos;
- dirty_ptr[r_ptri] = 0;
- r_ptr[r_ptri++] = 0;
-
- while (i_more || f_more)
- {
- char *r_item = r_item_buf;
- int cmp;
-
- if (!f_more)
- cmp = -1;
- else if (!i_more)
- cmp = 1;
- else
- cmp = (*is->method->compare_item)(i_item, f_item);
- if (cmp == 0) /* insert i=f */
- {
- if (!i_mode)
- {
- r_item = NULL;
- dirty_ptr[r_ptri-1] = 1;
- }
- else
- memcpy (r_item, f_item, f_item_ptr - f_item);
-
- /* move i */
- i_item_ptr = i_item;
- i_more = (*data->read_item)(data->clientData, &i_item_ptr,
- &i_mode);
- /* move f */
- f_item_ptr = f_item;
- f_more = isc_read_item (pp, &f_item_ptr);
- }
- else if (cmp > 0) /* insert f */
- {
- memcpy (r_item, f_item, f_item_ptr - f_item);
- /* move f */
- f_item_ptr = f_item;
- f_more = isc_read_item (pp, &f_item_ptr);
- }
- else /* insert i */
- {
- if (!i_mode) /* delete item which isn't there? */
- {
- logf (LOG_FATAL, "Inconsistent register");
- abort ();
- }
- memcpy (r_item, i_item, i_item_ptr - i_item);
- dirty_ptr[r_ptri-1] = 1;
- /* move i */
- i_item_ptr = i_item;
- i_more = (*data->read_item)(data->clientData, &i_item_ptr,
- &i_mode);
- }
- if (r_item) /* insert resulting item? */
- {
- char *r_out_ptr = r_buf + r_offset;
- int new_offset;
- int border;
-
- /* border set to initial fill or block size depending on
- whether we are creating a new one or updating and old
- */
- if (block_ptr[r_ptri-1])
- border = r_ptr[r_ptri-1] + is->method->filecat[cat].bsize
- -ISAMC_BLOCK_OFFSET;
- else
- border = r_ptr[r_ptri-1] + is->method->filecat[cat].ifill
- -ISAMC_BLOCK_OFFSET;
-
- (*is->method->code_item)(ISAMC_ENCODE, r_clientData,
- &r_out_ptr, &r_item);
- new_offset = r_out_ptr - r_buf;
-
- if (border >= r_offset && border < new_offset)
- {
- /* Initial fill of current block category reached...
- Save offset in r_ptr
- */
- r_ptr[r_ptri++] = r_offset;
- if (cat == is->max_cat)
- {
- /* We are dealing with block of max size. Block(s)
- will be flushed. Note: the block(s) are surely not
- the last one(s).
- */
- if (is->method->debug > 1)
- logf (LOG_LOG, "isc: flush %d sections", r_ptri-1);
- isc_flush_blocks (is, r_ptr, r_ptri, r_buf,
- &nextpos, &firstpos, cat, 0);
- r_ptri = 0;
- r_ptr[r_ptri++] = 0;
- memcpy (r_buf, r_buf + r_offset, new_offset - r_offset);
- new_offset = (new_offset - r_offset);
- }
- }
- r_offset = new_offset;
- if (cat < is->max_cat &&
- r_ptri>is->method->filecat[cat].mblocks)
- {
- /* Max number blocks in current category reached ->
- must switch to next category (with larger block size)
- */
- int j = 1;
- cat++;
- /* r_ptr[0] = r_ptr[0] = 0 true anyway.. */
- /* AD: Any old blocks should be deleted */
- for (i = 2; i < r_ptri; i++)
- {
- border = is->method->filecat[cat].ifill -
- ISAMC_BLOCK_OFFSET + r_ptr[j-1];
- if (r_ptr[i] > border && r_ptr[i-1] <= border)
- r_ptr[j++] = r_ptr[i-1];
- }
- r_ptri = j;
- }
- }
- }
- r_ptr[r_ptri++] = r_offset;
- /* flush rest of block(s) in r_buf */
- if (is->method->debug > 1)
- logf (LOG_LOG, "isc: flush rest, %d sections", r_ptri-1);
- isc_flush_blocks (is, r_ptr, r_ptri, r_buf, &nextpos, &firstpos, cat, 1);
- (*is->method->code_stop)(ISAMC_ENCODE, r_clientData);
- return cat + firstpos * 8;
-}
-
-
-#if 0
-ISAMC_P isc_merge (ISAMC is, ISAMC_P ipos, ISAMC_I data)
-{
- ISAMC_PP pp;
- char f_item[128], *f_item_ptr;
- int f_more;
- int cat = 0;
- int nextpos;
-
- char i_item[128], *i_item_ptr;
- int i_more, insertMode;
-
- char r_item_buf[128];
- int r_offset = ISAMC_BLOCK_OFFSET;
- int r_dirty = 0;
- char *r_ptr[100];
- int r_ptri = 0;
- int r_start = 0;
- void *r_clientData = (*is->method->code_start)();
-
- /* rewind and read first item from file */
- pp = isc_position (is, ipos);
- f_item_ptr = f_item;
- f_more = isc_read_item (pp, &f_item_ptr);
- cat = pp->cat;
-
- /* read first item from i */
- i_item_ptr = i_item;
- i_more = (*data->read_item)(data->clientData, &i_item_ptr, &insertMode);
-
- while (f_more || i_more)
- {
- int cmp;
- char *r_item = r_item_buf;
-
- if (!f_more)
- cmp = -1;
- else if (!i_more)
- cmp = 1;
- else
- cmp = (*is->method->compare_item)(i_item, f_item);
- if (cmp == 0) /* insert i=f */
- {
- if (!insertMode)
- {
- r_item = NULL;
- r_dirty = 1;
- }
- else
- memcpy (r_item, f_item, f_item_ptr - f_item);
-
- /* move i */
- i_item_ptr = i_item;
- i_more = (*data->read_item)(data->clientData, &i_item_ptr,
- &insertMode);
- /* move f */
- f_item_ptr = f_item;
- f_more = isc_read_item (pp, &f_item_ptr);
- }
- else if (cmp > 0) /* insert f */
- {
- memcpy (r_item, f_item, f_item_ptr - f_item);
- /* move f */
- f_item_ptr = f_item;
- f_more = isc_read_item (pp, &f_item_ptr);
- }
- else /* insert i */
- {
- if (!insertMode) /* delete item which isn't there? */
- {
- logf (LOG_FATAL, "Inconsistent register");
- abort ();
- }
- memcpy (r_item, i_item, i_item_ptr - i_item);
- r_dirty = 1;
- /* move i */
- i_item_ptr = i_item;
- i_more = (*data->read_item)(data->clientData, &i_item_ptr,
- &insertMode);
- }
- /* check for end of input block condition */
-
- if (r_item) /* insert resulting item? */
- {
- char *r_out_ptr = is->r_buf + r_offset;
- int new_offset;
- int border = is->method->filecat[cat].initsize - r_start;
-
- (*is->method->code_item)(r_clientData, &r_out_ptr, &r_item);
- new_offset = r_out_ptr - is->r_buf;
-
- if (border >= r_offset && border < r_newoffset)
- {
- r_ptr[r_ptri++] = r_offset;
- if (!is->method->filecat[cat].mblocks)
- {
- assert (r_ptri == 1);
- /* dump block from 0 -> r_offset in max cat */
- r_ptri = 0;
- r_offset = ISAMC_BLOCK_OFFSET;
- }
- }
- r_offset = new_offset;
- }
- if (r_ptri && r_ptri == is->method->filecat[cat].mblocks)
- {
- int i, j = 0;
-
- /* dump previous blocks in chain */
-
- /* recalc r_ptr's */
- cat++;
- for (i = 1; i<r_ptr; i++)
- {
- if (r_ptr[i] > is->method->filecat[cat].ifill &&
- r_ptr[i-1] <= is->method->filecat[cat].ifill)
- r_ptr[j++] = r_ptr[i-1];
- }
- r_ptri = j;
- }
- }
- (*is->method->code_stop)(r_clientData);
- return ipos;
-}
-#endif
-
void isc_pp_close (ISAMC_PP pp)
{
ISAMC is = pp->is;
pp->offset = 0;
pp->is = is;
pp->decodeClientData = (*is->method->code_start)(ISAMC_DECODE);
+ pp->deleteFlag = 0;
return pp;
}
-/* returns 1 if item could be read; 0 otherwise */
+/* returns non-zero if item could be read; 0 otherwise */
int isc_read_key (ISAMC_PP pp, void *buf)
{
return isc_read_item (pp, (char **) &buf);
}
-/* returns 1 if item could be read; 0 otherwise */
+/* returns non-zero if item could be read; 0 otherwise */
int isc_read_item (ISAMC_PP pp, char **dst)
{
ISAMC is = pp->is;
return 0;
src = pp->buf;
isc_read_block (is, pp->cat, pp->pos, src);
-
memcpy (&pp->next, src, sizeof(pp->next));
src += sizeof(pp->next);
memcpy (&pp->size, src, sizeof(pp->size));
src += sizeof(pp->size);
/* assume block is non-empty */
assert (pp->next != pp->pos);
+ if (pp->deleteFlag)
+ isc_release_block (is, pp->cat, pp->pos);
+ (*is->method->code_item)(ISAMC_DECODE, pp->decodeClientData, dst, &src);
+ pp->offset = src - pp->buf;
+ return 2;
}
(*is->method->code_item)(ISAMC_DECODE, pp->decodeClientData, dst, &src);
pp->offset = src - pp->buf;
return 1;
}
-int isc_read_islast (ISAMC_PP pp)
-{
- return pp->offset >= pp->size;
-}
-
int isc_numkeys (ISAMC_PP pp)
{
return 1;
--- /dev/null
+/*
+ * Copyright (c) 1996, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log: merge.c,v $
+ * Revision 1.1 1996-11-01 08:59:15 adam
+ * First version of isc_merge that supports update/delete.
+ *
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <log.h>
+#include "isamc-p.h"
+
+struct isc_merge_block {
+ int offset; /* offset in r_buf */
+ int block; /* block number of file (0 if none) */
+ int dirty; /* block is different from that on file */
+};
+
+static void flush_blocks (ISAMC is, struct isc_merge_block *mb, int ptr,
+ char *r_buf, int *firstpos, int cat, int last)
+{
+ int i;
+
+ for (i = 1; i<ptr; i++)
+ {
+ /* skip rest if not dirty */
+ if (!mb[i-1].dirty)
+ {
+ assert (mb[i-1].block);
+ if (!*firstpos)
+ *firstpos = mb[i-1].block;
+ if (is->method->debug > 2)
+ logf (LOG_LOG, "isc: skip block %d %d", cat, mb[i-1].block);
+ ++(is->files[cat].no_skip_writes);
+ continue;
+ }
+ /* consider this block number */
+ if (!mb[i-1].block)
+ mb[i-1].block = isc_alloc_block (is, cat);
+ if (!*firstpos)
+ *firstpos = mb[i-1].block;
+
+ /* consider next block pointer */
+ if (last && i == ptr-1)
+ mb[i].block = 0;
+ else if (!mb[i].block)
+ mb[i].block = isc_alloc_block (is, cat);
+
+ /* write block */
+ assert (mb[i].offset > mb[i-1].offset);
+ isc_write_dblock (is, cat, mb[i-1].block, r_buf + mb[i-1].offset,
+ mb[i].block, mb[i].offset - mb[i-1].offset);
+ }
+}
+
+ISAMC_P isc_merge (ISAMC is, ISAMC_P ipos, ISAMC_I data)
+{
+
+ char i_item[128], *i_item_ptr;
+ int i_more, i_mode, i;
+
+ ISAMC_PP pp;
+ char f_item[128], *f_item_ptr;
+ int f_more;
+
+ struct isc_merge_block mb[100];
+ int firstpos = 0;
+ int cat = 0;
+ char r_item_buf[128]; /* temporary result output */
+ char *r_buf; /* block with resulting data */
+ int r_offset = 0; /* current offset in r_buf */
+ int ptr = 0; /* pointer */
+ void *r_clientData; /* encode client data */
+
+ r_clientData = (*is->method->code_start)(ISAMC_ENCODE);
+ r_buf = is->merge_buf + ISAMC_BLOCK_OFFSET;
+
+ pp = isc_pp_open (is, ipos);
+ /* read first item from file. make sure f_more indicates no boundary */
+ f_item_ptr = f_item;
+ f_more = isc_read_item (pp, &f_item_ptr);
+ if (f_more > 0)
+ f_more = 1;
+ cat = pp->cat;
+
+ if (is->method->debug > 1)
+ logf (LOG_LOG, "isc: isc_merge begin %d %d", cat, pp->pos);
+
+ /* read first item from i */
+ i_item_ptr = i_item;
+ i_more = (*data->read_item)(data->clientData, &i_item_ptr, &i_mode);
+
+ mb[ptr].block = pp->pos; /* is zero if no block on disk */
+ mb[ptr].dirty = 0;
+ mb[ptr++].offset = 0;
+
+ while (i_more || f_more)
+ {
+ char *r_item = r_item_buf;
+ int cmp;
+
+ if (!f_more)
+ cmp = -1;
+ else if (!i_more)
+ cmp = 1;
+ else
+ cmp = (*is->method->compare_item)(i_item, f_item);
+ if (cmp == 0) /* insert i=f */
+ {
+ if (!i_mode) /* delete item? */
+ {
+ /* move i */
+ i_item_ptr = i_item;
+ i_more = (*data->read_item)(data->clientData, &i_item_ptr,
+ &i_mode);
+ /* it next input item the same as current except
+ for the delete flag? */
+ cmp = (*is->method->compare_item)(i_item, f_item);
+ if (0 && !cmp && i_mode)
+ {
+ /* yes! insert as if it was an insert only */
+ memcpy (r_item, i_item, i_item_ptr - i_item);
+ i_item_ptr = i_item;
+ i_more = (*data->read_item)(data->clientData, &i_item_ptr,
+ &i_mode);
+ }
+ else
+ {
+ /* no! delete the item */
+ r_item = NULL;
+ mb[ptr-1].dirty = 1;
+ }
+ }
+ else
+ {
+ memcpy (r_item, f_item, f_item_ptr - f_item);
+
+ /* move i */
+ i_item_ptr = i_item;
+ i_more = (*data->read_item)(data->clientData, &i_item_ptr,
+ &i_mode);
+ }
+ /* move f */
+ f_item_ptr = f_item;
+ f_more = isc_read_item (pp, &f_item_ptr);
+ }
+ else if (cmp > 0) /* insert f */
+ {
+ memcpy (r_item, f_item, f_item_ptr - f_item);
+ /* move f */
+ f_item_ptr = f_item;
+ f_more = isc_read_item (pp, &f_item_ptr);
+ }
+ else /* insert i */
+ {
+ if (!i_mode) /* delete item which isn't there? */
+ {
+ logf (LOG_FATAL, "Inconsistent register at offset %d",
+ r_offset);
+ abort ();
+ }
+ memcpy (r_item, i_item, i_item_ptr - i_item);
+ mb[ptr-1].dirty = 1;
+ /* move i */
+ i_item_ptr = i_item;
+ i_more = (*data->read_item)(data->clientData, &i_item_ptr,
+ &i_mode);
+ }
+ if (f_more > 1)
+ {
+ /* block to block boundary in the original file. */
+ f_more = 1;
+ if (cat == pp->cat)
+ {
+ /* the resulting output is of the same category as the
+ the original
+ */
+ if (mb[ptr-1].offset == r_offset)
+ {
+ /* the resulting output block is empty. Delete
+ the original (if any)
+ */
+ if (mb[ptr-1].block)
+ isc_release_block (is, pp->cat, mb[ptr-1].block);
+ mb[ptr-1].block = pp->pos;
+ mb[ptr-1].dirty = 1;
+ }
+ else
+ {
+ /* indicate new boundary based on the original file */
+ mb[ptr].block = pp->pos;
+ mb[ptr].dirty = 0;
+ mb[ptr++].offset = r_offset;
+#if 0
+ if (r_item && cat == is->max_cat)
+ {
+ /* We are dealing with block(s) of max size. Block(s)
+ will be flushed. Note: the block(s) are surely not
+ the last one(s).
+ */
+ if (is->method->debug > 2)
+ logf (LOG_LOG, "isc: flush A %d sections", ptr-1);
+ flush_blocks (is, mb, ptr-1, r_buf, &firstpos, cat, 0);
+ ptr = 0;
+ mb[ptr].block = pp->pos;
+ mb[ptr].dirty = 0;
+ mb[ptr++].offset = 0;
+ }
+#endif
+ }
+ }
+ }
+ if (r_item) /* insert resulting item? */
+ {
+ char *r_out_ptr = r_buf + r_offset;
+ int new_offset;
+ int border;
+
+ /* border set to initial fill or block size depending on
+ whether we are creating a new one or updating and old one
+ */
+ if (mb[ptr-1].block)
+ border = mb[ptr-1].offset + is->method->filecat[cat].bsize
+ -ISAMC_BLOCK_OFFSET;
+ else
+ border = mb[ptr-1].offset + is->method->filecat[cat].ifill
+ -ISAMC_BLOCK_OFFSET;
+
+ (*is->method->code_item)(ISAMC_ENCODE, r_clientData,
+ &r_out_ptr, &r_item);
+ new_offset = r_out_ptr - r_buf;
+
+ if (border >= r_offset && border < new_offset)
+ {
+ if (is->method->debug > 2)
+ logf (LOG_LOG, "isc: border %d %d", ptr, border);
+ /* Max size of current block category reached ...
+ make new virtual block entry */
+ mb[ptr].block = 0;
+ mb[ptr].dirty = 1;
+ mb[ptr++].offset = r_offset;
+ if (cat == is->max_cat)
+ {
+ /* We are dealing with block(s) of max size. Block(s)
+ will be flushed. Note: the block(s) are surely not
+ the last one(s).
+ */
+ if (is->method->debug > 2)
+ logf (LOG_LOG, "isc: flush B %d sections", ptr-1);
+ flush_blocks (is, mb, ptr, r_buf, &firstpos, cat, 0);
+ mb[0].block = mb[ptr-1].block;
+ ptr = 0;
+ mb[ptr].dirty = 1;
+ mb[ptr++].offset = 0;
+ memcpy (r_buf, r_buf + r_offset, new_offset - r_offset);
+ new_offset = (new_offset - r_offset);
+ }
+ }
+ r_offset = new_offset;
+ }
+ if (cat < is->max_cat && ptr > is->method->filecat[cat].mblocks)
+ {
+ /* Max number blocks in current category reached ->
+ must switch to next category (with larger block size)
+ */
+ int j = 0;
+
+ (is->files[cat].no_remap)++;
+ /* delete all original block(s) read so far */
+ for (i = 1; i < ptr; i++)
+ if (mb[i-1].block)
+ isc_release_block (is, pp->cat, mb[i-1].block);
+ /* also delete all block to be read in the future */
+ pp->deleteFlag = 1;
+
+ /* remap block offsets */
+ assert (mb[j].offset == 0);
+ cat++;
+ mb[j].dirty = 1;
+ mb[j++].block = 0;
+ for (i = 2; i < ptr; i++)
+ {
+ int border = is->method->filecat[cat].ifill -
+ ISAMC_BLOCK_OFFSET + mb[j-1].offset;
+ if (is->method->debug > 3)
+ logf (LOG_LOG, "isc: remap %d border=%d", i-1, border);
+ if (mb[i].offset > border && mb[i-1].offset <= border)
+ {
+ if (is->method->debug > 3)
+ logf (LOG_LOG, "isc: to %d %d", j, mb[i-1].offset);
+ mb[j].dirty = 1;
+ mb[j].block = 0;
+ mb[j++].offset = mb[i-1].offset;
+ assert (j <= i);
+ }
+ }
+ if (is->method->debug > 2)
+ logf (LOG_LOG, "isc: remap from %d to %d sections to cat %d",
+ ptr, j, cat);
+ ptr = j;
+ }
+ }
+ if (mb[ptr-1].offset < r_offset)
+ { /* make the final boundary offset */
+ mb[ptr].dirty = 1; /* ignored by flush_blocks */
+ mb[ptr].block = 0; /* ignored by flush_blocks */
+ mb[ptr++].offset = r_offset;
+ }
+ else
+ { /* empty output. Release last block if any */
+ if (cat == pp->cat && mb[ptr-1].block)
+ {
+ isc_release_block (is, pp->cat, mb[ptr-1].block);
+ mb[ptr-1].block = 0;
+ mb[ptr-1].dirty = 1;
+ }
+ }
+
+ if (is->method->debug > 2)
+ logf (LOG_LOG, "isc: flush C, %d sections", ptr-1);
+
+ /* flush rest of block(s) in r_buf */
+ flush_blocks (is, mb, ptr, r_buf, &firstpos, cat, 1);
+
+ (*is->method->code_stop)(ISAMC_ENCODE, r_clientData);
+ if (!firstpos)
+ cat = 0;
+ if (is->method->debug > 1)
+ logf (LOG_LOG, "isc: isc_merge return %d %d", cat, firstpos);
+ return cat + firstpos * 8;
+}
+