289 lines
8.3 KiB
C
289 lines
8.3 KiB
C
|
/****************************************************************
|
||
|
* *
|
||
|
* Copyright 2001, 2010 Fidelity Information Services, Inc *
|
||
|
* *
|
||
|
* This source code contains the intellectual property *
|
||
|
* of its copyright holder(s), and is made available *
|
||
|
* under a license. If you do not know the terms of *
|
||
|
* the license, please stop and do not read further. *
|
||
|
* *
|
||
|
****************************************************************/
|
||
|
|
||
|
#include "mdef.h"
|
||
|
|
||
|
#include <stddef.h> /* for offsetof() macro */
|
||
|
#include "gtm_ctype.h"
|
||
|
|
||
|
#include "mlkdef.h"
|
||
|
#include "gtm_string.h"
|
||
|
#include "subscript.h"
|
||
|
#include "gdsroot.h" /* for filestruct.h */
|
||
|
#include "gdsbt.h" /* for gdsfhead.h */
|
||
|
#include "gtm_facility.h" /* for fileinfo.h */
|
||
|
#include "fileinfo.h" /* for gdsfhead.h */
|
||
|
#include "gdsfhead.h" /* for filestruct.h */
|
||
|
#include "filestruct.h" /* for jnl.h */
|
||
|
#include "jnl.h"
|
||
|
#include "repl_dbg.h"
|
||
|
#include "copy.h"
|
||
|
#include "zshow.h"
|
||
|
#include "mvalconv.h"
|
||
|
#include "str2gvkey.h"
|
||
|
|
||
|
GBLREF char *ext_stop;
|
||
|
GBLREF gv_key *gv_currkey;
|
||
|
static boolean_t in_tp;
|
||
|
static int4 num_records;
|
||
|
|
||
|
/* callers please set up the proper condition-handlers */
|
||
|
/* expects a null-terminated ext_buff. does the equivalent but inverse of jnl2ext */
|
||
|
|
||
|
char *ext2jnlcvt(char *ext_buff, int4 ext_len, jnl_record *rec)
|
||
|
{
|
||
|
char *ext_next;
|
||
|
jnl_record *temp_rec;
|
||
|
|
||
|
temp_rec = rec;
|
||
|
for ( ; (NULL != (ext_next = strchr(ext_buff, '\n'))); )
|
||
|
{
|
||
|
*ext_next++ = '\0';
|
||
|
rec = (jnl_record *)ext2jnl(ext_buff, rec);
|
||
|
assert(0 == (INTPTR_T)rec % JNL_REC_START_BNDRY);
|
||
|
if (ext_stop == ext_buff)
|
||
|
break;
|
||
|
ext_buff = ext_next;
|
||
|
}
|
||
|
|
||
|
assert(rec != temp_rec);
|
||
|
ext_stop = ext_buff;
|
||
|
return (char *)rec;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* expects a single null-terminated ptr (equivalent to one line in the extract-file) */
|
||
|
|
||
|
char *ext2jnl(char *ptr, jnl_record *rec)
|
||
|
{
|
||
|
unsigned char *pool_save, ch, chtmp;
|
||
|
int keylength, keystate, len, i, reclen, temp_reclen;
|
||
|
bool keepgoing;
|
||
|
mstr src, des;
|
||
|
jnl_record *temp_rec;
|
||
|
muextract_type exttype;
|
||
|
enum jnl_record_type rectype;
|
||
|
jrec_suffix *suffix;
|
||
|
uint4 nodeflags;
|
||
|
DEBUG_ONLY(uint4 tcom_num = 0;)
|
||
|
|
||
|
ext_stop = ptr + strlen(ptr) + 1;
|
||
|
temp_rec = rec;
|
||
|
|
||
|
exttype = (muextract_type)MUEXTRACT_TYPE(ptr);
|
||
|
assert((exttype >= 0) && (exttype < MUEXT_MAX_TYPES));
|
||
|
|
||
|
switch(exttype)
|
||
|
{
|
||
|
case MUEXT_SET:
|
||
|
if (in_tp)
|
||
|
{
|
||
|
if (0 == num_records)
|
||
|
{
|
||
|
num_records++;
|
||
|
rec->prefix.jrec_type = JRT_TSET;
|
||
|
} else
|
||
|
rec->prefix.jrec_type = JRT_USET;
|
||
|
} else
|
||
|
rec->prefix.jrec_type = JRT_SET;
|
||
|
break;
|
||
|
|
||
|
case MUEXT_KILL:
|
||
|
if (in_tp)
|
||
|
{
|
||
|
if (0 == num_records)
|
||
|
{
|
||
|
num_records++;
|
||
|
rec->prefix.jrec_type = JRT_TKILL;
|
||
|
} else
|
||
|
rec->prefix.jrec_type = JRT_UKILL;
|
||
|
} else
|
||
|
rec->prefix.jrec_type = JRT_KILL;
|
||
|
break;
|
||
|
|
||
|
case MUEXT_ZKILL:
|
||
|
if (in_tp)
|
||
|
{
|
||
|
if (0 == num_records)
|
||
|
{
|
||
|
num_records++;
|
||
|
rec->prefix.jrec_type = JRT_TZKILL;
|
||
|
} else
|
||
|
rec->prefix.jrec_type = JRT_UZKILL;
|
||
|
} else
|
||
|
rec->prefix.jrec_type = JRT_ZKILL;
|
||
|
break;
|
||
|
|
||
|
# ifdef GTM_TRIGGER
|
||
|
case MUEXT_ZTWORM:
|
||
|
if (in_tp)
|
||
|
{
|
||
|
if (0 == num_records)
|
||
|
{
|
||
|
num_records++;
|
||
|
rec->prefix.jrec_type = JRT_TZTWORM;
|
||
|
} else
|
||
|
rec->prefix.jrec_type = JRT_UZTWORM;
|
||
|
} else
|
||
|
GTMASSERT; /* ZTWORMHOLE should always been seen only inside a TP fence */
|
||
|
break;
|
||
|
case MUEXT_ZTRIG:
|
||
|
if (in_tp)
|
||
|
{
|
||
|
if (0 == num_records)
|
||
|
{
|
||
|
num_records++;
|
||
|
rec->prefix.jrec_type = JRT_TZTRIG;
|
||
|
} else
|
||
|
rec->prefix.jrec_type = JRT_UZTRIG;
|
||
|
} else
|
||
|
GTMASSERT; /* ZTRIGGER should always been seen only inside a TP fence */
|
||
|
break;
|
||
|
# endif
|
||
|
|
||
|
case MUEXT_TSTART:
|
||
|
in_tp = TRUE;
|
||
|
num_records = 0;
|
||
|
return (char *)rec;
|
||
|
break;
|
||
|
|
||
|
case MUEXT_TCOMMIT:
|
||
|
rec->prefix.jrec_type = JRT_TCOM;
|
||
|
DEBUG_ONLY(
|
||
|
/* External filter format has only ONE TSTART..TCOM. The journal record received from the external filter
|
||
|
* SHOULD also have only ONE TSTART..TCOM
|
||
|
*/
|
||
|
tcom_num++;
|
||
|
assert(1 == tcom_num);
|
||
|
)
|
||
|
rec->jrec_tcom.num_participants = 1; /* Only ONE TSTART..TCOM in the external filter format */
|
||
|
in_tp = FALSE;
|
||
|
break;
|
||
|
|
||
|
case MUEXT_PINI:
|
||
|
case MUEXT_PFIN:
|
||
|
case MUEXT_EOF:
|
||
|
case MUEXT_ZTSTART:
|
||
|
case MUEXT_ZTCOMMIT:
|
||
|
assert(FALSE);
|
||
|
ext_stop = ptr;
|
||
|
return (char *)rec;
|
||
|
break;
|
||
|
|
||
|
case MUEXT_NULL:
|
||
|
rec->prefix.jrec_type = JRT_NULL;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
assert(FALSE);
|
||
|
ext_stop = ptr;
|
||
|
return (char *)rec;
|
||
|
break;
|
||
|
}
|
||
|
rectype = (enum jnl_record_type)rec->prefix.jrec_type;
|
||
|
ptr = strtok(ptr, "\\"); /* get the rec-type field */
|
||
|
assert(NULL != ptr);
|
||
|
ptr = strtok(NULL, "\\"); /* get the time field */
|
||
|
assert(NULL != ptr);
|
||
|
ptr = strtok(NULL, "\\"); /* get the tn field */
|
||
|
assert(NULL != ptr);
|
||
|
rec->prefix.tn = asc2i((uchar_ptr_t)ptr, STRLEN(ptr));
|
||
|
ptr = strtok(NULL, "\\"); /* get the pid field */
|
||
|
assert(NULL != ptr);
|
||
|
ptr = strtok(NULL, "\\"); /* get the client pid field */
|
||
|
assert(NULL != ptr);
|
||
|
ptr = strtok(NULL, "\\"); /* get the token or jnl_seqno */
|
||
|
assert(NULL != ptr);
|
||
|
rec->jrec_null.jnl_seqno = asc2l((uchar_ptr_t)ptr,STRLEN(ptr));
|
||
|
|
||
|
switch(exttype)
|
||
|
{
|
||
|
case MUEXT_NULL:
|
||
|
rec->jrec_null.prefix.forwptr = rec->jrec_null.suffix.backptr = NULL_RECLEN;
|
||
|
rec->jrec_null.suffix.suffix_code = JNL_REC_SUFFIX_CODE;
|
||
|
return ((char_ptr_t)rec) + NULL_RECLEN;
|
||
|
case MUEXT_TCOMMIT:
|
||
|
ptr = strtok(NULL, "\\"); /* get the participants */
|
||
|
ptr = strtok(NULL, "\\"); /* get the jnl_tid */
|
||
|
rec->jrec_tcom.jnl_tid[0] = 0;
|
||
|
if (NULL != ptr)
|
||
|
strcpy(rec->jrec_tcom.jnl_tid, ptr);
|
||
|
num_records = 0;
|
||
|
rec->jrec_tcom.prefix.forwptr = rec->jrec_tcom.suffix.backptr = TCOM_RECLEN;
|
||
|
rec->jrec_tcom.suffix.suffix_code = JNL_REC_SUFFIX_CODE;
|
||
|
return ((char_ptr_t)rec) + TCOM_RECLEN;
|
||
|
}
|
||
|
assert(IS_SET_KILL_ZKILL_ZTRIG_ZTWORM(rectype));
|
||
|
ptr = strtok(NULL, "\\"); /* get the update_num field */
|
||
|
assert(NULL != ptr);
|
||
|
assert(OFFSETOF(struct_jrec_upd, update_num) == OFFSETOF(struct_jrec_ztworm, update_num));
|
||
|
rec->jrec_set_kill.update_num = asc2i((uchar_ptr_t)ptr, STRLEN(ptr));
|
||
|
if (MUEXT_ZTWORM != exttype)
|
||
|
{
|
||
|
ptr = strtok(NULL, "\\"); /* get the nodeflags field */
|
||
|
assert(NULL != ptr);
|
||
|
rec->jrec_set_kill.mumps_node.nodeflags = asc2i((uchar_ptr_t)ptr, STRLEN(ptr));
|
||
|
}
|
||
|
ptr += (strlen(ptr) + 1); /* get the key-value and data also; can't use strtok since there might be '\\' in the subscript */
|
||
|
assert(NULL != ptr);
|
||
|
if (MUEXT_ZTWORM != exttype)
|
||
|
{
|
||
|
assert(IS_SET_KILL_ZKILL_ZTRIG(rectype));
|
||
|
len = STRLEN(ptr);
|
||
|
keylength = zwrkeylength(ptr, len); /* determine length of key */
|
||
|
|
||
|
REPL_DPRINT2("ext2jnl source:KEY=DATA:%s\n", ptr);
|
||
|
assert(keylength <= len);
|
||
|
str2gvkey_nogvfunc(ptr, keylength, gv_currkey);
|
||
|
rec->jrec_set_kill.mumps_node.length = gv_currkey->end;
|
||
|
memcpy(rec->jrec_set_kill.mumps_node.text, gv_currkey->base, gv_currkey->end);
|
||
|
temp_reclen = (int)(FIXED_UPD_RECLEN + rec->jrec_set_kill.mumps_node.length + SIZEOF(jnl_str_len_t));
|
||
|
if (IS_KILL_ZKILL(rectype))
|
||
|
{
|
||
|
temp_reclen += JREC_SUFFIX_SIZE;
|
||
|
reclen = ROUND_UP2(temp_reclen, JNL_REC_START_BNDRY);
|
||
|
memset((char_ptr_t)rec + temp_reclen - JREC_SUFFIX_SIZE, 0, reclen - temp_reclen);
|
||
|
suffix = (jrec_suffix *)((char_ptr_t)rec + reclen - JREC_SUFFIX_SIZE);
|
||
|
rec->prefix.forwptr = suffix->backptr = reclen;
|
||
|
suffix->suffix_code = JNL_REC_SUFFIX_CODE;
|
||
|
return (char_ptr_t)rec + reclen;
|
||
|
}
|
||
|
/* we have to get the data value now */
|
||
|
src.len = len - keylength - 1;
|
||
|
src.addr = ptr + (keylength + 1);
|
||
|
} else
|
||
|
{ /* ZTWORMHOLE */
|
||
|
assert(IS_ZTWORM(rectype));
|
||
|
src.addr = ptr;
|
||
|
src.len = STRLEN(ptr);
|
||
|
temp_reclen = (int)(FIXED_ZTWORM_RECLEN);
|
||
|
}
|
||
|
des.len = 0;
|
||
|
des.addr = (char_ptr_t)rec + temp_reclen + SIZEOF(jnl_str_len_t);
|
||
|
REPL_DPRINT3("ext2jnl JNL Format (before zwr2format): src : Len %d :: DATA:%s\n", src.len, src.addr);
|
||
|
REPL_DPRINT3("ext2jnl JNL Format (before zwr2format): des : Len %d :: DATA:%s\n", des.len, des.addr);
|
||
|
if (!zwr2format(&src, &des))
|
||
|
{
|
||
|
assert(FALSE);
|
||
|
return (char_ptr_t)rec;
|
||
|
}
|
||
|
REPL_DPRINT3("ext2jnl JNL Format : src : Len %d :: DATA:%s\n", src.len, src.addr);
|
||
|
REPL_DPRINT3("ext2jnl JNL Format : des : Len %d :: DATA:%s\n", des.len, des.addr);
|
||
|
PUT_MSTR_LEN((char_ptr_t)rec + temp_reclen, des.len);
|
||
|
temp_reclen += SIZEOF(jnl_str_len_t) + des.len + JREC_SUFFIX_SIZE;
|
||
|
reclen = ROUND_UP2(temp_reclen, JNL_REC_START_BNDRY);
|
||
|
memset((char_ptr_t)rec + temp_reclen - JREC_SUFFIX_SIZE, 0, reclen - temp_reclen);
|
||
|
suffix = (jrec_suffix *)((char_ptr_t)rec + reclen - JREC_SUFFIX_SIZE);
|
||
|
rec->prefix.forwptr = suffix->backptr = reclen;
|
||
|
suffix->suffix_code = JNL_REC_SUFFIX_CODE;
|
||
|
return (char_ptr_t)rec + reclen;
|
||
|
}
|