fis-gtm/sr_port/jnl_file_close.c

199 lines
6.1 KiB
C

/****************************************************************
* *
* Copyright 2003, 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_time.h"
#include "gtm_string.h"
#if defined(UNIX)
#include "gtm_unistd.h"
#include "aswp.h"
#include "lockconst.h"
#include "interlock.h"
#include "sleep_cnt.h"
#include "performcaslatchcheck.h"
#include "wcs_sleep.h"
#include "gt_timer.h"
#include "wbox_test_init.h"
#elif defined(VMS)
#include <rms.h>
#include <iodef.h>
#include <psldef.h>
#include <ssdef.h>
#include <efndef.h>
#include "iosb_disk.h"
#endif
#include "gdsroot.h"
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gdsbt.h"
#include "gdsblk.h"
#include "gdsfhead.h"
#include "filestruct.h"
#include "jnl.h"
#include "jnl_write.h"
#include "gtmio.h"
#include "repl_sp.h" /* F_CLOSE */
#include "iosp.h" /* for SS_NORMAL */
#include "ccp.h"
#include "send_msg.h"
#include "eintr_wrappers.h"
#include "anticipatory_freeze.h"
#ifdef UNIX
#include "wcs_clean_dbsync.h"
#endif
#if defined(VMS)
GBLREF short astq_dyn_avail;
static const unsigned short zero_fid[3];
#endif
#ifdef DEBUG
GBLREF boolean_t ok_to_UNWIND_in_exit_handling;
#endif
GBLREF jnl_gbls_t jgbl;
error_def(ERR_JNLCLOSE);
error_def(ERR_JNLFLUSH);
error_def(ERR_JNLFSYNCERR);
error_def(ERR_JNLWRERR);
error_def(ERR_PREMATEOF);
error_def(ERR_TEXT);
void jnl_file_close(gd_region *reg, bool clean, bool dummy)
{
jnl_file_header *header;
unsigned char hdr_base[REAL_JNL_HDR_LEN + MAX_IO_BLOCK_SIZE];
sgmnt_addrs *csa;
sgmnt_data_ptr_t csd;
jnl_private_control *jpc;
jnl_buffer_ptr_t jb;
struct_jrec_eof eof_record;
off_jnl_t eof_addr;
uint4 status, read_write_size;
int rc, save_errno, idx;
uint4 jnl_fs_block_size;
csa = &FILE_INFO(reg)->s_addrs;
csd = csa->hdr;
assert(!clean || csa->now_crit || (csd->clustered && (CCST_CLOSED == csa->nl->ccp_state)));
DEBUG_ONLY(
if (clean)
ASSERT_JNLFILEID_NOT_NULL(csa);
)
jpc = csa->jnl;
#if defined(UNIX)
if (csa->dbsync_timer)
CANCEL_DBSYNC_TIMER(csa);
#elif defined(VMS)
/* See comment about ordering of the two statements below, in similar code in gds_rundown */
if (csa->dbsync_timer)
{
csa->dbsync_timer = FALSE;
++astq_dyn_avail;
}
sys$cantim(csa, PSL$C_USER); /* cancel all dbsync-timers for this region */
#endif
if ((NULL == jpc) || (NOJNL == jpc->channel))
return;
jb = jpc->jnl_buff;
jnl_fs_block_size = jb->fs_block_size;
header = (jnl_file_header *)(ROUND_UP2((uintszofptr_t)hdr_base, jnl_fs_block_size));
if (clean)
{
if(!jgbl.mur_extract)
jnl_write_eof_rec(csa, &eof_record);
if (SS_NORMAL != (jpc->status = jnl_flush(reg)))
{
send_msg(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd),
ERR_TEXT, 2, RTS_ERROR_TEXT("Error with journal flush during jnl_file_close"),
jpc->status);
assert(FALSE);
rts_error(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd),
ERR_TEXT, 2, RTS_ERROR_TEXT("Error with journal flush during jnl_file_close"),
jpc->status);
}
assert(jb->dskaddr == jb->freeaddr);
UNIX_ONLY(jnl_fsync(reg, jb->dskaddr);)
UNIX_ONLY(assert(jb->freeaddr == jb->fsync_dskaddr);)
eof_addr = jb->freeaddr - EOF_RECLEN;
read_write_size = ROUND_UP2(REAL_JNL_HDR_LEN, jnl_fs_block_size);
assert((unsigned char *)header + read_write_size <= ARRAYTOP(hdr_base));
DO_FILE_READ(jpc->channel, 0, header, read_write_size, jpc->status, jpc->status2);
if (SYSCALL_SUCCESS(jpc->status))
{
if(!jgbl.mur_extract)
{
assert(header->end_of_data <= eof_addr);
header->end_of_data = eof_addr;
header->eov_timestamp = eof_record.prefix.time;
assert(header->eov_timestamp >= header->bov_timestamp);
header->eov_tn = eof_record.prefix.tn;
assert(header->eov_tn >= header->bov_tn);
header->end_seqno = eof_record.jnl_seqno;
}
# ifdef UNIX
for (idx = 0; idx < MAX_SUPPL_STRMS; idx++)
header->strm_end_seqno[idx] = csd->strm_reg_seqno[idx];
if (jgbl.forw_phase_recovery)
{ /* If MUPIP JOURNAL -ROLLBACK, might need some adjustment. See macro definition for comments */
MUR_ADJUST_STRM_REG_SEQNO_IF_NEEDED(csd, header->strm_end_seqno);
}
# endif
header->crash = FALSE;
JNL_DO_FILE_WRITE(csa, csd->jnl_file_name, jpc->channel,
0, header, read_write_size, jpc->status, jpc->status2);
if (SYSCALL_ERROR(jpc->status))
{
assert(FALSE);
rts_error(VARLSTCNT(5) ERR_JNLWRERR, 2, JNL_LEN_STR(csd), jpc->status);
}
UNIX_ONLY(
GTM_JNL_FSYNC(csa, jpc->channel, rc);
if (-1 == rc)
{
save_errno = errno;
send_msg(VARLSTCNT(9) ERR_JNLFSYNCERR, 2, JNL_LEN_STR(csd),
ERR_TEXT, 2, RTS_ERROR_TEXT("Error with fsync during jnl_file_close"), save_errno);
assert(FALSE);
rts_error(VARLSTCNT(9) ERR_JNLFSYNCERR, 2, JNL_LEN_STR(csd),
ERR_TEXT, 2, RTS_ERROR_TEXT("Error with fsync during jnl_file_close"), save_errno);
}
)
}
/* jnl_file_id should be nullified only after the jnl file header has been written to disk.
* Nullifying the jnl_file_id signals that the jnl file has been switched. The replication source server
* assumes that the jnl file has been completely written to disk (including the header) before the switch is
* signalled.
*/
NULLIFY_JNL_FILE_ID(csa);
jb->cycle++; /* increment shared cycle so all future callers of jnl_ensure_open recognize journal switch */
}
JNL_FD_CLOSE(jpc->channel, rc); /* sets jpc->channel to NOJNL */
#ifdef UNIX
GTM_WHITE_BOX_TEST(WBTEST_ANTIFREEZE_JNLCLOSE, rc, EIO);
#endif
jpc->cycle--; /* decrement cycle so jnl_ensure_open() knows to reopen the journal */
VMS_ONLY(jpc->qio_active = FALSE;)
jpc->pini_addr = 0;
if (clean && (SS_NORMAL != jpc->status || SS_NORMAL != rc))
{
status = jpc->status; /* jnl_send_oper resets jpc->status, so save it */
jnl_send_oper(jpc, ERR_JNLCLOSE);
DEBUG_ONLY(ok_to_UNWIND_in_exit_handling = TRUE;)
rts_error(VARLSTCNT(5) ERR_JNLCLOSE, 2, JNL_LEN_STR(csd), status);
}
}