/* * GetPageWithFreeSpace - try to find a page in the given relation with * at least the specified amount of free space. * * If successful, return the block number; if not, return InvalidBlockNumber. * * The caller must be prepared for the possibility that the returned page * will turn out to have too little space available by the time the caller * gets a lock on it. In that case, the caller should report the actual * amount of free space available on that page and then try again (see * RecordAndGetPageWithFreeSpace). If InvalidBlockNumber is returned, * extend the relation. */ BlockNumber GetPageWithFreeSpace(Relation rel, Size spaceNeeded) { uint8 min_cat = fsm_space_needed_to_cat(spaceNeeded); return fsm_search(rel, min_cat); }
/* * RecordAndGetPageWithFreeSpace - update info about a page and try again. * * We provide this combo form to save some locking overhead, compared to * separate RecordPageWithFreeSpace + GetPageWithFreeSpace calls. There's * also some effort to return a page close to the old page; if there's a * page with enough free space on the same FSM page where the old one page * is located, it is preferred. * * For very small heap relations that don't have a FSM, we update the local * map to indicate we have tried a page, and return the next page to try. */ BlockNumber RecordAndGetPageWithFreeSpace(Relation rel, BlockNumber oldPage, Size oldSpaceAvail, Size spaceNeeded) { int old_cat; int search_cat; FSMAddress addr; uint16 slot; int search_slot; BlockNumber nblocks = InvalidBlockNumber; /* First try the local map, if it exists. */ if (FSM_LOCAL_MAP_EXISTS) { Assert((rel->rd_rel->relkind == RELKIND_RELATION || rel->rd_rel->relkind == RELKIND_TOASTVALUE) && fsm_local_map.map[oldPage] == FSM_LOCAL_AVAIL); fsm_local_map.map[oldPage] = FSM_LOCAL_NOT_AVAIL; return fsm_local_search(); } if (!fsm_allow_writes(rel, oldPage, InvalidBlockNumber, &nblocks)) { /* * If we have neither a local map nor a FSM, we probably just tried * the target block in the smgr relation entry and failed, so we'll * need to create the local map. */ fsm_local_set(rel, nblocks); return fsm_local_search(); } /* Normal FSM logic follows */ old_cat = fsm_space_avail_to_cat(oldSpaceAvail); search_cat = fsm_space_needed_to_cat(spaceNeeded); /* Get the location of the FSM byte representing the heap block */ addr = fsm_get_location(oldPage, &slot); search_slot = fsm_set_and_search(rel, addr, slot, old_cat, search_cat); /* * If fsm_set_and_search found a suitable new block, return that. * Otherwise, search as usual. */ if (search_slot != -1) return fsm_get_heap_blk(addr, search_slot); else return fsm_search(rel, search_cat); }
void fsm( event_t *evt ) { /* Start with the init loop. */ if (fsm_state == FSM_INIT) { fsm_init( evt ); return; } else if (fsm_state == FSM_ERR) { LED0_ON(); return; } /* Handle normal events. */ switch (evt->type) { case EVENT_TYPE_TIMER: if (evt->timer.timer == 0) { LED0_TOGGLE(); timer_start( 0, 500, NULL ); } else if (evt->timer.timer == 1) { if (fsm_state == FSM_SEARCH) fsm_search(); else if (fsm_state == FSM_RUN) fsm_run(); } break; case EVENT_TYPE_ADC: fsm_adcBuf[ fsm_adc ] = ADCL; fsm_adcBuf[ fsm_adc ] += ADCH<<8; /*printf( "adc %d: %u", fsm_adc, fsm_adcBuf[ fsm_adc ] );*/ fsm_adc = 1-fsm_adc; adc_start( fsm_adc ); break; default: break; } }
/* * RecordAndGetPageWithFreeSpace - update info about a page and try again. * * We provide this combo form to save some locking overhead, compared to * separate RecordPageWithFreeSpace + GetPageWithFreeSpace calls. There's * also some effort to return a page close to the old page; if there's a * page with enough free space on the same FSM page where the old one page * is located, it is preferred. */ BlockNumber RecordAndGetPageWithFreeSpace(Relation rel, BlockNumber oldPage, Size oldSpaceAvail, Size spaceNeeded) { int old_cat = fsm_space_avail_to_cat(oldSpaceAvail); int search_cat = fsm_space_needed_to_cat(spaceNeeded); FSMAddress addr; uint16 slot; int search_slot; /* Get the location of the FSM byte representing the heap block */ addr = fsm_get_location(oldPage, &slot); search_slot = fsm_set_and_search(rel, addr, slot, old_cat, search_cat); /* * If fsm_set_and_search found a suitable new___ block, return that. * Otherwise, search as usual. */ if (search_slot != -1) return fsm_get_heap_blk(addr, search_slot); else return fsm_search(rel, search_cat); }
/* * GetPageWithFreeSpace - try to find a page in the given relation with * at least the specified amount of free space. * * If successful, return the block number; if not, return InvalidBlockNumber. * * The caller must be prepared for the possibility that the returned page * will turn out to have too little space available by the time the caller * gets a lock on it. In that case, the caller should report the actual * amount of free space available on that page and then try again (see * RecordAndGetPageWithFreeSpace). If InvalidBlockNumber is returned, * extend the relation. * * For very small heap relations that don't have a FSM, we try every other * page before extending the relation. To keep track of which pages have * been tried, initialize a local in-memory map of pages. */ BlockNumber GetPageWithFreeSpace(Relation rel, Size spaceNeeded, bool check_fsm_only) { uint8 min_cat = fsm_space_needed_to_cat(spaceNeeded); BlockNumber target_block, nblocks; /* First try the FSM, if it exists. */ target_block = fsm_search(rel, min_cat); if (target_block == InvalidBlockNumber && (rel->rd_rel->relkind == RELKIND_RELATION || rel->rd_rel->relkind == RELKIND_TOASTVALUE) && !check_fsm_only) { nblocks = RelationGetNumberOfBlocks(rel); if (nblocks > HEAP_FSM_CREATION_THRESHOLD) { /* * If the FSM knows nothing of the rel, try the last page before * we give up and extend. This avoids one-tuple-per-page syndrome * during bootstrapping or in a recently-started system. */ target_block = nblocks - 1; } else if (nblocks > 0) { /* Create or update local map and get first candidate block. */ fsm_local_set(rel, nblocks); target_block = fsm_local_search(); } } return target_block; }