fis-gtm/sr_unix/gtmsource_seqno_init.c

200 lines
8.2 KiB
C
Raw Normal View History

/****************************************************************
* *
* Copyright 2006, 2012 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 "gtm_string.h"
#include "gtm_inet.h"
#include "gtm_fcntl.h"
#ifdef VMS
#include <descrip.h> /* Required for gtmsource.h */
#endif
#include "gdsroot.h"
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gdsbt.h"
#include "gdsfhead.h"
#include "filestruct.h"
#include "error.h"
#include "repl_msg.h"
#include "repl_shutdcode.h"
#include "gtmsource.h"
#include "jnl.h"
#include "gtmmsg.h"
#include "repl_instance.h"
GBLREF gd_addr *gd_header;
GBLREF jnlpool_addrs jnlpool;
GBLREF jnlpool_ctl_ptr_t jnlpool_ctl;
GBLREF repl_conn_info_t *this_side;
error_def(ERR_NOREPLCTDREG);
error_def(ERR_REPLINSTDBMATCH);
error_def(ERR_REPLINSTDBSTRM);
/* Find the start_jnl_seqno */
void gtmsource_seqno_init(boolean_t this_side_std_null_coll)
{
boolean_t is_supplementary;
gd_region *region_top, *reg;
int4 idx;
sgmnt_addrs *csa, *repl_csa;
sgmnt_data_ptr_t csd;
seq_num db_seqno, replinst_seqno, strm_db_seqno[MAX_SUPPL_STRMS], strm_inst_seqno, zqgblmod_seqno;
sm_uc_ptr_t gld_fn;
unix_db_info *udi;
/* Unix and VMS have different field names for now, but will both be soon changed to instfilename instead of gtmgbldir */
gld_fn = (sm_uc_ptr_t)jnlpool_ctl->jnlpool_id.instfilename;
zqgblmod_seqno = 0;
region_top = gd_header->regions + gd_header->n_regions;
db_seqno = 0;
replinst_seqno = jnlpool.repl_inst_filehdr->jnl_seqno;
/* The stream specific jnl seqnos are valid only if this is a supplementary instance. */
is_supplementary = jnlpool.repl_inst_filehdr->is_supplementary;
if (is_supplementary)
{ /* Since this is a supplementary instance, the 0th stream should be at least 1 (even if the db file header
* still says 0). The first update to that replicated database will set the strm_reg_seqno to a non-zero value.
* See repl_inst_create.c for similar code and comment on why this is needed for a supplementary instance.
* By a similar argument, streams 1 thru 15 also need to have seqno of at least 1 as that will be the seqno
* assigned for the next update which happens on that stream. This adjustment of seqno 0 to 1 avoids spurious
* ERR_REPLINSTDBSTRM errors further down in this module.
*/
for (idx = 0; idx < MAX_SUPPL_STRMS; idx++)
strm_db_seqno[idx] = 1;
}
for (reg = gd_header->regions; reg < region_top; reg++)
{
assert(reg->open);
csa = &FILE_INFO(reg)->s_addrs;
csd = csa->hdr;
if (REPL_ALLOWED(csd))
{
if (db_seqno < csd->reg_seqno)
db_seqno = csd->reg_seqno;
if (is_supplementary)
{
for (idx = 0; idx < MAX_SUPPL_STRMS; idx++)
{
if (strm_db_seqno[idx] < csd->strm_reg_seqno[idx])
strm_db_seqno[idx] = csd->strm_reg_seqno[idx];
}
}
if (zqgblmod_seqno < csd->zqgblmod_seqno)
zqgblmod_seqno = csd->zqgblmod_seqno;
}
}
if (0 == db_seqno)
{ /* No replicated region, or databases created with older * version of GTM */
gtm_putmsg(VARLSTCNT(5) ERR_NOREPLCTDREG, 3, LEN_AND_LIT("instance file"), gld_fn);
/* Error, has to shutdown all regions 'cos mupip needs exclusive access to turn replication on */
gtmsource_exit(ABNORMAL_SHUTDOWN);
}
/* Assert that the jnl seqno of the instance is greater than or equal to the start_seqno of the last histinfo record in the
* instance file. If this was not the case, a REPLINSTSEQORD error would have been issued in "jnlpool_init"
*/
assert(!jnlpool_ctl->last_histinfo_seqno || (replinst_seqno >= jnlpool_ctl->last_histinfo_seqno));
/* Check if jnl seqno in db and instance file match */
if (0 != replinst_seqno)
{
if (db_seqno != replinst_seqno)
{ /* Journal seqno from the databases does NOT match that stored in the replication instance file header. */
udi = FILE_INFO(jnlpool.jnlpool_dummy_reg);
gtm_putmsg(VARLSTCNT(6) ERR_REPLINSTDBMATCH, 4, LEN_AND_STR(udi->fn), &replinst_seqno, &db_seqno);
gtmsource_exit(ABNORMAL_SHUTDOWN);
}
if (is_supplementary)
{ /* Check that each of the potentially 16 stream seqnos are also identical between db and instance file */
for (idx = 0; idx < MAX_SUPPL_STRMS; idx++)
{
strm_inst_seqno = jnlpool.repl_inst_filehdr->strm_seqno[idx];
if (strm_inst_seqno && (strm_db_seqno[idx] != strm_inst_seqno))
{
udi = FILE_INFO(jnlpool.jnlpool_dummy_reg);
gtm_putmsg(VARLSTCNT(7) ERR_REPLINSTDBSTRM, 5, LEN_AND_STR(udi->fn),
&strm_inst_seqno, idx, &strm_db_seqno[idx]);
assert(FALSE);
gtmsource_exit(ABNORMAL_SHUTDOWN);
}
}
}
} else
{ /* Instance file header has no seqno values. Initialize it from the db file header. */
jnlpool.repl_inst_filehdr->jnl_seqno = db_seqno;
if (is_supplementary)
{ /* Initialize each of the potentially 16 stream seqnos from the db */
idx = 0;
jnlpool.repl_inst_filehdr->strm_seqno[idx] = strm_db_seqno[idx];
idx++;
/* For streams 1 thru 15, if the db seqno is at 1, it means that stream
* has no updates yet in this instance. In that case, keep the instance file
* header at seqno of 0 to avoid showing unused streams as being used.
* For stream 0 though, we use it always in case of a supplementary
* instance so initialize it even if it is to the seqno 1.
*/
for ( ; idx < MAX_SUPPL_STRMS; idx++)
{
assert(0 < strm_db_seqno[idx]);
jnlpool.repl_inst_filehdr->strm_seqno[idx] = (1 < strm_db_seqno[idx]) ? strm_db_seqno[idx] : 0;
}
}
}
/* At this point, we are guaranteed there is no other process attached to the journal pool (since our parent source
* server command is still waiting with the ftok lock for the pool to be initialized by this child). Even then it
* does not hurt to get the lock on the journal pool before updating fields in there.
*/
DEBUG_ONLY(repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;)
assert(!repl_csa->hold_onto_crit); /* so it is ok to invoke "grab_lock" and "rel_lock" unconditionally */
GRAB_LOCK(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK);
jnlpool_ctl->start_jnl_seqno = db_seqno;
jnlpool_ctl->jnl_seqno = db_seqno;
jnlpool_ctl->max_zqgblmod_seqno = zqgblmod_seqno;
jnlpool_ctl->prev_jnlseqno_time = 0;
if (is_supplementary)
{ /* Copy stream jnl seqno info from instance file header to jnlpool.
* From this point onwards, only the jnlpool will have uptodate values for strm_seqno.
* Therefore only that should be used by whoever wants to find out the current strm_seqno.
*/
for (idx = 0; idx < MAX_SUPPL_STRMS; idx++)
jnlpool.jnlpool_ctl->strm_seqno[idx] = jnlpool.repl_inst_filehdr->strm_seqno[idx];
}
/* Initialize details for this side of the replication connection. Do it while we still have the jnlpool lock. */
assert(this_side == &jnlpool_ctl->this_side);
this_side->proto_ver = REPL_PROTO_VER_THIS;
this_side->jnl_ver = JNL_VER_THIS;
this_side->is_std_null_coll = this_side_std_null_coll;
this_side->trigger_supported = GTMTRIG_ONLY(TRUE) NON_GTMTRIG_ONLY(FALSE);
/* The following 3 members make sense only if the other side of a replication connection is also known. Since
* this_side talks about the properties of this instance, these 3 dont make sense in this context. When a connection
* to the other side is made, each source server's gtmsource_local->remote_side will have these fields appropriately set.
*/
this_side->cross_endian = FALSE;
this_side->endianness_known = FALSE;
this_side->null_subs_xform = FALSE;
this_side->is_supplementary = is_supplementary;
rel_lock(jnlpool.jnlpool_dummy_reg);
DEBUG_ONLY(
/* Assert that seqno fields in "gtmsrc_lcl" array are within the instance journal seqno.
* This is taken care of in "mur_close_files".
*/
for (idx = 0; NUM_GTMSRC_LCL > idx; idx++)
{
if ('\0' != jnlpool.gtmsrc_lcl_array[idx].secondary_instname[0])
{
assert(jnlpool.gtmsrc_lcl_array[idx].resync_seqno <= db_seqno);
assert(jnlpool.gtmsrc_lcl_array[idx].connect_jnl_seqno <= db_seqno);
}
}
)
jnlpool.jnlpool_ctl->pool_initialized = TRUE; /* It is only now that the journal pool is completely initialized */
}