199 lines
6.1 KiB
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);
|
|
}
|
|
}
|