Example #1
0
block_id bm_getfree(block_id orig_hint, boolean_t *blk_used, unsigned int cw_work, cw_set_element *cs, int *cw_depth_ptr)
{
	cw_set_element	*cs1;
	sm_uc_ptr_t	bmp;
	block_id	bml, hint, hint_cycled, hint_limit;
	block_id_ptr_t	b_ptr;
	int		cw_set_top, depth, lcnt;
	unsigned int	local_maps, map_size, n_decrements = 0, total_blks;
	trans_num	ctn;
	int4		free_bit, offset;
	uint4		space_needed;
	uint4		status;
	srch_blk_status	blkhist;

	total_blks = (dba_mm == cs_data->acc_meth) ? cs_addrs->total_blks : cs_addrs->ti->total_blks;
	if (orig_hint >= total_blks)		/* for TP, hint can be > total_blks */
		orig_hint = 1;
	hint = orig_hint;
	hint_cycled = DIVIDE_ROUND_UP(total_blks, BLKS_PER_LMAP);
	hint_limit = DIVIDE_ROUND_DOWN(orig_hint, BLKS_PER_LMAP);
	local_maps = hint_cycled + 2;	/* for (up to) 2 wraps */
	for (lcnt = 0; lcnt <= local_maps; lcnt++)
	{
		bml = bmm_find_free(hint / BLKS_PER_LMAP, (sm_uc_ptr_t)MM_ADDR(cs_data), local_maps);
		if ((NO_FREE_SPACE == bml) || (bml >= hint_cycled))
		{	/* if no free space or might have looped to original map, extend */
			if ((NO_FREE_SPACE != bml) && (hint_limit < hint_cycled))
			{
				hint_cycled = hint_limit;
				hint = 1;
				continue;
			}
			if (SS_NORMAL != (status = gdsfilext(cs_data->extension_size, total_blks)))
				return (status);
			if (dba_mm == cs_data->acc_meth)
				return (FILE_EXTENDED);
			hint = total_blks;
			total_blks = cs_addrs->ti->total_blks;
			hint_cycled = DIVIDE_ROUND_UP(total_blks, BLKS_PER_LMAP);
			local_maps = hint_cycled + 2;	/* for (up to) 2 wraps */
			/*
			 * note that you can make an optimization of not going back over the whole database and going over
			 * only the extended section. but since it is very unlikely that a free block won't be found
			 * in the extended section and the fact that we are starting from the extended section in either
			 * approach and the fact that we have a GTMASSERT to check that we don't have a lot of
			 * free blocks while doing an extend and the fact that it is very easy to make the change to do
			 * a full-pass, the full-pass solution is currently being implemented
			 */
			lcnt = -1;	/* allow it one extra pass to ensure that it can take advantage of the entension */
			n_decrements++;	/* used only for debugging purposes */
			continue;
		}
		bml *= BLKS_PER_LMAP;
		if (ROUND_DOWN2(hint, BLKS_PER_LMAP) != bml)
		{	/* not within requested map */
			if ((bml < hint) && (hint_cycled))	/* wrap? - second one should force an extend for sure */
				hint_cycled = (hint_limit < hint_cycled) ? hint_limit: 0;
			hint = bml + 1;				/* start at beginning */
		}
		if (ROUND_DOWN2(total_blks, BLKS_PER_LMAP) == bml)
			map_size = (total_blks - bml);
		else
			map_size = BLKS_PER_LMAP;
		if (0 != dollar_tlevel)
		{
			depth = cw_work;
			cw_set_top = *cw_depth_ptr;
			if (depth < cw_set_top)
				tp_get_cw(cs, cw_work, &cs1);
			for (; depth < cw_set_top;  depth++, cs1 = cs1->next_cw_set)
			{	/* do tp front to back because list is more efficient than tp_get_cw and forward pointers exist */
				if (bml == cs1->blk)
				{
					TRAVERSE_TO_LATEST_CSE(cs1);
					break;
				}
			}
			if (depth >= cw_set_top)
			{
				assert(cw_set_top == depth);
				depth = 0;
			}
		} else
		{
			for (depth = *cw_depth_ptr - 1; depth >= cw_work;  depth--)
			{	/* do non-tp back to front, because of adjacency */
				if (bml == (cs + depth)->blk)
				{
					cs1 = cs + depth;
					break;
				}
			}
			if (depth < cw_work)
			{
				assert(cw_work - 1 == depth);
				depth = 0;
			}
		}
		if (0 == depth)
		{
			ctn = cs_addrs->ti->curr_tn;
			if (!(bmp = t_qread(bml, (sm_int_ptr_t)&blkhist.cycle, &blkhist.cr)))
				return MAP_RD_FAIL;
			if ((BM_SIZE(BLKS_PER_LMAP) != ((blk_hdr_ptr_t)bmp)->bsiz) || (LCL_MAP_LEVL != ((blk_hdr_ptr_t)bmp)->levl))
			{
				assert(CDB_STAGNATE > t_tries);
				rdfail_detail = cdb_sc_badbitmap;
				return MAP_RD_FAIL;
			}
			offset = 0;
		} else
		{
			bmp = cs1->old_block;
			b_ptr = (block_id_ptr_t)(cs1->upd_addr);
			b_ptr += cs1->reference_cnt - 1;
			offset = *b_ptr + 1;
		}
		if (offset < map_size)
		{
			free_bit = bm_find_blk(offset, (sm_uc_ptr_t)bmp + sizeof(blk_hdr), map_size, blk_used);
			if (MAP_RD_FAIL == free_bit)
				return MAP_RD_FAIL;
		} else
			free_bit = NO_FREE_SPACE;
		if (NO_FREE_SPACE != free_bit)
			break;
		if ((hint = bml + BLKS_PER_LMAP) >= total_blks)		/* if map is full, start at 1st blk in next map */
		{	/* wrap - second one should force an extend for sure */
			hint = 1;
			if (hint_cycled)
				hint_cycled = (hint_limit < hint_cycled) ? hint_limit: 0;
		}
		if ((0 == depth) && (FALSE != cs_addrs->now_crit))	/* if it's from the cw_set, its state is murky */
			bit_clear(bml / BLKS_PER_LMAP, MM_ADDR(cs_data));	/* if crit, repair master map error */
	}
	/* If not in the final retry, it is possible that free_bit is >= map_size (e.g. if bitmap block gets recycled). */
	if (map_size <= (uint4)free_bit && CDB_STAGNATE <= t_tries)
	{	/* bad free bit */
		assert((NO_FREE_SPACE == free_bit) && (lcnt > local_maps));	/* All maps full, should have extended */
		GTMASSERT;
	}
	if (0 != depth)
	{
		b_ptr = (block_id_ptr_t)(cs1->upd_addr);
		b_ptr += cs1->reference_cnt++;
		*b_ptr = free_bit;
	} else
	{
		space_needed = (BLKS_PER_LMAP + 1) * sizeof(block_id);
		if (dollar_tlevel)
		{
			ENSURE_UPDATE_ARRAY_SPACE(space_needed);	/* have brackets for "if" for macros */
		}
		BLK_ADDR(b_ptr, space_needed, block_id);
		memset(b_ptr, 0, space_needed);
		*b_ptr = free_bit;
		blkhist.blk_num = bml;
		blkhist.buffaddr = bmp;	/* cycle and cr have already been assigned from t_qread */
		t_write_map(&blkhist, (uchar_ptr_t)b_ptr, ctn, 1); /* last parameter 1 is what cs->reference_cnt gets set to */
	}
	return bml + free_bit;
}
Example #2
0
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);
        )
    }
