func()

in alloc.go [181:258]


func (a *allocator) fileCommitAlloc(st *allocCommitState) reason {
	const op = "txfile/commit-alloc-meta"

	if !st.updated {
		return nil
	}

	dataFreed := st.tx.data.freed.Regions()
	metaFreed := st.tx.meta.freed.Regions()

	// Predict number of meta pages required to store new freelist,
	// by iterating all region entries and take the potential encoding size
	// into account. As allocation might force a region from the data area
	// being moved (or split) into the meta area, we add more dummy region
	// with enforced max size. So the allocator can move pages between
	// meta and data if required.
	// This method over-estimates the number of required pages, as
	// we will have to allocate pages from the metaFree lists end
	// after the estimator finishes.
	prediction := prepareFreelistEncPagePrediction(freePageHeaderSize, a.pageSize)
	prediction.AddRegions(dataFreed)
	prediction.AddRegions(metaFreed)
	prediction.AddRegions(a.data.freelist.regions)
	prediction.AddRegions(a.meta.freelist.regions)
	if prediction.count > 0 {
		// only add extra pages if we need to write the meta page
		prediction.AddRegion(region{id: 1, count: math.MaxUint32})
		prediction.AddRegion(region{id: 1, count: math.MaxUint32})
	}

	// alloc regions for writing the new freelist
	var allocRegions regionList
	if n := prediction.count; n > 0 {
		allocRegions = a.MetaAllocator().AllocRegions(st.tx, n)
		if allocRegions == nil {
			return a.err(op).of(OutOfMemory).
				report("not enough space to allocate freelist meta pages")
		}
	}

	// Compute new freelist. As consecutive regions are merged the
	// resulting list might require less pages
	newDataList := mergeRegionLists(a.data.freelist.regions, dataFreed)
	newMetaList := mergeRegionLists(a.meta.freelist.regions, metaFreed)

	st.allocRegions = allocRegions

	dataEndMarker := a.data.endMarker
	metaEndMarker := a.meta.endMarker

	// Remove pages from end of overflow area from meta freelist + adjust end marker
	st.metaList, st.overflowFreed = releaseOverflowPages(newMetaList, a.maxPages, metaEndMarker)
	if st.overflowFreed > 0 {
		st.tx.stats.overflow.freed += st.overflowFreed

		newEnd := metaEndMarker - PageID(st.overflowFreed)
		if metaEndMarker > dataEndMarker { // shrink overflow area, which was allocated from data area
			dataEndMarker = newEnd
		}
		metaEndMarker = newEnd
	}

	// Remove pages from end of data area. Pages are removed from the data area
	// only if the file size has been decreased.
	st.dataList, st.dataFreed = releaseOverflowPages(newDataList, a.maxPages, dataEndMarker)
	if st.dataFreed > 0 {
		dataEndMarker -= PageID(st.dataFreed)
		if metaEndMarker >= dataEndMarker {
			metaEndMarker = dataEndMarker
		}
	}

	// Update new allocator end markers if regions have been removed from the free lists.
	st.dataEndMarker = dataEndMarker
	st.metaEndMarker = metaEndMarker

	return nil
}