Bug 1574143 - Remove BlocksRingBuffer::EntryReserver - r=gregtatum
authorGerald Squelart <gsquelart@mozilla.com>
Fri, 16 Aug 2019 03:54:49 +0000
changeset 488428 2fd28586dfbe3ecc7a08a5dbec3cc39d2c838ee8
parent 488427 1050dca058c32f29609390345646ffde7e9f6114
child 488429 e54b58ba5f3a177e8d3abbb5de1e10903a83910d
push id36443
push userccoroiu@mozilla.com
push dateFri, 16 Aug 2019 09:48:15 +0000
treeherdermozilla-central@5d4cbfe103bb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgregtatum
bugs1574143, 1562604
milestone70.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1574143 - Remove BlocksRingBuffer::EntryReserver - r=gregtatum The point of the EntryReserver was mainly to have an object that represented a writing lock on BlocksRingBuffer, so potentially perform multiple consecutive writes. After some experience implementing bug 1562604, there's actually no need for it. So instead of having `Put()` create an `EntryReserver`, we now have `ReserveAndPut()` that does the whole work in one function. Differential Revision: https://phabricator.services.mozilla.com/D42116
mozglue/baseprofiler/public/BlocksRingBuffer.h
mozglue/tests/TestBaseProfiler.cpp
--- a/mozglue/baseprofiler/public/BlocksRingBuffer.h
+++ b/mozglue/baseprofiler/public/BlocksRingBuffer.h
@@ -27,22 +27,20 @@ namespace mozilla {
 // still valid, but contains no data, and gracefully denies accesses.
 //
 // To write an entry, the buffer reserves a block of sufficient size (to contain
 // user data of predetermined size), writes the entry size, and lets the caller
 // fill the entry contents using ModuloBuffer::Iterator APIs and a few entry-
 // specific APIs. E.g.:
 // ```
 // BlockRingsBuffer brb(PowerOfTwo<BlockRingsBuffer::Length>(1024));
-// brb.Put([&](BlocksRingBuffer::EntryReserver aER) {
-//   aER.Reserve([&](BlocksRingBuffer::EntryWriter aEW) {
-//     /* Use EntryWriter functions to serialize objects into entry. */
-//     aEW.WriteObject(123);
-//   });
-// });
+// brb.ReserveAndPut([]() { return sizeof(123); },
+//                   [&](BlocksRingBuffer::EntryWriter& aEW) {
+//                     aEW.WriteObject(123);
+//                   });
 // ```
 // Other `Put...` functions may be used as shortcuts for simple objects.
 // The objects given to the caller's callbacks should only be used inside the
 // callbacks and not stored elsewhere, because they keep their own references to
 // the BlocksRingBuffer and therefore should not live longer.
 //
 // When reading data, the buffer iterates over blocks (it knows how to read the
 // entry size, and therefore move to the next block), and lets the caller read
@@ -557,20 +555,18 @@ class BlocksRingBuffer {
     if (MOZ_LIKELY(mMaybeUnderlyingBuffer) && aBlockIndex >= mFirstReadIndex &&
         aBlockIndex < mNextWriteIndex) {
       AssertBlockIndexIsValid(aBlockIndex);
       maybeEntryReader.emplace(ReaderInBlockAt(aBlockIndex));
     }
     return std::forward<Callback>(aCallback)(std::move(maybeEntryReader));
   }
 
-  class EntryReserver;
-
   // Class used to write an entry contents.
-  // Created through `EntryReserver`, lives within a lock guard lifetime.
+  // Created through `Put()`, lives within a lock guard lifetime.
   class MOZ_RAII EntryWriter : public BufferWriter {
    public:
     // Disallow copying, moving, and assignments.
     EntryWriter(const EntryWriter& aOther) = delete;
     EntryWriter& operator=(const EntryWriter& aOther) = delete;
     EntryWriter(EntryWriter&& aOther) = delete;
     EntryWriter& operator=(EntryWriter&& aOther) = delete;
 
@@ -629,18 +625,18 @@ class BlocksRingBuffer {
         mRing.AssertBlockIndexIsValid(aBlockIndex);
         return Some(EntryReader(mRing, aBlockIndex));
       }
       // Block has been overwritten/cleared.
       return Nothing();
     }
 
    private:
-    // Only an EntryReserver can instantiate an EntryWriter.
-    friend class EntryReserver;
+    // Only a BlocksRingBuffer can instantiate an EntryWriter.
+    friend class BlocksRingBuffer;
 
     // Compute space needed for a block that can contain an entry of size
     // `aEntryBytes`.
     static Length BlockSizeForEntrySize(Length aEntryBytes) {
       return aEntryBytes +
              static_cast<Length>(BufferWriter::ULEB128Size(aEntryBytes));
     }
 
@@ -662,188 +658,105 @@ class BlocksRingBuffer {
 
     // This EntryWriter should only live inside one of the thread-safe
     // BlocksRingBuffer functions, for this reference to stay valid.
     BlocksRingBuffer& mRing;
     const Length mEntryBytes;
     const Index mEntryStart;
   };
 
-  // Class used to reserve space for new blocks, and to create `EntryWriter`s
-  // for them; lives within a lock guard lifetime.
-  class EntryReserver {
-   public:
-#ifdef DEBUG
-    ~EntryReserver() {
-      // No EntryReserver should live outside of a mutexed call.
-      mRing->mMutex.AssertCurrentThreadOwns();
-    }
-#endif  // DEBUG
-
-    // Reserve `aBytes`, call `aCallback` with a temporary EntryWriter, and
-    // return whatever `aCallback` returns.
-    // Callback should not store `EntryWriter`, as it may become invalid after
-    // this thread-safe call.
-    template <typename Callback>
-    auto Reserve(Length aBytes, Callback&& aCallback) {
-      // Don't allow even half of the buffer length. More than that would
-      // probably be unreasonable, and much more would risk having an entry
-      // wrapping around and overwriting itself!
-      MOZ_RELEASE_ASSERT(
-          aBytes <
-          mRing->mMaybeUnderlyingBuffer->mBuffer.BufferLength().Value() / 2);
-      // COmpute block size from the requested entry size.
-      const Length blockBytes = EntryWriter::BlockSizeForEntrySize(aBytes);
-      // We will put this new block at the end of the current buffer.
-      const BlockIndex blockIndex = mRing->mNextWriteIndex;
-      // Compute the end of this new block...
-      const Index blockEnd = Index(blockIndex) + blockBytes;
-      // ... which is where the following block will go.
-      mRing->mNextWriteIndex = BlockIndex(blockEnd);
-      while (
-          blockEnd >
-          Index(mRing->mFirstReadIndex) +
-              mRing->mMaybeUnderlyingBuffer->mBuffer.BufferLength().Value()) {
-        // About to trample on an old block.
-        EntryReader reader = mRing->ReaderInBlockAt(mRing->mFirstReadIndex);
-        // Call provided entry destructor for that entry.
-        if (mRing->mMaybeUnderlyingBuffer->mEntryDestructor) {
-          mRing->mMaybeUnderlyingBuffer->mEntryDestructor(reader);
+  // Main function to write entries.
+  // Reserve `aCallbackBytes()` bytes, call `aCallback()` with a pointer to an
+  // on-stack temporary EntryWriter (nullptr when out-of-session), and return
+  // whatever `aCallback` returns. Callback should not store `EntryWriter`,
+  // because it may become invalid after this thread-safe call.
+  // Note: `aCallbackBytes` is a callback instead of a simple value, to delay
+  // this potentially-expensive computation until after we're checked that we're
+  // in-session; use `Put(Length, Callback)` below if you know the size already.
+  template <typename CallbackBytes, typename Callback>
+  auto ReserveAndPut(CallbackBytes aCallbackBytes, Callback&& aCallback) {
+    {  // Locked block.
+      baseprofiler::detail::BaseProfilerAutoLock lock(mMutex);
+      if (MOZ_LIKELY(mMaybeUnderlyingBuffer)) {
+        Length bytes = std::forward<CallbackBytes>(aCallbackBytes)();
+        // Don't allow even half of the buffer length. More than that would
+        // probably be unreasonable, and much more would risk having an entry
+        // wrapping around and overwriting itself!
+        MOZ_RELEASE_ASSERT(
+            bytes < mMaybeUnderlyingBuffer->mBuffer.BufferLength().Value() / 2);
+        // COmpute block size from the requested entry size.
+        const Length blockBytes = EntryWriter::BlockSizeForEntrySize(bytes);
+        // We will put this new block at the end of the current buffer.
+        const BlockIndex blockIndex = mNextWriteIndex;
+        // Compute the end of this new block...
+        const Index blockEnd = Index(blockIndex) + blockBytes;
+        // ... which is where the following block will go.
+        mNextWriteIndex = BlockIndex(blockEnd);
+        while (blockEnd >
+               Index(mFirstReadIndex) +
+                   mMaybeUnderlyingBuffer->mBuffer.BufferLength().Value()) {
+          // About to trample on an old block.
+          EntryReader reader = ReaderInBlockAt(mFirstReadIndex);
+          // Call provided entry destructor for that entry.
+          if (mMaybeUnderlyingBuffer->mEntryDestructor) {
+            mMaybeUnderlyingBuffer->mEntryDestructor(reader);
+          }
+          mMaybeUnderlyingBuffer->mClearedBlockCount += 1;
+          MOZ_ASSERT(reader.CurrentIndex() <= Index(reader.NextBlockIndex()));
+          // Move the buffer reading start past this cleared block.
+          mFirstReadIndex = reader.NextBlockIndex();
         }
-        mRing->mMaybeUnderlyingBuffer->mClearedBlockCount += 1;
-        MOZ_ASSERT(reader.CurrentIndex() <= Index(reader.NextBlockIndex()));
-        // Move the buffer reading start past this cleared block.
-        mRing->mFirstReadIndex = reader.NextBlockIndex();
+        mMaybeUnderlyingBuffer->mPushedBlockCount += 1;
+        // Finally, let aCallback write into the entry.
+        EntryWriter entryWriter(*this, blockIndex, bytes);
+        return std::forward<Callback>(aCallback)(&entryWriter);
       }
-      mRing->mMaybeUnderlyingBuffer->mPushedBlockCount += 1;
-      // Finally, let aCallback write into the entry.
-      return std::forward<Callback>(aCallback)(
-          EntryWriter(*mRing, blockIndex, aBytes));
-    }
-
-    // Write a new entry copied from the given buffer, return block index.
-    BlockIndex Write(const void* aSrc, Length aBytes) {
-      return Reserve(aBytes, [&](EntryWriter& aEW) {
-        aEW.Write(aSrc, aBytes);
-        return aEW.CurrentBlockIndex();
-      });
-    }
-
-    // Write a new entry copied from the given object, return block index.
-    // Restricted to trivially-copyable types.
-    // TODO: Allow more types (follow-up patches in progress).
-    template <typename T>
-    BlockIndex WriteObject(const T& aOb) {
-      return Write(&aOb, sizeof(T));
-    }
-
-    // Index of the first block in the whole buffer.
-    BlockIndex BufferRangeStart() const { return mRing->mFirstReadIndex; }
-
-    // Index past the last block in the whole buffer.
-    BlockIndex BufferRangeEnd() const { return mRing->mNextWriteIndex; }
-
-    // Get another entry based on a {Current,Next}BlockIndex(). This may fail if
-    // the buffer has already looped around and destroyed that block.
-    Maybe<EntryReader> GetEntryAt(BlockIndex aBlockIndex) {
-      // Don't accept a not-yet-written index.
-      MOZ_ASSERT(aBlockIndex <= BufferRangeEnd());
-      if (aBlockIndex >= BufferRangeStart() && aBlockIndex < BufferRangeEnd()) {
-        // Block is still alive -> Return reader for it.
-        mRing->AssertBlockIndexIsValid(aBlockIndex);
-        return Some(EntryReader(*mRing, aBlockIndex));
-      }
-      // Block has been overwritten/cleared.
-      return Nothing();
-    }
-
-   private:
-    // Only a BlocksRingBuffer can instantiate an EntryReserver.
-    friend class BlocksRingBuffer;
-
-    explicit EntryReserver(BlocksRingBuffer& aRing)
-        : mRing(WrapNotNull(&aRing)) {
-      // No EntryReserver should live outside of a mutexed call.
-      mRing->mMutex.AssertCurrentThreadOwns();
-    }
-
-    // Using a non-null pointer instead of a reference, to allow copying.
-    // This EntryReserver should only live inside one of the thread-safe
-    // BlocksRingBuffer functions, for this reference to stay valid.
-    NotNull<BlocksRingBuffer*> mRing;
-  };
-
-  // Main function to write entries.
-  // Call `aCallback(Maybe<BlocksRingBuffer::EntryReserver>&&)`, and return
-  // whatever `aCallback` returns. `Maybe` may be `Nothing` when out-of-session.
-  // Callback should not store `EntryReserver`, because it may become invalid
-  // after this call. The `EntryReserver` can then be used to reserve one or
-  // more entries; another callback can then fill each.
-  template <typename Callback>
-  auto Put(Callback&& aCallback) {
-    // Implementation note: We are locking during the whole operation (reserving
-    // and writing entry), which means slow writers could block the buffer for a
-    // while. It should be possible to only lock when reserving the space, and
-    // then letting the callback write the entry without a need for the lock, as
-    // it's the only thread that should be accessing this particular entry.
-    // Extra safety would be necessary to ensure the entry cannot be read, and
-    // fast writers going around the ring cannot trample on this entry until it
-    // is fully written.
-    // TODO: Investigate this potential improvement as part of bug 1562604.
-    baseprofiler::detail::BaseProfilerAutoLock lock(mMutex);
-    Maybe<EntryReserver> maybeEntryReserver;
-    if (MOZ_LIKELY(mMaybeUnderlyingBuffer)) {
-      maybeEntryReserver.emplace(EntryReserver(*this));
-    }
-    return std::forward<Callback>(aCallback)(std::move(maybeEntryReserver));
+    }  // End of locked block.
+    // Out-of-session, just invoke the callback with nullptr, no need to hold
+    // the lock.
+    return std::forward<Callback>(aCallback)(nullptr);
   }
 
   // Add a new entry of known size, call `aCallback` with a pointer to a
   // temporary EntryWriter (can be null when out-of-session), and return
   // whatever `aCallback` returns. Callback should not store the `EntryWriter`,
   // as it may become invalid after this thread-safe call.
   template <typename Callback>
-  auto Put(Length aLength, Callback&& aCallback) {
-    return Put([&](Maybe<EntryReserver>&& aER) {
-      if (MOZ_LIKELY(aER)) {
-        // We are in-session, with an EntryReserver at the ready.
-        // Reserve the requested space, then invoke the callback with a pointer
-        // to the reserved EntryWriter.
-        return aER->Reserve(aLength, [&](EntryWriter& aEW) {
-          return std::forward<Callback>(aCallback)(&aEW);
-        });
-      }
-      // Out-of-session, just invoke the callback with nullptr.
-      return std::forward<Callback>(aCallback)(nullptr);
-    });
+  auto Put(Length aBytes, Callback&& aCallback) {
+    return ReserveAndPut([aBytes]() { return aBytes; },
+                         std::forward<Callback>(aCallback));
   }
 
   // Add a new entry copied from the given buffer, return block index.
   BlockIndex PutFrom(const void* aSrc, Length aBytes) {
-    return Put([&](Maybe<EntryReserver>&& aER) {
-      if (MOZ_LIKELY(aER)) {
-        return std::move(aER)->Write(aSrc, aBytes);
-      }
-      // Out-of-session, return "empty" BlockIndex.
-      return BlockIndex{};
-    });
+    return ReserveAndPut([aBytes]() { return aBytes; },
+                         [&](EntryWriter* aEntryWriter) {
+                           if (MOZ_LIKELY(aEntryWriter)) {
+                             aEntryWriter->Write(aSrc, aBytes);
+                             return aEntryWriter->CurrentBlockIndex();
+                           }
+                           // Out-of-session, return "empty" BlockIndex.
+                           return BlockIndex{};
+                         });
   }
 
   // Add a new entry copied from the given object, return block index.
   // Restricted to trivially-copyable types.
   // TODO: Allow more types (follow-up patches in progress, see bug 1562604).
   template <typename T>
   BlockIndex PutObject(const T& aOb) {
-    return Put([&](Maybe<EntryReserver>&& aER) {
-      if (MOZ_LIKELY(aER)) {
-        return std::move(aER)->WriteObject<T>(aOb);
-      }
-      // Out-of-session, return "empty" BlockIndex.
-      return BlockIndex{};
-    });
+    return ReserveAndPut([]() { return sizeof(T); },
+                         [&](EntryWriter* aEntryWriter) {
+                           if (MOZ_LIKELY(aEntryWriter)) {
+                             aEntryWriter->WriteObject(aOb);
+                             return aEntryWriter->CurrentBlockIndex();
+                           }
+                           // Out-of-session, return "empty" BlockIndex.
+                           return BlockIndex{};
+                         });
   }
 
   // Clear all entries, calling entry destructor (if any), and move read index
   // to the end so that these entries cannot be read anymore.
   void Clear() {
     baseprofiler::detail::BaseProfilerAutoLock lock(mMutex);
     ClearAllEntries();
   }
--- a/mozglue/tests/TestBaseProfiler.cpp
+++ b/mozglue/tests/TestBaseProfiler.cpp
@@ -519,21 +519,23 @@ void TestBlocksRingBufferAPI() {
     });
 
     // Push `1` directly.
     MOZ_RELEASE_ASSERT(ExtractBlockIndex(rb.PutObject(uint32_t(1))) == 1);
     //   0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
     //   - S[4 |    int(1)    ]E
     VERIFY_START_END_DESTROYED(1, 6, 0);
 
-    // Push `2` through EntryReserver, check output BlockIndex.
-    auto bi2 = rb.Put([](Maybe<BlocksRingBuffer::EntryReserver>&& aER) {
-      MOZ_RELEASE_ASSERT(aER.isSome());
-      return aER->WriteObject(uint32_t(2));
-    });
+    // Push `2` through ReserveAndPut, check output BlockIndex.
+    auto bi2 = rb.ReserveAndPut([]() { return sizeof(uint32_t); },
+                                [](BlocksRingBuffer::EntryWriter* aEW) {
+                                  MOZ_RELEASE_ASSERT(!!aEW);
+                                  aEW->WriteObject(uint32_t(2));
+                                  return aEW->CurrentBlockIndex();
+                                });
     static_assert(
         std::is_same<decltype(bi2), BlocksRingBuffer::BlockIndex>::value,
         "All index-returning functions should return a "
         "BlocksRingBuffer::BlockIndex");
     MOZ_RELEASE_ASSERT(ExtractBlockIndex(bi2) == 6);
     //   0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
     //   - S[4 |    int(1)    ] [4 |    int(2)    ]E
     VERIFY_START_END_DESTROYED(1, 11, 0);
@@ -595,26 +597,24 @@ void TestBlocksRingBufferAPI() {
 
     MOZ_RELEASE_ASSERT(bi2Next != bi2);
     MOZ_RELEASE_ASSERT(bi2Next > bi2);
     MOZ_RELEASE_ASSERT(bi2Next >= bi2);
     MOZ_RELEASE_ASSERT(!(bi2Next == bi2));
     MOZ_RELEASE_ASSERT(!(bi2Next < bi2));
     MOZ_RELEASE_ASSERT(!(bi2Next <= bi2));
 
-    // Push `3` through EntryReserver and then EntryWriter, check writer output
+    // Push `3` through Put, check writer output
     // is returned to the initial caller.
-    auto put3 = rb.Put([&](Maybe<BlocksRingBuffer::EntryReserver>&& aER) {
-      MOZ_RELEASE_ASSERT(aER.isSome());
-      return aER->Reserve(
-          sizeof(uint32_t), [&](BlocksRingBuffer::EntryWriter& aEW) {
-            aEW.WriteObject(uint32_t(3));
-            return float(ExtractBlockIndex(aEW.CurrentBlockIndex()));
-          });
-    });
+    auto put3 =
+        rb.Put(sizeof(uint32_t), [&](BlocksRingBuffer::EntryWriter* aEW) {
+          MOZ_RELEASE_ASSERT(!!aEW);
+          aEW->WriteObject(uint32_t(3));
+          return float(ExtractBlockIndex(aEW->CurrentBlockIndex()));
+        });
     static_assert(std::is_same<decltype(put3), float>::value,
                   "Expect float as returned by callback.");
     MOZ_RELEASE_ASSERT(put3 == 11.0);
     //   0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15 (16)
     //   - S[4 |    int(1)    ] [4 |    int(2)    ] [4 |    int(3)    ]E
     VERIFY_START_END_DESTROYED(1, 16, 0);
 
     // Re-Read single entry at bi2, should now have a next entry.
@@ -662,32 +662,29 @@ void TestBlocksRingBufferAPI() {
 
     // Check that we have `2` to `4`.
     count = 1;
     rb.ReadEach([&](BlocksRingBuffer::EntryReader& aReader) {
       MOZ_RELEASE_ASSERT(aReader.ReadObject<uint32_t>() == ++count);
     });
     MOZ_RELEASE_ASSERT(count == 4);
 
-    // Push 5 through EntryReserver then EntryWriter, no returns.
+    // Push 5 through Put, no returns.
     // This will destroy the second entry.
     // Check that the EntryWriter can access bi4 but not bi2.
-    auto bi5_6 = rb.Put([&](Maybe<BlocksRingBuffer::EntryReserver>&& aER) {
-      MOZ_RELEASE_ASSERT(aER.isSome());
-      return aER->Reserve(
-          sizeof(uint32_t), [&](BlocksRingBuffer::EntryWriter& aEW) {
-            aEW.WriteObject(uint32_t(5));
-            MOZ_RELEASE_ASSERT(aEW.GetEntryAt(bi2).isNothing());
-            MOZ_RELEASE_ASSERT(aEW.GetEntryAt(bi4).isSome());
-            MOZ_RELEASE_ASSERT(aEW.GetEntryAt(bi4)->CurrentBlockIndex() == bi4);
-            MOZ_RELEASE_ASSERT(aEW.GetEntryAt(bi4)->ReadObject<uint32_t>() ==
-                               4);
-            return MakePair(aEW.CurrentBlockIndex(), aEW.BlockEndIndex());
-          });
-    });
+    auto bi5_6 =
+        rb.Put(sizeof(uint32_t), [&](BlocksRingBuffer::EntryWriter* aEW) {
+          MOZ_RELEASE_ASSERT(!!aEW);
+          aEW->WriteObject(uint32_t(5));
+          MOZ_RELEASE_ASSERT(aEW->GetEntryAt(bi2).isNothing());
+          MOZ_RELEASE_ASSERT(aEW->GetEntryAt(bi4).isSome());
+          MOZ_RELEASE_ASSERT(aEW->GetEntryAt(bi4)->CurrentBlockIndex() == bi4);
+          MOZ_RELEASE_ASSERT(aEW->GetEntryAt(bi4)->ReadObject<uint32_t>() == 4);
+          return MakePair(aEW->CurrentBlockIndex(), aEW->BlockEndIndex());
+        });
     auto& bi5 = bi5_6.first();
     auto& bi6 = bi5_6.second();
     //  16  17  18  19  20  21  22  23  24  25  26  11  12  13  14  15 (16)
     //  [4 |    int(4)    ] [4 |    int(5)    ]E ? S[4 |    int(3)    ]
     VERIFY_START_END_DESTROYED(11, 26, 2);
 
     // Read single entry at bi2, should now gracefully fail.
     rb.ReadAt(bi2, [](Maybe<BlocksRingBuffer::EntryReader>&& aMaybeReader) {
@@ -793,22 +790,16 @@ void TestBlocksRingBufferUnderlyingBuffe
     BlocksRingBuffer::State state = rb.GetState();
     // When out-of-session, range start and ends are the same, and there are no
     // pushed&cleared blocks.
     MOZ_RELEASE_ASSERT(state.mRangeStart == state.mRangeEnd);
     MOZ_RELEASE_ASSERT(state.mPushedBlockCount == 0);
     MOZ_RELEASE_ASSERT(state.mClearedBlockCount == 0);
     // `Put()` functions run the callback with `Nothing`.
     int32_t ran = 0;
-    rb.Put([&](Maybe<BlocksRingBuffer::EntryReserver>&& aMaybeEntryReserver) {
-      MOZ_RELEASE_ASSERT(aMaybeEntryReserver.isNothing());
-      ++ran;
-    });
-    MOZ_RELEASE_ASSERT(ran == 1);
-    ran = 0;
     rb.Put(1, [&](BlocksRingBuffer::EntryWriter* aMaybeEntryWriter) {
       MOZ_RELEASE_ASSERT(!aMaybeEntryWriter);
       ++ran;
     });
     MOZ_RELEASE_ASSERT(ran == 1);
     // `PutFrom` won't do anything, and returns the null BlockIndex.
     MOZ_RELEASE_ASSERT(rb.PutFrom(&ran, sizeof(ran)) ==
                        BlocksRingBuffer::BlockIndex{});
@@ -870,22 +861,16 @@ void TestBlocksRingBufferUnderlyingBuffe
       MOZ_RELEASE_ASSERT(state.mPushedBlockCount == 0);
       MOZ_RELEASE_ASSERT(state.mClearedBlockCount == 0);
     } else {
       MOZ_RELEASE_ASSERT(state.mRangeStart < state.mRangeEnd);
       MOZ_RELEASE_ASSERT(state.mPushedBlockCount > 0);
       MOZ_RELEASE_ASSERT(state.mClearedBlockCount <= state.mPushedBlockCount);
     }
     int32_t ran = 0;
-    rb.Put([&](Maybe<BlocksRingBuffer::EntryReserver>&& aMaybeEntryReserver) {
-      MOZ_RELEASE_ASSERT(aMaybeEntryReserver.isSome());
-      ++ran;
-    });
-    MOZ_RELEASE_ASSERT(ran == 1);
-    ran = 0;
     // The following three `Put...` will write three int32_t of value 1.
     bi = rb.Put(sizeof(ran),
                 [&](BlocksRingBuffer::EntryWriter* aMaybeEntryWriter) {
                   MOZ_RELEASE_ASSERT(!!aMaybeEntryWriter);
                   ++ran;
                   aMaybeEntryWriter->WriteObject(ran);
                   return aMaybeEntryWriter->CurrentBlockIndex();
                 });