public void CouldAddNextChunkBeforeCompleted() { var path = TestUtils.GetPath(); var processConfig = new ProcessConfig(path); StartupConfig.StreamLogBufferPoolFlags = LMDBEnvironmentFlags.NoSync; StartupConfig.StreamBlockIndexFlags = LMDBEnvironmentFlags.NoSync; var slm = new StreamLogManager(processConfig, "CouldAddNextChunk", null, 512, true, true); var bufferPool = slm.BufferPool; var blockIndex = slm.BlockIndex; var streamId = (StreamLogId)42; short valueSize = 8; var state = slm.StateStorage.GetState(streamId); state.CheckInit(streamId, 8, SerializationFormat.Binary); var sl = new StreamLog(slm, state, textId: "test_stream"); var count = 100; SharedMemory currentBuffer = null; using (Benchmark.Run("AddNext (KOPS)", count * 1000)) { var version = 1UL; var block = blockIndex.RentNextWritableBlock(sl, minimumLength: 1, version, default); // var slc = new StreamBlock(buffer.RetainChunkMemory(false), streamId, valueSize, 1); var firstBufferRef = block.SharedMemory.BufferRef; for (int i = 0; i < count; i++) { version = (ulong)i + 1; if (!block.Claim(version, 8).IsValid) { Assert.Fail("!slc.Claim(version, 8).IsValid"); } block.Commit(); var bufferRef = block.SharedMemory.BufferRef; blockIndex.PrepareNextWritableStreamBlock(sl, length: 1); blockIndex.PrepareNextWritableStreamBlock(sl, length: 1); block.Complete(); block = blockIndex.RentNextWritableBlock(sl, minimumLength: 1, version + 1, default); var bufferRef1 = block.SharedMemory.BufferRef; // As if someone has created the next buffer before the second call, forget the first call block.DisposeFree(); block = blockIndex.RentNextWritableBlock(sl, minimumLength: 1, version + 1, default); var bufferRef2 = block.SharedMemory.BufferRef; if (block.SharedMemory.ReferenceCount != 2) { Assert.Fail($"buffer.RefCount {block.SharedMemory.ReferenceCount} != 1"); } if (bufferRef1 != bufferRef2) { Assert.Fail($"bufferRef1 {bufferRef1} != bufferRef2 {bufferRef2}"); } block.Complete(); var nextVersion = block.NextVersion; block.DisposeFree(); blockIndex.PrepareNextWritableStreamBlock(sl, length: 1); blockIndex.PrepareNextWritableStreamBlock(sl, length: 1); // block = new StreamBlock(block.SharedMemory.RetainBlockMemory(false), streamId, valueSize, nextVersion); block = blockIndex.RentNextWritableBlock(sl, minimumLength: 1, nextVersion, default); } if (!block.Claim(version + 1, 8).IsValid) { Assert.Fail("!slc.Claim(version, 8).IsValid"); } block.Commit(); block.Complete(); block = blockIndex.RentNextWritableBlock(sl, minimumLength: 1, block.NextVersion, default); Assert.AreEqual(2, block.SharedMemory.ReferenceCount); block.DisposeFree(); block = blockIndex.RentNextWritableBlock(sl, minimumLength: 1, version + 2, default); Assert.IsFalse(block.IsCompleted); // TODO test replace //// replace existing //var toReplaceVersion = slc.FirstVersion; //var toReplaceRef = buffer.BufferRef; //slc.Complete(); //// SharedMemory.Free(buffer); //// slc.DisposeFree(); //buffer = chunkIndex.GetOrCreateNextWritableChunkBuffer(sl, toReplaceVersion, toReplaceRef, 1); //slc = new StreamLogChunk(buffer.RetainChunkMemory(false), streamId, valueSize, version + 2); //Assert.AreNotEqual(toReplaceRef, buffer.BufferRef); // SharedMemory.Free(buffer); block.DisposeFree(); } //bufferPool.PrintBuffers(); //bufferPool.PrintBuffersAfterPoolDispose = true; Benchmark.Dump(); Console.WriteLine("Finished"); sl.Dispose(); slm.Dispose(); }