uint4 mur_block_count_correct(reg_ctl_list *rctl) { gtm_uint64_t native_size, size; sgmnt_data_ptr_t mu_data; int4 mu_int_ovrhd; uint4 total_blks; uint4 status; uint4 new_bit_maps, bplmap, new_blocks, tmpcnt; enum db_acc_method acc_meth; MUR_CHANGE_REG(rctl); mu_data = cs_data; acc_meth = mu_data->acc_meth; switch (acc_meth) { case dba_bg: case dba_mm: mu_int_ovrhd = (int4)DIVIDE_ROUND_UP(SIZEOF_FILE_HDR(mu_data) + mu_data->free_space, DISK_BLOCK_SIZE); break; default: assertpro(FALSE && acc_meth); } mu_int_ovrhd += 1; assert(mu_int_ovrhd == mu_data->start_vbn); size = mu_int_ovrhd + (off_t)(mu_data->blk_size / DISK_BLOCK_SIZE) * mu_data->trans_hist.total_blks; native_size = gds_file_size(gv_cur_region->dyn.addr->file_cntl); /* In the following tests, the EOF block should always be 1 greater than the actual size of the file. * This is due to the GDS being allocated in even DISK_BLOCK_SIZE-byte blocks. */ if (native_size && (size < native_size)) { total_blks = (dba_mm == acc_meth) ? cs_addrs->total_blks : cs_addrs->ti->total_blks; if (JNL_ENABLED(cs_addrs)) cs_addrs->jnl->pini_addr = 0; /* Stop simulation of GTM process journal record writing (if any active)*/ /* If journaling, gdsfilext will need to write an inctn record. The timestamp of that journal record will * need to be adjusted to the current system time to reflect that it is recovery itself writing that record * instead of simulating GT.M activity. Since the variable jgbl.dont_reset_gbl_jrec_time is still set, gdsfilext * will NOT modify jgbl.gbl_jrec_time. Temporarily reset it to allow for adjustments to gbl_jrec_time. */ assert(jgbl.dont_reset_gbl_jrec_time); jgbl.dont_reset_gbl_jrec_time = FALSE; /* Calculate the number of blocks to add based on the difference between the real file size and the file size * computed from the header->total_blks. Takes into account that gdsfilext() will automatically add new_bit_maps * to the amount of blocks we request. */ bplmap = cs_data->bplmap; new_blocks = (native_size - size)/(mu_data->blk_size / DISK_BLOCK_SIZE); new_bit_maps = DIVIDE_ROUND_UP(total_blks + new_blocks, bplmap) - DIVIDE_ROUND_UP(total_blks, bplmap); tmpcnt = new_blocks - new_bit_maps; /* Call GDSFILEXT only if the no of blocks by which DB needs to be extended is not '0' since GDSFILEXT() treats * extension by count 0 as unavailability of space(NO_FREE_SPACE error). And in the following case, tmpcnt could * be '0' on AIX because in MM mode AIX increases the native_size to the nearest multiple of OS_PAGE_SIZE. * And this increase could be less than GT.M block size.*/ if (tmpcnt && SS_NORMAL != (status = GDSFILEXT(new_blocks - new_bit_maps, total_blks, TRANS_IN_PROG_FALSE))) { jgbl.dont_reset_gbl_jrec_time = TRUE; return (status); } jgbl.dont_reset_gbl_jrec_time = TRUE; # ifdef DEBUG /* Check that the filesize and blockcount in the fileheader match now after the extend */ size = mu_int_ovrhd + (off_t)(mu_data->blk_size / DISK_BLOCK_SIZE) * mu_data->trans_hist.total_blks; native_size = gds_file_size(gv_cur_region->dyn.addr->file_cntl); ALIGN_DBFILE_SIZE_IF_NEEDED(size, native_size); assert(size == native_size); # endif } return SS_NORMAL; }
uint4 mur_block_count_correct(reg_ctl_list *rctl) { unsigned int native_size, size; sgmnt_data_ptr_t mu_data; int4 mu_int_ovrhd; uint4 total_blks; uint4 status; uint4 new_bit_maps, bplmap, new_blocks; MUR_CHANGE_REG(rctl); mu_data = cs_data; switch (mu_data->acc_meth) { default: GTMASSERT; break; #if defined(VMS) && defined(GT_CX_DEF) case dba_bg: /* necessary to do calculation in this manner to prevent double rounding causing an error */ if (mu_data->unbacked_cache) mu_int_ovrhd = DIVIDE_ROUND_UP(SIZEOF_FILE_HDR(mu_data) + mu_data->free_space + mu_data->lock_space_size, DISK_BLOCK_SIZE); else mu_int_ovrhd = DIVIDE_ROUND_UP(SIZEOF_FILE_HDR(mu_data) + BT_SIZE(mu_data) + mu_data->free_space + mu_data->lock_space_size, DISK_BLOCK_SIZE); break; #else case dba_bg: #endif case dba_mm: mu_int_ovrhd = (int4)DIVIDE_ROUND_UP(SIZEOF_FILE_HDR(mu_data) + mu_data->free_space, DISK_BLOCK_SIZE); break; } mu_int_ovrhd += 1; assert(mu_int_ovrhd == mu_data->start_vbn); size = mu_int_ovrhd + (mu_data->blk_size / DISK_BLOCK_SIZE) * mu_data->trans_hist.total_blks; native_size = gds_file_size(gv_cur_region->dyn.addr->file_cntl); /* In the following tests, the EOF block should always be 1 greater than the actual size of the file. * This is due to the GDS being allocated in even DISK_BLOCK_SIZE-byte blocks. */ if (native_size && (size < native_size)) { total_blks = (dba_mm == mu_data->acc_meth) ? cs_addrs->total_blks : cs_addrs->ti->total_blks; if (JNL_ENABLED(cs_addrs)) cs_addrs->jnl->pini_addr = 0; /* Stop simulation of GTM process journal record writing (if any active)*/ /* If journaling, gdsfilext will need to write an inctn record. The timestamp of that journal record will * need to be adjusted to the current system time to reflect that it is recovery itself writing that record * instead of simulating GT.M activity. Since the variable jgbl.dont_reset_gbl_jrec_time is still set, gdsfilext * will NOT modify jgbl.gbl_jrec_time. Temporarily reset it to allow for adjustments to gbl_jrec_time. */ assert(jgbl.dont_reset_gbl_jrec_time); jgbl.dont_reset_gbl_jrec_time = FALSE; /* Calculate the number of blocks to add based on the difference between the real file size and the file size * computed from the header->total_blks. Takes into account that gdsfilext() will automatically add new_bit_maps * to the amount of blocks we request. */ bplmap = cs_data->bplmap; new_blocks = (native_size - size)/(mu_data->blk_size / DISK_BLOCK_SIZE); new_bit_maps = DIVIDE_ROUND_UP(total_blks + new_blocks, bplmap) - DIVIDE_ROUND_UP(total_blks, bplmap); if (SS_NORMAL != (status = gdsfilext(new_blocks - new_bit_maps, total_blks))) { jgbl.dont_reset_gbl_jrec_time = TRUE; return (status); } jgbl.dont_reset_gbl_jrec_time = TRUE; DEBUG_ONLY( /* Check that the filesize and blockcount in the fileheader match now after the extend */ size = mu_int_ovrhd + (mu_data->blk_size / DISK_BLOCK_SIZE) * mu_data->trans_hist.total_blks; native_size = gds_file_size(gv_cur_region->dyn.addr->file_cntl); assert(size == native_size); ) }
void recover_truncate(sgmnt_addrs *csa, sgmnt_data_ptr_t csd, gd_region* reg) { char *err_msg; uint4 old_total, cur_total, new_total; off_t old_size, cur_size, new_size; int ftrunc_status, status; unix_db_info *udi; int semval; if (NULL != csa->nl && csa->nl->trunc_pid && !is_proc_alive(csa->nl->trunc_pid, 0)) csa->nl->trunc_pid = 0; if (!csd->before_trunc_total_blks) return; assert((GDSVCURR == csd->desired_db_format) && (csd->blks_to_upgrd == 0) && (dba_mm != csd->acc_meth)); /* If called from db_init, assure we've grabbed the access semaphor and are the only process attached to the database. * Otherwise, we should have crit when called from wcs_recover. */ udi = FILE_INFO(reg); assert((udi->grabbed_access_sem && (1 == (semval = semctl(udi->semid, 1, GETVAL)))) || csa->now_crit); /* Interrupted truncate scenario */ if (NULL != csa->nl) csa->nl->root_search_cycle++; old_total = csd->before_trunc_total_blks; /* Pre-truncate total_blks */ old_size = (off_t)SIZEOF_FILE_HDR(csd) /* Pre-truncate file size (in bytes) */ + (off_t)old_total * csd->blk_size + DISK_BLOCK_SIZE; cur_total = csa->ti->total_blks; /* Actual total_blks right now */ cur_size = (off_t)gds_file_size(reg->dyn.addr->file_cntl) * DISK_BLOCK_SIZE; /* Actual file size right now (in bytes) */ new_total = csd->after_trunc_total_blks; /* Post-truncate total_blks */ new_size = old_size - (off_t)(old_total - new_total) * csd->blk_size; /* Post-truncate file size (in bytes) */ /* We don't expect FTRUNCATE to leave the file size in an 'in between' state, hence the assert below. */ assert(old_size == cur_size || new_size == cur_size); if (new_total == cur_total && old_size == cur_size) { /* Crash after reducing total_blks, before successful FTRUNCATE. Complete the FTRUNCATE here. */ DBGEHND((stdout, "DBG:: recover_truncate() -- completing truncate, old_total = [%lu], cur_total = [%lu]\n", old_total, new_total)); assert(csd->before_trunc_free_blocks >= DELTA_FREE_BLOCKS(old_total, new_total)); csa->ti->free_blocks = csd->before_trunc_free_blocks - DELTA_FREE_BLOCKS(old_total, new_total); clear_cache_array(csa, csd, reg, new_total, old_total); WRITE_EOF_BLOCK(reg, csd, new_total, status); if (status != 0) { err_msg = (char *)STRERROR(errno); rts_error(VARLSTCNT(6) ERR_MUTRUNCERROR, 4, REG_LEN_STR(reg), LEN_AND_STR(err_msg)); return; } FTRUNCATE(FILE_INFO(reg)->fd, new_size, ftrunc_status); if (ftrunc_status != 0) { err_msg = (char *)STRERROR(errno); rts_error(VARLSTCNT(6) ERR_MUTRUNCERROR, 4, REG_LEN_STR(reg), LEN_AND_STR(err_msg)); return; } } else { /* Crash before even changing csa->ti->total_blks OR after successful FTRUNCATE */ /* In either case, the db file is in a consistent state, so no need to do anything further */ assert((old_total == cur_total && old_size == cur_size) || (new_total == cur_total && new_size == cur_size)); if (!((old_total == cur_total && old_size == cur_size) || (new_total == cur_total && new_size == cur_size))) { rts_error(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(reg)); } } csd->before_trunc_total_blks = 0; /* indicate CONSISTENT */ }