Example #3
0
void mupip_extend(void)
{
	unsigned short	r_len;
	char		regionname[MAX_RN_LEN];
	uint4		bplmap, bit_maps, blocks, i, old_total, total, status;
	int4		tblocks;
	int		fd;

	r_len = SIZEOF(regionname);
	if (cli_get_str("REG_NAME", regionname, &r_len) == FALSE)
		rts_error(VARLSTCNT(1) ERR_MUNODBNAME);
	if (cli_get_int("BLOCKS",&tblocks))
	{
		if (tblocks < 1)
		{
			util_out_print("!/BLOCKS too small, no extension done",TRUE);
			mupip_exit(ERR_MUNOACTION);
		}
		blocks = tblocks;
	} else
		blocks = (uint4)-1;
	gvinit();
	for (i = 0, gv_cur_region = gd_header->regions; i < gd_header->n_regions; i++, gv_cur_region++)
	{
		if (memcmp(gv_cur_region->rname, regionname, r_len) == 0)
			break;
	}
	if (i >= gd_header->n_regions)
	{
		gtm_putmsg(VARLSTCNT(4) ERR_NOREGION, 2, r_len, regionname);
		mupip_exit(ERR_MUNOACTION);
	}
	if ((dba_bg != gv_cur_region->dyn.addr->acc_meth) && (dba_mm != gv_cur_region->dyn.addr->acc_meth))
	{
		util_out_print("Can only EXTEND BG and MM databases",TRUE);
		mupip_exit(ERR_MUNOACTION);
	}
	if (reg_cmcheck(gv_cur_region))
	{
		util_out_print("!/Can't EXTEND region !AD across network",TRUE, REG_LEN_STR(gv_cur_region));
		mupip_exit(ERR_MUNOACTION);
	}
#	if !defined(MM_FILE_EXT_OK) && defined(UNIX)
	if (dba_mm == gv_cur_region->dyn.addr->acc_meth)
	{
		FILE_CNTL_INIT(gv_cur_region->dyn.addr);
		if (!STANDALONE(gv_cur_region))
		{
			util_out_print("Can't get standalone access to database file !AD with MM access method, no extension done.",
				TRUE, DB_LEN_STR(gv_cur_region));
			mupip_exit(ERR_MUNOACTION);
		}
		assert((FILE_INFO(gv_cur_region))->grabbed_access_sem); /* we should have standalone access */
	}
#	endif
	gvcst_init(gv_cur_region);
	if (gv_cur_region->was_open)
	{	/* This should not happen as extend works on only one region at a time, but handle for safety */
		gtm_putmsg(VARLSTCNT(4) ERR_DBOPNERR, 2, DB_LEN_STR(gv_cur_region));
		DB_IPCS_RESET(gv_cur_region);
		mupip_exit(ERR_MUNOACTION);
	}
	cs_addrs = &FILE_INFO(gv_cur_region)->s_addrs;
	cs_data = cs_addrs->hdr;
	if ((uint4)-1 == blocks)
	{
		if (cs_addrs->hdr->extension_size == 0)
		{
			util_out_print("The extension size on file !AD is zero, no extension done.",TRUE,
				DB_LEN_STR(gv_cur_region));
			DB_IPCS_RESET(gv_cur_region);
			mupip_exit(ERR_MUNOACTION);
		}
		blocks = cs_addrs->hdr->extension_size;
	}
	/* cannot extend for read_only database. */
	if (gv_cur_region->read_only)
	{
		gtm_putmsg(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region));
		DB_IPCS_RESET(gv_cur_region);
		mupip_exit(ERR_MUNOACTION);
	}
	switch(gv_cur_region->dyn.addr->acc_meth)
	{
		case dba_bg:
		case dba_mm:
			grab_crit(gv_cur_region);
			GRAB_UNFROZEN_CRIT(gv_cur_region, cs_addrs, cs_data);
			old_total = cs_addrs->ti->total_blks;
			if ((uint4)NO_FREE_SPACE == (status = gdsfilext(blocks, old_total)))
			{
				rel_crit(gv_cur_region);
				util_out_print("The extension failed on file !AD; check disk space and permissions.", TRUE,
					DB_LEN_STR(gv_cur_region));
				DB_IPCS_RESET(gv_cur_region);
				mupip_exit(ERR_MUNOACTION);
			} else
				assert(SS_NORMAL == status);
			total = cs_addrs->ti->total_blks;
			bplmap = cs_addrs->hdr->bplmap;
			bit_maps = DIVIDE_ROUND_UP(total, bplmap) - DIVIDE_ROUND_UP(old_total, bplmap);
			rel_crit(gv_cur_region);
			break;
		default:
			GTMASSERT;
	}
	util_out_print("Extension successful, file !AD extended by !UL blocks.  Total blocks = !UL.",TRUE,
		DB_LEN_STR(gv_cur_region), total - old_total - bit_maps, total - DIVIDE_ROUND_UP(total, bplmap));
	DB_IPCS_RESET(gv_cur_region); /* final cleanup (for successful case) before exit */
	mupip_exit(SS_NORMAL);
}