//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //ORIGINAL LINE: private void verifyUpdateResults(int filePages, PagedFile pagedFile, java.util.List<java.util.concurrent.Future<UpdateResult>> futures) throws InterruptedException, java.util.concurrent.ExecutionException, java.io.IOException private void VerifyUpdateResults(int filePages, PagedFile pagedFile, IList <Future <UpdateResult> > futures) { UpdateResult[] results = new UpdateResult[futures.Count]; for (int i = 0; i < results.Length; i++) { results[i] = futures[i].get(); } foreach (UpdateResult result in results) { using (PageCursor cursor = pagedFile.Io(0, PF_SHARED_READ_LOCK)) { for (int i = 0; i < filePages; i++) { assertTrue(cursor.Next()); int threadId = result.ThreadId; int expectedCount = result.PageCounts[i]; int actualCount; do { cursor.Offset = threadId * 4; actualCount = cursor.Int; } while (cursor.ShouldRetry()); assertThat("wrong count for threadId:" + threadId + ", aka. real threadId:" + result.RealThreadId + ", filePageId:" + i, actualCount, @is(expectedCount)); } } } }
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //ORIGINAL LINE: private void verifyAdversarialPagedContent(PagedFile pagedFile) throws java.io.IOException private void VerifyAdversarialPagedContent(PagedFile pagedFile) { using (PageCursor cursor = pagedFile.Io(0, PF_SHARED_READ_LOCK)) { while (cursor.Next()) { ReadAndVerifyAdversarialPage(cursor, pagedFile.PageSize()); } } }
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //ORIGINAL LINE: private void performConsistentAdversarialRead(PageCursor cursor, long maxPageId, long startingPage, int pageSize) throws java.io.IOException private void PerformConsistentAdversarialRead(PageCursor cursor, long maxPageId, long startingPage, int pageSize) { long pagesToLookAt = Math.Min(maxPageId, startingPage + 3) - startingPage + 1; for (int j = 0; j < pagesToLookAt; j++) { assertTrue(cursor.Next()); ReadAndVerifyAdversarialPage(cursor, pageSize); } }
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //ORIGINAL LINE: private void ensureAllPagesExists(int filePages, PagedFile pagedFile) throws java.io.IOException private void EnsureAllPagesExists(int filePages, PagedFile pagedFile) { using (PageCursor cursor = pagedFile.Io(0, PF_SHARED_WRITE_LOCK)) { for (int i = 0; i < filePages; i++) { assertTrue(cursor.Next(), "failed to initialise file page " + i); } } pageCache.flushAndForce(); }
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //ORIGINAL LINE: private void performConsistentAdversarialWrite(PageCursor cursor, java.util.concurrent.ThreadLocalRandom rng, int pageSize) throws java.io.IOException private void PerformConsistentAdversarialWrite(PageCursor cursor, ThreadLocalRandom rng, int pageSize) { for (int j = 0; j < 3; j++) { assertTrue(cursor.Next()); // Avoid generating zeros, so we can tell them apart from the // absence of a write: sbyte b = ( sbyte )rng.Next(1, 127); for (int k = 0; k < pageSize; k++) { cursor.PutByte(b); } assertFalse(cursor.ShouldRetry()); } }
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes: //ORIGINAL LINE: @Test void mustNotRunOutOfSwapperAllocationSpace() throws Exception //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: internal virtual void MustNotRunOutOfSwapperAllocationSpace() { assumeTrue(fs is EphemeralFileSystemAbstraction, "This test is file system agnostic, and too slow on a real file system"); configureStandardPageCache(); File file = file("a"); int iterations = short.MaxValue * 3; for (int i = 0; i < iterations; i++) { PagedFile pagedFile = pageCache.map(file, filePageSize); using (PageCursor cursor = pagedFile.Io(0, PF_SHARED_WRITE_LOCK)) { assertTrue(cursor.Next()); } pagedFile.Close(); } }
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //ORIGINAL LINE: protected void performReadOrUpdate(java.util.concurrent.ThreadLocalRandom rng, boolean updateCounter, int pf_flags) throws java.io.IOException protected internal override void performReadOrUpdate(ThreadLocalRandom rng, bool updateCounter, int pfFlags) { int pageId = rng.Next(0, _filePages); using (PageCursor cursor = _pagedFile.io(pageId, pfFlags)) { int counter; try { assertTrue(cursor.Next()); do { cursor.Offset = offset; counter = cursor.Int; } while (cursor.ShouldRetry()); string lockName = updateCounter ? "PF_SHARED_WRITE_LOCK" : "PF_SHARED_READ_LOCK"; string reason = string.Format("inconsistent page read from filePageId:{0}, with {1}, threadId:{2}", pageId, lockName, Thread.CurrentThread.Id); assertThat(reason, counter, @is(pageCounts[pageId])); } catch (Exception throwable) { _shouldStop.set(true); throw throwable; } if (updateCounter) { counter++; pageCounts[pageId]++; cursor.Offset = offset; cursor.PutInt(counter); } if (cursor.CheckAndClearBoundsFlag()) { _shouldStop.set(true); throw new System.IndexOutOfRangeException("offset = " + offset + ", filPageId:" + pageId + ", threadId: " + threadId + ", updateCounter = " + updateCounter); } } }
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes: //ORIGINAL LINE: @RepeatedTest(20) void pageCacheMustRemainInternallyConsistentWhenGettingRandomFailures() internal virtual void PageCacheMustRemainInternallyConsistentWhenGettingRandomFailures() { assertTimeout(ofMillis(LONG_TIMEOUT_MILLIS), () => { // NOTE: This test is inherently non-deterministic. This means that every failure must be // thoroughly investigated, since they have a good chance of being a real issue. // This is effectively a targeted robustness test. RandomAdversary adversary = new RandomAdversary(0.5, 0.2, 0.2); adversary.ProbabilityFactor = 0.0; FileSystemAbstraction fs = new AdversarialFileSystemAbstraction(adversary, this.fs); ThreadLocalRandom rng = ThreadLocalRandom.current(); // Because our test failures are non-deterministic, we use this tracer to capture a full history of the // events leading up to any given failure. LinearTracers linearTracers = LinearHistoryTracerFactory.pageCacheTracer(); getPageCache(fs, maxPages, linearTracers.PageCacheTracer, linearTracers.CursorTracerSupplier); PagedFile pfA = pageCache.map(existingFile("a"), filePageSize); PagedFile pfB = pageCache.map(existingFile("b"), filePageSize / 2 + 1); adversary.ProbabilityFactor = 1.0; for (int i = 0; i < 1000; i++) { PagedFile pagedFile = rng.nextBoolean() ? pfA : pfB; long maxPageId = pagedFile.LastPageId; bool performingRead = rng.nextBoolean() && maxPageId != -1; long startingPage = maxPageId < 0 ? 0 : rng.nextLong(maxPageId + 1); int pfFlags = performingRead ? PF_SHARED_READ_LOCK : PF_SHARED_WRITE_LOCK; int pageSize = pagedFile.PageSize(); try { using (PageCursor cursor = pagedFile.Io(startingPage, pfFlags)) { if (performingRead) { PerformConsistentAdversarialRead(cursor, maxPageId, startingPage, pageSize); } else { PerformConsistentAdversarialWrite(cursor, rng, pageSize); } } } catch (AssertionError error) { // Capture any exception that might have hit the eviction thread. adversary.ProbabilityFactor = 0.0; try { using (PageCursor cursor = pagedFile.Io(0, PF_SHARED_WRITE_LOCK)) { for (int j = 0; j < 100; j++) { cursor.Next(rng.nextLong(maxPageId + 1)); } } } catch (Exception throwable) { error.addSuppressed(throwable); } throw error; } catch (Exception) { // Don't worry about it... it's fine! // throwable.printStackTrace(); // only enable this when debugging test failures. } } // Unmapping will cause pages to be flushed. // We don't want that to fail, since it will upset the test tear-down. adversary.ProbabilityFactor = 0.0; try { // Flushing all pages, if successful, should clear any internal // exception. pageCache.flushAndForce(); // Do some post-chaos verification of what has been written. VerifyAdversarialPagedContent(pfA); VerifyAdversarialPagedContent(pfB); pfA.Close(); pfB.Close(); } catch (Exception e) { linearTracers.printHistory(System.err); throw e; } }); }
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes: //ORIGINAL LINE: @RepeatedTest(50) void writeLockingCursorMustThrowWhenLockingPageRacesWithUnmapping() internal virtual void WriteLockingCursorMustThrowWhenLockingPageRacesWithUnmapping() { assertTimeout(ofMillis(SEMI_LONG_TIMEOUT_MILLIS), () => { // Even if we block in pin, waiting to grab a lock on a page that is // already locked, and the PagedFile is concurrently closed, then we // want to have an exception thrown, such that we race and get a // page that is writable after the PagedFile has been closed. // This is important because closing a PagedFile implies flushing, thus // ensuring that all changes make it to storage. // Conversely, we don't have to go to the same lengths for read locked // pages, because those are never changed. Not by us, anyway. File file = file("a"); generateFileWithRecords(file, recordsPerFilePage * 2, recordSize); getPageCache(fs, maxPages, PageCacheTracer.NULL, PageCursorTracerSupplier.NULL); PagedFile pf = pageCache.map(file, filePageSize); System.Threading.CountdownEvent hasLockLatch = new System.Threading.CountdownEvent(1); System.Threading.CountdownEvent unlockLatch = new System.Threading.CountdownEvent(1); System.Threading.CountdownEvent secondThreadGotLockLatch = new System.Threading.CountdownEvent(1); AtomicBoolean doneWriteSignal = new AtomicBoolean(); AtomicBoolean doneCloseSignal = new AtomicBoolean(); executor.submit(() => { using (PageCursor cursor = pf.Io(0, PF_SHARED_WRITE_LOCK)) { cursor.Next(); hasLockLatch.countDown(); unlockLatch.await(); } return(null); }); hasLockLatch.await(); // A write lock is now held on page 0. Future <object> takeLockFuture = executor.submit(() => { using (PageCursor cursor = pf.Io(0, PF_SHARED_WRITE_LOCK)) { cursor.Next(); doneWriteSignal.set(true); secondThreadGotLockLatch.await(); } return(null); }); Future <object> closeFuture = executor.submit(() => { pf.Close(); doneCloseSignal.set(true); return(null); }); try { Thread.yield(); closeFuture.get(50, TimeUnit.MILLISECONDS); fail("Expected a TimeoutException here"); } catch (TimeoutException) { // As expected, the close cannot not complete while an write // lock is held } // Now, both the close action and a grab for an write page lock is // waiting for our first thread. // When we release that lock, we should see that either close completes // and our second thread, the one blocked on the write lock, gets an // exception, or we should see that the second thread gets the lock, // and then close has to wait for that thread as well. unlockLatch.countDown(); // The race is on. bool anyDone; do { Thread.yield(); anyDone = doneWriteSignal.get() | doneCloseSignal.get(); } while (!anyDone); if (doneCloseSignal.get()) { closeFuture.get(1000, TimeUnit.MILLISECONDS); // The closeFuture got it first, so the takeLockFuture should throw. try { secondThreadGotLockLatch.countDown(); // only to prevent incorrect programs from deadlocking takeLockFuture.get(); fail("Expected takeLockFuture.get() to throw an ExecutionException"); } catch (ExecutionException e) { Exception cause = e.InnerException; assertThat(cause, instanceOf(typeof(FileIsNotMappedException))); assertThat(cause.Message, startsWith("File has been unmapped")); } } else { assertTrue(doneWriteSignal.get()); // The takeLockFuture got it first, so the closeFuture should // complete when we release the latch. secondThreadGotLockLatch.countDown(); closeFuture.get(20000, TimeUnit.MILLISECONDS); } }); }