+ SYSNO sysno;
+ int i;
+ ASSERTZH;
+ yaz_log(LOG_API,"zebra_admin_import_segment");
+ zh->errCode=0;
+ for (i = 0; i<segment->num_segmentRecords; i++)
+ {
+ Z_NamePlusRecord *npr = segment->segmentRecords[i];
+
+ printf ("--------------%d--------------------\n", i);
+ if (npr->which == Z_NamePlusRecord_intermediateFragment)
+ {
+ Z_FragmentSyntax *fragment = npr->u.intermediateFragment;
+ if (fragment->which == Z_FragmentSyntax_notExternallyTagged)
+ {
+ Odr_oct *oct = fragment->u.notExternallyTagged;
+ printf ("%.*s", (oct->len > 100 ? 100 : oct->len) ,
+ oct->buf);
+
+ sysno = 0;
+
+ zebra_update_record(zh,
+ 0, /* record Type */
+ &sysno,
+ 0, /* match */
+ 0, /* fname */
+ oct->buf, oct->len,
+ 0);
+ }
+ }
+ }
+ return 0;
+}
+
+int zebra_admin_exchange_record (ZebraHandle zh,
+ const char *rec_buf,
+ size_t rec_len,
+ const char *recid_buf, size_t recid_len,
+ int action)
+ /* 1 = insert. Fail it already exists */
+ /* 2 = replace. Fail it does not exist */
+ /* 3 = delete. Fail if does not exist */
+ /* 4 = update. Insert/replace */
+{
+ SYSNO sysno = 0;
+ char *rinfo = 0;
+ char recid_z[256];
+ ASSERTZH;
+ yaz_log(LOG_API,"zebra_admin_exchange_record ac=%d", action);
+ zh->errCode=0;
+
+ if (!recid_buf || recid_len <= 0 || recid_len >= sizeof(recid_z))
+ return -1;
+ memcpy (recid_z, recid_buf, recid_len);
+ recid_z[recid_len] = 0;
+
+ if (zebra_begin_trans(zh, 1))
+ return -1;
+
+ rinfo = dict_lookup (zh->reg->matchDict, recid_z);
+ if (rinfo)
+ {
+ if (action == 1) /* fail if insert */
+ {
+ zebra_end_trans(zh);
+ return -1;
+ }
+
+ memcpy (&sysno, rinfo+1, sizeof(sysno));
+ }
+ else
+ {
+ if (action == 2 || action == 3) /* fail if delete or update */
+ {
+ zebra_end_trans(zh);
+ return -1;
+ }
+ action = 1; /* make it an insert (if it's an update).. */
+ }
+ buffer_extract_record (zh, rec_buf, rec_len,
+ action == 3 ? 1 : 0 /* delete flag */,
+ 0, /* test mode */
+ 0, /* recordType */
+ &sysno,
+ 0, /* match */
+ 0, /* fname */
+ 0, /* force update */
+ 1 /* allow update */
+ );
+ if (action == 1)
+ {
+ dict_insert (zh->reg->matchDict, recid_z, sizeof(sysno), &sysno);
+ }
+ else if (action == 3)
+ {
+ dict_delete (zh->reg->matchDict, recid_z);
+ }
+ zebra_end_trans(zh);
+ return 0;
+}
+
+int delete_w_handle(const char *info, void *handle)
+{
+ ZebraHandle zh = (ZebraHandle) handle;
+ ISAMC_P pos;
+
+ if (*info == sizeof(pos))
+ {
+ memcpy (&pos, info+1, sizeof(pos));
+ isamb_unlink(zh->reg->isamb, pos);
+ }
+ return 0;
+}
+
+static int delete_SU_handle(void *handle, int ord)
+{
+ ZebraHandle zh = (ZebraHandle) handle;
+ char ord_buf[20];
+ int ord_len;
+
+ ord_len = key_SU_encode (ord, ord_buf);
+ ord_buf[ord_len] = '\0';
+
+ assert (zh->reg->isamb);
+ dict_delete_subtree(zh->reg->dict, ord_buf,
+ zh, delete_w_handle);
+ return 0;
+}
+
+int zebra_drop_database (ZebraHandle zh, const char *database)
+{
+ int ret = 0;
+ ASSERTZH;
+ yaz_log(LOG_API,"zebra_drop_database");
+ zh->errCode = 0;
+
+ if (zebra_select_database (zh, database))
+ return -1;
+ if (zebra_begin_trans (zh, 1))
+ return -1;
+ if (zh->reg->isamb)
+ {
+ zebraExplain_curDatabase (zh->reg->zei, database);
+
+ zebraExplain_trav_ord(zh->reg->zei, zh, delete_SU_handle);
+ zebraExplain_removeDatabase(zh->reg->zei, zh);
+ }
+ else
+ {
+ yaz_log(LOG_WARN, "drop database only supported for isam:b");
+ ret = -1;
+ }
+ zebra_end_trans (zh);
+ return ret;
+}
+
+int zebra_create_database (ZebraHandle zh, const char *database)
+{
+ ASSERTZH;
+ yaz_log(LOG_API,"zebra_create_database");
+ zh->errCode=0;
+
+ if (zebra_select_database (zh, database))
+ return -1;
+ if (zebra_begin_trans (zh, 1))
+ return -1;
+
+ /* announce database */
+ if (zebraExplain_newDatabase (zh->reg->zei, database, 0
+ /* explainDatabase */))
+ {
+ zebra_end_trans (zh);
+ zh->errCode = 224;
+ zh->errString = "database already exist";
+ return -1;
+ }
+ zebra_end_trans (zh);
+ return 0;
+}
+
+int zebra_string_norm (ZebraHandle zh, unsigned reg_id,
+ const char *input_str, int input_len,
+ char *output_str, int output_len)
+{
+ WRBUF wrbuf;
+ ASSERTZH;
+ yaz_log(LOG_API,"zebra_string_norm ");
+ zh->errCode=0;
+ if (!zh->reg->zebra_maps)
+ return -1;
+ wrbuf = zebra_replace(zh->reg->zebra_maps, reg_id, "",
+ input_str, input_len);
+ if (!wrbuf)
+ return -2;
+ if (wrbuf_len(wrbuf) >= output_len)
+ return -3;
+ if (wrbuf_len(wrbuf))
+ memcpy (output_str, wrbuf_buf(wrbuf), wrbuf_len(wrbuf));
+ output_str[wrbuf_len(wrbuf)] = '\0';
+ return wrbuf_len(wrbuf);
+}
+
+
+int zebra_set_state (ZebraHandle zh, int val, int seqno)
+{
+ char state_fname[256];
+ char *fname;
+ long p = getpid();
+ FILE *f;
+ ASSERTZH;
+ yaz_log(LOG_API,"zebra_set_state v=%d seq=%d", val, seqno);
+ zh->errCode=0;
+
+ sprintf (state_fname, "state.%s.LCK", zh->reg_name);
+ fname = zebra_mk_fname (res_get(zh->res, "lockDir"), state_fname);
+ f = fopen (fname, "w");
+
+ yaz_log (LOG_DEBUG, "%c %d %ld", val, seqno, p);
+ fprintf (f, "%c %d %ld\n", val, seqno, p);
+ fclose (f);
+ xfree (fname);
+ return 0;
+}
+
+int zebra_get_state (ZebraHandle zh, char *val, int *seqno)
+{
+ char state_fname[256];
+ char *fname;
+ FILE *f;
+
+ ASSERTZH;
+ yaz_log(LOG_API,"zebra_get_state ");
+ zh->errCode=0;
+ sprintf (state_fname, "state.%s.LCK", zh->reg_name);
+ fname = zebra_mk_fname (res_get(zh->res, "lockDir"), state_fname);
+ f = fopen (fname, "r");
+ *val = 'o';
+ *seqno = 0;
+
+ if (f)
+ {
+ fscanf (f, "%c %d", val, seqno);
+ fclose (f);
+ }
+ xfree (fname);
+ return 0;
+}
+
+int zebra_begin_read (ZebraHandle zh)
+{
+ return zebra_begin_trans(zh, 0);
+}
+
+int zebra_end_read (ZebraHandle zh)
+{
+ return zebra_end_trans(zh);
+}
+
+static void read_res_for_transaction(ZebraHandle zh)
+{
+ const char *group = res_get(zh->res, "group");
+ const char *v;
+
+ zh->m_group = group;
+ v = res_get_prefix(zh->res, "followLinks", group, "1");
+ zh->m_follow_links = atoi(v);
+
+ zh->m_record_id = res_get_prefix(zh->res, "recordId", group, 0);
+ zh->m_record_type = res_get_prefix(zh->res, "recordType", group, 0);
+
+ v = res_get_prefix(zh->res, "storeKeys", group, "1");
+ zh->m_store_keys = atoi(v);
+
+ v = res_get_prefix(zh->res, "storeData", group, "1");
+ zh->m_store_data = atoi(v);
+
+ v = res_get_prefix(zh->res, "explainDatabase", group, "0");
+ zh->m_explain_database = atoi(v);
+
+ v = res_get_prefix(zh->res, "openRW", group, "1");
+ zh->m_flag_rw = atoi(v);
+
+ v = res_get_prefix(zh->res, "fileVerboseLimit", group, "100000");
+ zh->m_file_verbose_limit = atoi(v);
+}
+
+int zebra_begin_trans (ZebraHandle zh, int rw)
+{
+ if (!zh->res)
+ {
+ zh->errCode = 2;
+ zh->errString = "zebra_begin_trans: no database selected";
+ return -1;
+ }
+ ASSERTZHRES;
+ yaz_log(LOG_API,"zebra_begin_trans rw=%d",rw);
+
+ if (zh->user_perm)
+ {
+ if (rw && !strchr(zh->user_perm, 'w'))
+ {
+ zh->errCode = 223;
+ zh->errString = 0;
+ return -1;
+ }
+ }
+
+ assert (zh->res);
+ if (rw)
+ {
+ int pass;
+ int seqno = 0;
+ char val = '?';
+ const char *rval = 0;
+
+ (zh->trans_no++);
+ if (zh->trans_w_no)
+ {
+ read_res_for_transaction(zh);
+ return 0;
+ }
+ if (zh->trans_no != 1)
+ {
+ zh->errCode = 2;
+ zh->errString = "zebra_begin_trans: write trans not allowed within read trans";
+ return -1;
+ }
+ if (zh->reg)
+ {
+ resultSetInvalidate (zh);
+ zebra_register_close (zh->service, zh->reg);
+ }
+ zh->trans_w_no = zh->trans_no;
+
+ zh->errCode=0;
+
+ zh->records_inserted = 0;
+ zh->records_updated = 0;
+ zh->records_deleted = 0;
+ zh->records_processed = 0;
+
+#if HAVE_SYS_TIMES_H
+ times (&zh->tms1);
+#endif
+ /* lock */
+ if (zh->shadow_enable)
+ rval = res_get (zh->res, "shadow");
+
+ for (pass = 0; pass < 2; pass++)
+ {
+ if (rval)
+ {
+ zebra_lock_r (zh->lock_normal);
+ zebra_lock_w (zh->lock_shadow);
+ }
+ else
+ {
+ zebra_lock_w (zh->lock_normal);
+ zebra_lock_w (zh->lock_shadow);
+ }
+
+ zebra_get_state (zh, &val, &seqno);
+ if (val == 'c')
+ {
+ yaz_log (LOG_LOG, "previous transaction didn't finish commit");
+ zebra_unlock (zh->lock_shadow);
+ zebra_unlock (zh->lock_normal);
+ zebra_commit (zh);
+ continue;
+ }
+ else if (val == 'd')
+ {
+ if (rval)
+ {
+ BFiles bfs = bfs_create (res_get (zh->res, "shadow"),
+ zh->path_reg);
+ yaz_log (LOG_LOG, "previous transaction didn't reach commit");
+ bf_commitClean (bfs, rval);
+ bfs_destroy (bfs);
+ }
+ else
+ {
+ yaz_log (LOG_WARN, "your previous transaction didn't finish");
+ }
+ }
+ break;
+ }
+ if (pass == 2)
+ {
+ yaz_log (LOG_FATAL, "zebra_begin_trans couldn't finish commit");
+ abort();
+ return -1;
+ }
+ zebra_set_state (zh, 'd', seqno);
+
+ zh->reg = zebra_register_open (zh->service, zh->reg_name,
+ 1, rval ? 1 : 0, zh->res,
+ zh->path_reg);
+ if (zh->reg)
+ zh->reg->seqno = seqno;
+ else
+ {
+ zebra_set_state (zh, 'o', seqno);
+
+ zebra_unlock (zh->lock_shadow);
+ zebra_unlock (zh->lock_normal);
+
+ zh->trans_no--;
+ zh->trans_w_no = 0;
+
+ zh->errCode = 2;
+ zh->errString = "zebra_begin_trans: cannot open register";
+ yaz_log(LOG_FATAL, zh->errString);
+ return -1;
+ }
+ }
+ else
+ {
+ int dirty = 0;
+ char val;
+ int seqno;
+
+ (zh->trans_no)++;
+
+ if (zh->trans_no != 1)
+ {
+ zebra_flush_reg (zh);
+ return 0;
+ }
+ zh->errCode=0;
+#if HAVE_SYS_TIMES_H
+ times (&zh->tms1);
+#endif
+ if (!zh->res)
+ {
+ (zh->trans_no)--;
+ zh->errCode = 109;
+ return -1;
+ }
+ if (!zh->lock_normal || !zh->lock_shadow)
+ {
+ (zh->trans_no)--;
+ zh->errCode = 2;
+ return -1;
+ }
+ zebra_get_state (zh, &val, &seqno);
+ if (val == 'd')
+ val = 'o';
+
+ if (!zh->reg)
+ dirty = 1;
+ else if (seqno != zh->reg->seqno)
+ {
+ yaz_log (LOG_LOG, "reopen seqno cur/old %d/%d",
+ seqno, zh->reg->seqno);
+ dirty = 1;
+ }
+ else if (zh->reg->last_val != val)
+ {
+ yaz_log (LOG_LOG, "reopen last cur/old %d/%d",
+ val, zh->reg->last_val);
+ dirty = 1;
+ }
+ if (!dirty)
+ return 0;
+
+ if (val == 'c')
+ zebra_lock_r (zh->lock_shadow);
+ else
+ zebra_lock_r (zh->lock_normal);
+
+ if (zh->reg)
+ {
+ resultSetInvalidate (zh);
+ zebra_register_close (zh->service, zh->reg);
+ }
+ zh->reg = zebra_register_open (zh->service, zh->reg_name,
+ 0, val == 'c' ? 1 : 0,
+ zh->res, zh->path_reg);
+ if (!zh->reg)
+ {
+ zebra_unlock (zh->lock_normal);
+ zebra_unlock (zh->lock_shadow);
+ zh->trans_no--;
+ zh->errCode = 109;
+ return -1;
+ }
+ zh->reg->last_val = val;
+ zh->reg->seqno = seqno;
+ }
+ read_res_for_transaction(zh);
+ return 0;
+}
+
+int zebra_end_trans (ZebraHandle zh)
+{
+ ZebraTransactionStatus dummy;
+ yaz_log(LOG_API,"zebra_end_trans");
+ return zebra_end_transaction(zh, &dummy);
+}
+
+int zebra_end_transaction (ZebraHandle zh, ZebraTransactionStatus *status)
+{
+ char val;
+ int seqno;
+ const char *rval;
+
+ ASSERTZH;
+ yaz_log(LOG_API,"zebra_end_transaction");
+
+ status->processed = 0;
+ status->inserted = 0;
+ status->updated = 0;
+ status->deleted = 0;
+ status->utime = 0;
+ status->stime = 0;
+
+ if (!zh->res || !zh->reg)
+ {
+ zh->errCode = 2;
+ zh->errString = "zebra_end_trans: no open transaction";
+ return -1;
+ }
+ if (zh->trans_no != zh->trans_w_no)
+ {
+ zh->trans_no--;
+ if (zh->trans_no != 0)
+ return 0;
+
+ /* release read lock */
+
+ zebra_unlock (zh->lock_normal);
+ zebra_unlock (zh->lock_shadow);
+ }
+ else
+ { /* release write lock */
+ zh->trans_no--;
+ zh->trans_w_no = 0;
+
+ yaz_log (LOG_LOG, "zebra_end_trans");
+ rval = res_get (zh->res, "shadow");
+
+ zebraExplain_runNumberIncrement (zh->reg->zei, 1);
+
+ zebra_flush_reg (zh);
+
+ resultSetInvalidate (zh);
+
+ zebra_register_close (zh->service, zh->reg);
+ zh->reg = 0;
+
+ yaz_log (LOG_LOG, "Records: "ZINT_FORMAT" i/u/d "
+ ZINT_FORMAT"/"ZINT_FORMAT"/"ZINT_FORMAT,
+ zh->records_processed, zh->records_inserted,
+ zh->records_updated, zh->records_deleted);
+
+ status->processed = zh->records_processed;
+ status->inserted = zh->records_inserted;
+ status->updated = zh->records_updated;
+ status->deleted = zh->records_deleted;
+
+ zebra_get_state (zh, &val, &seqno);
+ if (val != 'd')
+ {
+ BFiles bfs = bfs_create (rval, zh->path_reg);
+ yaz_log (LOG_LOG, "deleting shadow stuff val=%c", val);
+ bf_commitClean (bfs, rval);
+ bfs_destroy (bfs);
+ }
+ if (!rval)
+ seqno++;
+ zebra_set_state (zh, 'o', seqno);
+
+ zebra_unlock (zh->lock_shadow);
+ zebra_unlock (zh->lock_normal);
+
+ }
+#if HAVE_SYS_TIMES_H
+ times (&zh->tms2);
+ logf (LOG_LOG, "user/system: %ld/%ld",
+ (long) (zh->tms2.tms_utime - zh->tms1.tms_utime),
+ (long) (zh->tms2.tms_stime - zh->tms1.tms_stime));
+
+ status->utime = (long) (zh->tms2.tms_utime - zh->tms1.tms_utime);
+ status->stime = (long) (zh->tms2.tms_stime - zh->tms1.tms_stime);
+#endif
+ return 0;
+}
+
+int zebra_repository_update (ZebraHandle zh, const char *path)
+{
+ ASSERTZH;
+ zh->errCode=0;
+ logf (LOG_LOG|LOG_API, "updating %s", path);
+ repositoryUpdate (zh, path);
+ return zh->errCode;
+}
+
+int zebra_repository_delete (ZebraHandle zh, const char *path)
+{
+ ASSERTZH;
+ zh->errCode=0;
+ logf (LOG_LOG|LOG_API, "deleting %s", path);
+ repositoryDelete (zh, path);
+ return zh->errCode;
+}
+
+int zebra_repository_show (ZebraHandle zh, const char *path)
+{
+ ASSERTZH;
+ yaz_log(LOG_API,"zebra_repository_show");
+ zh->errCode=0;
+ repositoryShow (zh, path);
+ return zh->errCode;
+}
+
+static int zebra_commit_ex (ZebraHandle zh, int clean_only)
+{
+ int seqno;
+ char val;
+ const char *rval;
+ BFiles bfs;
+ ASSERTZH;
+ zh->errCode=0;
+
+ if (!zh->res)
+ {
+ zh->errCode = 109;
+ return -1;
+ }
+ rval = res_get (zh->res, "shadow");
+ if (!rval)
+ {
+ logf (LOG_WARN, "Cannot perform commit");
+ logf (LOG_WARN, "No shadow area defined");
+ return 0;
+ }
+
+ zebra_lock_w (zh->lock_normal);
+ zebra_lock_r (zh->lock_shadow);
+
+ bfs = bfs_create (res_get (zh->res, "register"), zh->path_reg);
+
+ zebra_get_state (zh, &val, &seqno);
+
+ if (rval && *rval)
+ bf_cache (bfs, rval);
+ if (bf_commitExists (bfs))
+ {
+ if (clean_only)
+ zebra_set_state (zh, 'd', seqno);
+ else
+ {
+ zebra_set_state (zh, 'c', seqno);
+
+ logf (LOG_LOG, "commit start");
+ bf_commitExec (bfs);
+#ifndef WIN32
+ sync ();
+#endif
+ }
+ logf (LOG_LOG, "commit clean");
+ bf_commitClean (bfs, rval);
+ seqno++;
+ zebra_set_state (zh, 'o', seqno);
+ }
+ else
+ {
+ logf (LOG_LOG, "nothing to commit");
+ }
+ bfs_destroy (bfs);
+
+ zebra_unlock (zh->lock_shadow);
+ zebra_unlock (zh->lock_normal);
+ return 0;
+}
+
+int zebra_clean (ZebraHandle zh)
+{
+ yaz_log(LOG_API,"zebra_clean");
+ return zebra_commit_ex(zh, 1);
+}
+
+int zebra_commit (ZebraHandle zh)
+{
+ yaz_log(LOG_API,"zebra_commit");
+ return zebra_commit_ex(zh, 0);
+}
+
+int zebra_init (ZebraHandle zh)
+{
+ const char *rval;
+ BFiles bfs = 0;
+ ASSERTZH;
+ yaz_log(LOG_API,"zebra_init");
+ zh->errCode=0;
+
+ if (!zh->res)
+ {
+ zh->errCode = 109;
+ return -1;
+ }
+ rval = res_get (zh->res, "shadow");
+
+ bfs = bfs_create (res_get (zh->service->global_res, "register"),
+ zh->path_reg);
+ if (rval && *rval)
+ bf_cache (bfs, rval);
+
+ bf_reset (bfs);
+ bfs_destroy (bfs);
+ zebra_set_state (zh, 'o', 0);
+ return 0;
+}