// TODO: This should be part of buffer pool class. // Ideally page manager shouldn't keep track of in memory-disk mappings. private async Task RecordUsageAndEvict(ulong pageId, ITransaction tran) { ulong[] pageIdsToEvict = this.bufferPool.GetEvictionPolicy().RecordUsageAndEvict(pageId).ToArray(); foreach (ulong pageIdToEvict in pageIdsToEvict) { if (tran.AmIHoldingALock(pageIdToEvict, out LockTypeEnum heldLockType)) { // If this page is needed for myself don't release the lock. // Just ignore for now. continue; } using (Releaser lckReleaser = await tran.AcquireLockWithCallerOwnership(pageIdToEvict, LockTypeEnum.Exclusive).ConfigureAwait(false)) { logger.LogDebug($"Evicting page {pageIdToEvict}"); IPage pageToEvict = this.bufferPool.GetPage(pageIdToEvict); // Somebody came before us and evicted the page. if (pageToEvict == null) { continue; } await this.FlushPage(pageToEvict).ConfigureAwait(false); bufferPool.EvictPage(pageToEvict.PageId(), pageToEvict.GetBufferPoolToken()); logger.LogDebug($"Page {pageIdToEvict} evicted from buffer pool and flushed to the disk."); } } }
public async Task <IPage> AllocatePage(PageType pageType, ColumnInfo[] columnTypes, ulong prevPageId, ulong nextPageId, ulong pageId, ITransaction tran) { logger.LogDebug($"Allocating new page {pageId}"); IPage page; using Releaser releaser = await tran.AcquireLockWithCallerOwnership(pageId, LockTypeEnum.Exclusive).ConfigureAwait(false); (Memory <byte> memory, ulong token) = this.bufferPool.GetMemory(); page = pageType switch { PageType.StringPage => new StringOnlyPage(pageSize, pageId, prevPageId, nextPageId, tran), PageType.MixedPage => new MixedPage(pageSize, pageId, columnTypes, prevPageId, nextPageId, memory, token, tran), _ => throw new ArgumentException("Unknown page type") }; Interlocked.Increment(ref this.pageCount); if (prevPageId != PageManagerConstants.NullPageId) { tran.VerifyLock(prevPageId, LockTypeEnum.Exclusive); IPage prevPage = await GetPage(prevPageId, tran, pageType, columnTypes).ConfigureAwait(false); if (prevPage.NextPageId() != page.NextPageId()) { throw new ArgumentException("Breaking the link"); } // TODO: Set next page id needs to be logged as well... prevPage.SetNextPageId(page.PageId()); } if (nextPageId != PageManagerConstants.NullPageId) { IPage nextPage = await GetPage(nextPageId, tran, pageType, columnTypes).ConfigureAwait(false); if (nextPage.PrevPageId() != page.PrevPageId()) { throw new ArgumentException("breaking the link"); } nextPage.SetPrevPageId(page.PageId()); } await RecordUsageAndEvict(page.PageId(), tran).ConfigureAwait(false); bufferPool.AddPage(page); AddToAllocationMap(page); return(page); }