void jnl_oper_user_ast(gd_region *reg) { jnl_private_control *jpc; uint4 status; int close_res; if (reg && reg->open) { jpc = FILE_INFO(reg)->s_addrs.jnl; if (SS_NORMAL != jpc->status) { assert(0 != jpc->jnllsb->lockid); status = gtm_deq(jpc->jnllsb->lockid, NULL, PSL$C_USER, 0); assert(SS$_NORMAL == status); jnl_send_oper(jpc, status); } if ((FALSE == jpc->qio_active) && (NOJNL != jpc->old_channel)) { JNL_FD_CLOSE(jpc->old_channel, close_res); /* sets csa->jnl->channel to NOJNL */ jpc->pini_addr = 0; jpc->jnllsb->lockid = 0; } } }
/* make sure that the journal file is available if appropriate */ uint4 jnl_ensure_open(void) { uint4 jnl_status; jnl_private_control *jpc; sgmnt_addrs *csa; sgmnt_data_ptr_t csd; boolean_t first_open_of_jnl, need_to_open_jnl; int close_res; # if defined(VMS) static const gds_file_id file; uint4 status; # endif error_def(ERR_JNLFILOPN); csa = cs_addrs; csd = csa->hdr; assert(csa->now_crit); jpc = csa->jnl; assert(NULL != jpc); assert(JNL_ENABLED(csa->hdr)); /* The goal is to change the code below to do only one JNL_FILE_SWITCHED(jpc) check instead of the additional * (NOJNL == jpc->channel) check done below. The assert below ensures that the NOJNL check can indeed * be subsumed by the JNL_FILE_SWITCHED check (with the exception of the source-server which has a special case that * needs to be fixed in C9D02-002241). Over time, this has to be changed to one check. */ assert((NOJNL != jpc->channel) || JNL_FILE_SWITCHED(jpc) || is_src_server); need_to_open_jnl = FALSE; jnl_status = 0; if (NOJNL == jpc->channel) { # ifdef VMS if (NOJNL != jpc->old_channel) { if (lib$ast_in_prog()) /* called from wcs_wipchk_ast */ jnl_oper_user_ast(gv_cur_region); else { status = sys$setast(DISABLE); jnl_oper_user_ast(gv_cur_region); if (SS$_WASSET == status) ENABLE_AST; } } # endif need_to_open_jnl = TRUE; } else if (JNL_FILE_SWITCHED(jpc)) { /* The journal file has been changed "on the fly"; close the old one and open the new one */ VMS_ONLY(assert(FALSE);) /* everyone having older jnl open should have closed it at time of switch in VMS */ JNL_FD_CLOSE(jpc->channel, close_res); /* sets jpc->channel to NOJNL */ need_to_open_jnl = TRUE; }
void heartbeat_timer(void) { gd_addr *addr_ptr; sgmnt_addrs *csa; jnl_private_control *jpc; gd_region *r_local, *r_top; int rc; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; /* It will take heartbeat_counter about 1014 years to overflow. */ heartbeat_counter++; DEBUG_ONLY(set_enospc_if_needed()); /* Check every 1 minute if we have an older generation journal file open. If so, close it. * The only exceptions are * a) The source server can have older generations open and they should not be closed. * b) If we are in the process of switching to a new journal file while we get interrupted * by the heartbeat timer, we should not close the older generation journal file * as it will anyways be closed by the mainline code. But identifying that we are in * the midst of a journal file switch is tricky so we check if the process is in * crit for this region and if so we skip the close this time and wait for the next heartbeat. */ if ((INTRPT_OK_TO_INTERRUPT == intrpt_ok_state) && !is_src_server && (0 == heartbeat_counter % NUM_HEARTBEATS_FOR_OLDERJNL_CHECK)) { for (addr_ptr = get_next_gdr(NULL); addr_ptr; addr_ptr = get_next_gdr(addr_ptr)) { for (r_local = addr_ptr->regions, r_top = r_local + addr_ptr->n_regions; r_local < r_top; r_local++) { if (!r_local->open || r_local->was_open) continue; if ((dba_bg != r_local->dyn.addr->acc_meth) && (dba_mm != r_local->dyn.addr->acc_meth)) continue; csa = &FILE_INFO(r_local)->s_addrs; if (csa->now_crit) continue; jpc = csa->jnl; if ((NULL != jpc) && (NOJNL != jpc->channel) && JNL_FILE_SWITCHED(jpc)) { /* The journal file we have as open is not the latest generation journal file. Close it */ /* Assert that we never have an active write on a previous generation journal file. */ assert(process_id != jpc->jnl_buff->io_in_prog_latch.u.parts.latch_pid); JNL_FD_CLOSE(jpc->channel, rc); /* sets jpc->channel to NOJNL */ jpc->pini_addr = 0; } } } } start_timer((TID)heartbeat_timer, HEARTBEAT_INTERVAL, heartbeat_timer, 0, NULL); }
/* make sure that the journal file is available if appropriate */ uint4 jnl_ensure_open(gd_region *reg, sgmnt_addrs *csa) { uint4 jnl_status; jnl_private_control *jpc; sgmnt_data_ptr_t csd; boolean_t first_open_of_jnl, need_to_open_jnl; int close_res; csd = csa->hdr; assert(csa->now_crit); jpc = csa->jnl; assert(&FILE_INFO(jpc->region)->s_addrs == csa); assert(&FILE_INFO(reg)->s_addrs == csa); assert(NULL != jpc); assert(JNL_ENABLED(csa->hdr)); /* The goal is to change the code below to do only one JNL_FILE_SWITCHED(jpc) check instead of the additional * (NOJNL == jpc->channel) check done below. The assert below ensures that the NOJNL check can indeed * be subsumed by the JNL_FILE_SWITCHED check (with the exception of the source-server which has a special case that * needs to be fixed in C9D02-002241). Over time, this has to be changed to one check. */ assert((NOJNL != jpc->channel) || JNL_FILE_SWITCHED(jpc) || is_src_server); need_to_open_jnl = FALSE; jnl_status = 0; if (NOJNL == jpc->channel) need_to_open_jnl = TRUE; else if (JNL_FILE_SWITCHED(jpc)) { /* The journal file has been changed "on the fly"; close the old one and open the new one */ JNL_FD_CLOSE(jpc->channel, close_res); /* sets jpc->channel to NOJNL */ need_to_open_jnl = TRUE; } if (need_to_open_jnl) { /* Whenever journal file get switch, reset the pini_addr and new_freeaddr. */ jpc->pini_addr = 0; jpc->new_freeaddr = 0; if (IS_GTCM_GNP_SERVER_IMAGE) gtcm_jnl_switched(reg); /* Reset pini_addr of all clients that had any older journal file open */ first_open_of_jnl = (0 == csa->nl->jnl_file.u.inode); jnl_status = jnl_file_open(reg, first_open_of_jnl); } # ifdef DEBUG else GTM_WHITE_BOX_TEST(WBTEST_JNL_FILE_OPEN_FAIL, jnl_status, ERR_JNLFILOPN); # endif assert((0 != jnl_status) || !JNL_FILE_SWITCHED(jpc) || (is_src_server && !JNL_ENABLED(csa) && REPL_WAS_ENABLED(csa))); return jnl_status; }