public unsafe void RavenDB_15975() { using (var options = StorageEnvironmentOptions.ForPath(DataDir)) { options.Encryption.MasterKey = Sodium.GenerateRandomBuffer((int)Sodium.crypto_aead_xchacha20poly1305_ietf_keybytes()); using (var innerPager = LinuxTestUtils.GetNewPager(options, DataDir, "Raven.Voron")) { AbstractPager cryptoPager; using (cryptoPager = new CryptoPager(innerPager)) { using (var tx = new TempPagerTransaction(isWriteTransaction: true)) { var overflowSize = 4 * Constants.Storage.PageSize + 100; cryptoPager.EnsureContinuous(26, 5); var pagePointer = cryptoPager.AcquirePagePointerForNewPage(tx, 26, 5); var header = (PageHeader *)pagePointer; header->PageNumber = 26; header->Flags = PageFlags.Overflow; header->OverflowSize = overflowSize; Memory.Set(pagePointer + PageHeader.SizeOf, (byte)'X', overflowSize); } using (var tx = new TempPagerTransaction()) { var pagePointer = cryptoPager.AcquirePagePointer(tx, 26); // Making sure that the data was decrypted and still holds those 'X' chars Assert.True(pagePointer[PageHeader.SizeOf] == 'X'); Assert.True(pagePointer[666] == 'X'); Assert.True(pagePointer[1039] == 'X'); } } } } }
public unsafe void WriteAndReadPageUsingCryptoPager() { using (var options = StorageEnvironmentOptions.ForPath(DataDir)) { options.Encryption.MasterKey = Sodium.GenerateRandomBuffer((int)Sodium.crypto_aead_xchacha20poly1305_ietf_keybytes()); using (var innerPager = LinuxTestUtils.GetNewPager(options, DataDir, "Raven.Voron")) { AbstractPager cryptoPager; using (cryptoPager = new CryptoPager(innerPager)) { using (var tx = new TempPagerTransaction(isWriteTransaction: true)) { cryptoPager.EnsureContinuous(17, 1); // We're gonna try to read and write to page 17 var pagePointer = cryptoPager.AcquirePagePointerForNewPage(tx, 17, 1); var header = (PageHeader *)pagePointer; header->PageNumber = 17; header->Flags = PageFlags.Single | PageFlags.FixedSizeTreePage; Memory.Set(pagePointer + PageHeader.SizeOf, (byte)'X', Constants.Storage.PageSize - PageHeader.SizeOf); } using (var tx = new TempPagerTransaction()) { var pagePointer = cryptoPager.AcquirePagePointer(tx, 17); // Making sure that the data was decrypted and still holds those 'X' chars Assert.True(pagePointer[PageHeader.SizeOf] == 'X'); Assert.True(pagePointer[666] == 'X'); Assert.True(pagePointer[1039] == 'X'); } } } } }
public StreamInfo?GetStreamInfoForReporting(Slice key, out string tag) { tag = null; if (TryGetLastChunkDetailsForStream(key, out var lastChunk) == false) { return(null); } var canRemovePage = CanRemovePage(lastChunk.PageNumber); var page = _llt.GetPage(lastChunk.PageNumber); try { var info = (StreamInfo *)(page.DataPointer + lastChunk.ChunkSize); tag = GetStreamTag(info); return(new StreamInfo { TagSize = info->TagSize, TotalSize = info->TotalSize, Version = info->Version }); } finally { RemovePage(); } bool CanRemovePage(long pageNumber) { // this methods checks if page was not used elsewhere prior executing GetStreamInfoForReporting method // if yes then we cannot remove it to avoid releasing used memory var lltState = (IPagerLevelTransactionState)_llt; var states = lltState.CryptoPagerTransactionState; if (states == null) { return(false); // not encrypted } if (states.Count == 0) { return(true); // no states yet } foreach (var kvp in states) { var pagerStates = kvp.Value; if (pagerStates.TryGetValue(pageNumber, out _)) { return(false); } } return(true); } void RemovePage() { if (canRemovePage == false) { return; } var lltState = (IPagerLevelTransactionState)_llt; var states = lltState.CryptoPagerTransactionState; if (states == null || states.Count == 0) { return; } foreach (var kvp in states) { var pager = kvp.Key; var pagerStates = kvp.Value; if (pagerStates.TryGetValue(page.PageNumber, out var buffer) == false) { continue; } if (buffer.Pointer != page.Pointer) { continue; } if (CryptoPager.CanReturnBuffer(buffer) == false) { return; } _llt._pageLocator.Reset(page.PageNumber); pagerStates.RemoveBuffer(page.PageNumber); var cryptoPager = (CryptoPager)pager; cryptoPager.ReturnBuffer(buffer); return; } } }