+
+struct random_read_info {
+ int max;
+ int idx;
+ int level;
+ int *delta;
+};
+
+int tst_random_read(void *vp, char **dst, int *insertMode)
+{
+ struct random_read_info *ri = (struct random_read_info *)vp;
+ int x;
+
+ while(ri->idx < ri->max && ri->delta[ri->idx] == ri->level)
+ {
+ ri->idx++;
+ ri->level = 0;
+ }
+ if (ri->idx >= ri->max)
+ return 0;
+
+ if (ri->delta[ri->idx] > 0)
+ {
+ ri->level++;
+ *insertMode = 1;
+ }
+ else
+ {
+ ri->level--;
+ *insertMode = 0;
+ }
+ x = ri->idx;
+ memcpy (*dst, &x, sizeof(int));
+ (*dst)+=sizeof(int);
+
+ yaz_log(YLOG_DEBUG, "%d %5d", *insertMode, x);
+ return 1;
+}
+
+void tst_random(ISAMB isb, int n, int rounds, int max_dups)
+{
+ ISAM_P isamb_p = 0;
+
+ int *freq = malloc(sizeof(int) * n);
+ int *delta = malloc(sizeof(int) * n);
+ int i, j;
+ for (i = 0; i<n; i++)
+ freq[i] = 0;
+
+ for (j = 0; j<rounds; j++)
+ {
+ yaz_log(YLOG_DEBUG, "round %d", j);
+ for (i = 0; i<n; i++)
+ {
+ if (rand() & 1)
+ delta[i] = (rand() % (1+max_dups)) - freq[i];
+ else
+ delta[i] = 0;
+ }
+ if (n)
+ {
+ ISAMC_I isamc_i;
+ struct random_read_info ri;
+
+ ri.delta = delta;
+ ri.idx = 0;
+ ri.max = n;
+ ri.level = 0;
+
+ isamc_i.clientData = &ri;
+ isamc_i.read_item = tst_random_read;
+
+ isamb_merge (isb, &isamb_p , &isamc_i);
+ }
+
+ yaz_log(YLOG_DEBUG, "dump %d", j);
+ isamb_dump(isb, isamb_p, log_pr);
+
+ yaz_log(YLOG_DEBUG, "----------------------------");
+ for (i = 0; i<n; i++)
+ freq[i] += delta[i];
+
+ if (!isamb_p)
+ {
+ for (i = 0; i<n; i++)
+ if (freq[i])
+ {
+ yaz_log(YLOG_WARN, "isamb_merge returned 0, but "
+ "freq is non-empty");
+ exit(1);
+ }
+ }
+ else
+ {
+ int level = 0;
+ int idx = 0;
+ char key_buf[20];
+ ISAMB_PP pp = isamb_pp_open (isb, isamb_p, 1);
+
+ yaz_log(YLOG_DEBUG, "test %d", j);
+
+ while(isamb_pp_read (pp, key_buf))
+ {
+ int x;
+ memcpy (&x, key_buf, sizeof(int));
+ yaz_log(YLOG_DEBUG, "Got %d", x);
+ while (idx < n && freq[idx] == level)
+ {
+ idx++;
+ level = 0;
+ }
+ if (idx == n)
+ {
+ yaz_log(YLOG_WARN, "tst_random: Extra item: %d", x);
+ exit(1);
+ }
+ if (idx != x)
+ {
+ yaz_log(YLOG_WARN, "tst_random: Mismatch %d != %d",
+ x, idx);
+ exit(1);
+ }
+ level++;
+ }
+ while (idx < n && freq[idx] == level)
+ {
+ idx++;
+ level = 0;
+ }
+ if (idx != n)
+ {
+ yaz_log(YLOG_WARN, "tst_random: Missing item: %d", idx);
+ exit(1);
+ }
+ isamb_pp_close(pp);
+ }
+ }
+ free(freq);
+ free(delta);
+}
+
+/* \fn void tst_minsert(ISAMB isb, int n)
+ \brief insert inserts n identical keys, removes n/2, then n-n/2 ..
+ \param isb ISAMB handle
+ \param n number of keys
+*/
+void tst_minsert(ISAMB isb, int n)
+{
+ ISAMC_I isamc_i;
+ ISAM_P isamb_p = 0;
+ struct read_info ri;
+
+ isamc_i.clientData = &ri;
+
+ /* all have same value = 1 */
+ ri.val = 1;
+ ri.step = 0;
+
+ isamc_i.read_item = code_read;
+
+ ri.no = 0;
+ ri.max = n;
+
+ ri.insertMode = 1;
+
+ isamb_merge (isb, &isamb_p , &isamc_i);
+
+ isamb_dump(isb, isamb_p, log_pr);
+
+ ri.no = 0;
+ ri.max = n - n/2;
+
+ ri.insertMode = 0;
+
+ isamb_merge (isb, &isamb_p , &isamc_i);
+
+ ri.no = 0;
+ ri.max = n/2;
+
+ ri.insertMode = 0;
+
+ isamb_merge (isb, &isamb_p , &isamc_i);
+ if (isamb_p)
+ {
+ yaz_log(YLOG_WARN, "tst_minsert: isamb_merge should be empty n=%d",
+ n);
+ exit(1);
+ }
+}
+
+/* tests for identical keys.. ISAMB does not handle that, so some of the
+ tests below fails
+*/
+static void identical_keys_tests(ISAMB isb)
+{
+#if 1
+ tst_minsert(isb, 10);
+#endif
+#if 0
+ tst_minsert(isb, 600); /* still fails */
+#endif
+#if 1
+ tst_random(isb, 20, 200, 1);
+#endif
+#if 1
+ tst_random(isb, 5, 200, 2);
+#endif
+
+#if 1
+ tst_random(isb, 250, 10, 4);
+#endif
+#if 1
+ /* fails if both are executed */
+ tst_random(isb, 20000, 10, 4);
+ tst_random(isb, 20000, 10, 10);
+#endif
+#if 1
+ tst_random(isb, 250, 100, 10);
+#endif
+}
+