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); }