/**************************************************************** * * * 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 #include #include #include #include #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); } }