200 lines
8.2 KiB
C
200 lines
8.2 KiB
C
/****************************************************************
|
|
* *
|
|
* 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 */
|
|
}
|