+
+static ISAM_P is_address(int type, int pos)
+{
+ ISAM_P r;
+
+ r = pos << 2;
+ r |= type;
+ return r;
+}
+
+ISAM_P is_merge(ISAM is, ISAM_P pos, int num, char *data)
+{
+ is_mtable tab;
+ int res;
+ char keybuf[IS_MAX_RECORD];
+ int oldnum, oldtype, i;
+ char operation, *record;
+
+ statistics.total_merge_operations++;
+ statistics.total_items += num;
+ if (!pos)
+ statistics.new_tables++;
+
+ is_m_establish_tab(is, &tab, pos);
+ if (pos)
+ if (is_m_read_full(&tab, tab.data) < 0)
+ {
+ logf (LOG_FATAL, "read_full failed");
+ exit(1);
+ }
+ oldnum = tab.num_records;
+ oldtype = tab.pos_type;
+ while (num)
+ {
+ operation = *(data)++;
+ record = (char*) data;
+ data += is_keysize(is);
+ num--;
+ while (num && !memcmp(record - 1, data, is_keysize(tab.is) + 1))
+ {
+ data += 1 + is_keysize(is);
+ num--;
+ statistics.dub_items_removed++;
+ }
+ if ((res = is_m_seek_record(&tab, record)) > 0) /* no match */
+ {
+ if (operation == KEYOP_INSERT)
+ {
+ logf (LOG_DEBUG, "XXInserting new record.");
+ is_m_write_record(&tab, record);
+ statistics.new_items++;
+ }
+ else
+ {
+ logf (LOG_DEBUG, "XXDeletion failed to find match.");
+ statistics.failed_deletes++;
+ }
+ }
+ else /* match found */
+ {
+ if (operation == KEYOP_INSERT)
+ {
+ logf (LOG_DEBUG, "XXSkipping insertion - match found.");
+ statistics.skipped_inserts++;
+ continue;
+ }
+ else if (operation == KEYOP_DELETE)
+ {
+ /* try to avoid needlessly moving data */
+ if (num && *(data) == KEYOP_INSERT)
+ {
+ /* next key is identical insert? - NOOP - skip it */
+ if (!memcmp(record, data + 1, is_keysize(is)))
+ {
+ logf (LOG_DEBUG, "XXNoop delete. skipping.");
+ data += 1 + is_keysize(is);
+ num--;
+ while (num && !memcmp(data, data + is_keysize(tab.is) +
+ 1, is_keysize(tab.is) + 1))
+ {
+ data += 1 + is_keysize(is);
+ num--;
+ statistics.dub_items_removed++;
+ }
+ statistics.delete_insert_noop++;
+ continue;
+ }
+ /* else check if next key can fit in this position */
+ if (is_m_peek_record(&tab, keybuf) &&
+ (*is->cmp)(data + 1, keybuf) < 0)
+ {
+ logf (LOG_DEBUG, "XXReplacing record.");
+ is_m_replace_record(&tab, data + 1);
+ data += 1 + is_keysize(is);
+ num--;
+ while (num && !memcmp(data, data + is_keysize(tab.is) +
+ 1, is_keysize(tab.is) + 1))
+ {
+ data += 1 + is_keysize(is);
+ num--;
+ statistics.dub_items_removed++;
+ }
+ statistics.delete_replace++;
+ continue;
+ }
+ }
+ logf (LOG_DEBUG, "Deleting record.");
+ is_m_delete_record(&tab);
+ statistics.delete++;
+ }
+ }
+ }
+ i = tab.pos_type;
+ while (i < tab.is->num_types - 1 && tab.num_records >
+ tab.is->types[i].max_keys)
+ i++;
+ if (i != tab.pos_type)
+ {
+ /* read remaining blocks */
+ for (; tab.cur_mblock; tab.cur_mblock = tab.cur_mblock->next)
+ if (tab.cur_mblock->state < IS_MBSTATE_CLEAN)
+ is_m_read_full(&tab, tab.cur_mblock);
+ is_p_unmap(&tab);
+ tab.pos_type = i;
+ if (pos)
+ statistics.block_jumps++;
+ }
+ if (!oldnum || tab.pos_type != oldtype || (abs(oldnum - tab.num_records) *
+ 100) / oldnum > tab.is->repack)
+ {
+ is_p_remap(&tab);
+ statistics.remaps++;
+ }
+ else
+ is_p_align(&tab);
+ if (tab.data)
+ {
+ is_p_sync(&tab);
+ pos = is_address(tab.pos_type, tab.data->diskpos);
+ }
+ else
+ {
+ pos = 0;
+ statistics.tab_deletes++;
+ }
+ is_m_release_tab(&tab);
+ return pos;
+}
+
+/*
+ * Locate a table of keys in an isam file. The ISPT is an individual
+ * position marker for that table.
+ */
+ISPT is_position(ISAM is, ISAM_P pos)
+{
+ ispt_struct *p;
+
+ p = ispt_alloc();
+ is_m_establish_tab(is, &p->tab, pos);
+ return p;
+}
+
+/*
+ * Release ISPT.
+ */
+void is_pt_free(ISPT ip)
+{
+ is_m_release_tab(&ip->tab);
+ ispt_free(ip);
+}
+
+/*
+ * Read a key from a table.
+ */
+int is_readkey(ISPT ip, void *buf)
+{
+ return is_m_read_record(&ip->tab, buf, 0);
+}
+
+int is_numkeys(ISPT ip)
+{
+ return is_m_num_records(&ip->tab);
+}
+
+void is_rewind(ISPT ip)
+{
+ is_m_rewind(&ip->tab);
+}