|  | // Copyright 2018 The Fuchsia Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "allocator/extent-reserver.h" | 
|  |  | 
|  | #include <bitmap/rle-bitmap.h> | 
|  | #include <gtest/gtest.h> | 
|  |  | 
|  | #include "allocator/node-reserver.h" | 
|  |  | 
|  | namespace blobfs { | 
|  | namespace { | 
|  |  | 
|  | // Test simple cases of reserving a single extent | 
|  | TEST(ExtentReserverTest, Reserve) { | 
|  | ExtentReserver reserver; | 
|  | BlockOffsetType start_block = 0; | 
|  | BlockCountType block_count = 1; | 
|  | Extent extent(start_block, block_count); | 
|  |  | 
|  | // The ReservedExtent constructor should reserve the extent. | 
|  | // The destructor should release the extent. | 
|  | { | 
|  | ReservedExtent reserved_extent(&reserver, extent); | 
|  | EXPECT_EQ(block_count, reserver.ReservedBlockCount()); | 
|  | } | 
|  | EXPECT_EQ(0u, reserver.ReservedBlockCount()); | 
|  | } | 
|  |  | 
|  | TEST(ExtentReserverTest, ReserveReset) { | 
|  | ExtentReserver reserver; | 
|  | BlockOffsetType start_block = 0; | 
|  | BlockCountType block_count = 1; | 
|  | Extent extent(start_block, block_count); | 
|  |  | 
|  | // The ReservedExtent constructor should reserve the extent. | 
|  | // Reset should release the extent. | 
|  | { | 
|  | ReservedExtent reserved_extent(&reserver, extent); | 
|  | EXPECT_EQ(block_count, reserver.ReservedBlockCount()); | 
|  | reserved_extent.Reset(); | 
|  | EXPECT_EQ(0u, reserver.ReservedBlockCount()); | 
|  | } | 
|  | EXPECT_EQ(0u, reserver.ReservedBlockCount()); | 
|  | } | 
|  |  | 
|  | // Test the constructors of the reserved extent. | 
|  | TEST(ExtentReserverTest, Constructor) { | 
|  | ExtentReserver reserver; | 
|  | BlockOffsetType start_block = 0; | 
|  | BlockCountType block_count = 1; | 
|  | Extent extent(start_block, block_count); | 
|  |  | 
|  | // Test reservation via the constructor. | 
|  | { | 
|  | ReservedExtent reserved_extent(&reserver, extent); | 
|  | EXPECT_EQ(extent.Start(), reserved_extent.extent().Start()); | 
|  | EXPECT_EQ(extent.Length(), reserved_extent.extent().Length()); | 
|  | EXPECT_EQ(block_count, reserver.ReservedBlockCount()); | 
|  | } | 
|  | EXPECT_EQ(0u, reserver.ReservedBlockCount()); | 
|  | } | 
|  |  | 
|  | TEST(ExtentReserverTest, MoveConstructor) { | 
|  | ExtentReserver reserver; | 
|  | BlockOffsetType start_block = 0; | 
|  | BlockCountType block_count = 1; | 
|  | Extent extent(start_block, block_count); | 
|  |  | 
|  | // Test reservation via move constructor. | 
|  | { | 
|  | ReservedExtent source_extent(&reserver, extent); | 
|  | EXPECT_EQ(1u, reserver.ReservedBlockCount()); | 
|  | EXPECT_EQ(extent.Start(), source_extent.extent().Start()); | 
|  | EXPECT_EQ(extent.Length(), source_extent.extent().Length()); | 
|  |  | 
|  | ReservedExtent dest_extent(std::move(source_extent)); | 
|  | EXPECT_EQ(1u, reserver.ReservedBlockCount()); | 
|  | EXPECT_EQ(extent.Start(), dest_extent.extent().Start()); | 
|  | EXPECT_EQ(extent.Length(), dest_extent.extent().Length()); | 
|  | } | 
|  | EXPECT_EQ(0u, reserver.ReservedBlockCount()); | 
|  | } | 
|  |  | 
|  | TEST(ExtentReserverTest, MoveAssignment) { | 
|  | ExtentReserver reserver; | 
|  | BlockOffsetType start_block = 0; | 
|  | BlockCountType block_count = 1; | 
|  | Extent extent(start_block, block_count); | 
|  |  | 
|  | // Test reservation via the move assignment operator. | 
|  | { | 
|  | ReservedExtent source_extent(&reserver, extent); | 
|  | EXPECT_EQ(1u, reserver.ReservedBlockCount()); | 
|  | EXPECT_EQ(extent.Start(), source_extent.extent().Start()); | 
|  | EXPECT_EQ(extent.Length(), source_extent.extent().Length()); | 
|  |  | 
|  | ReservedExtent dest_extent = std::move(source_extent); | 
|  | EXPECT_EQ(1u, reserver.ReservedBlockCount()); | 
|  | EXPECT_EQ(extent.Start(), dest_extent.extent().Start()); | 
|  | EXPECT_EQ(extent.Length(), dest_extent.extent().Length()); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Test splitting of extents. | 
|  | TEST(ExtentReserverTest, Split) { | 
|  | ExtentReserver reserver; | 
|  | uint64_t start_block = 0; | 
|  | BlockCountType block_count = 10; | 
|  | Extent extent{start_block, block_count}; | 
|  |  | 
|  | EXPECT_EQ(0u, reserver.ReservedBlockCount()); | 
|  | ReservedExtent reserved_extent(&reserver, extent); | 
|  | EXPECT_EQ(10u, reserver.ReservedBlockCount()); | 
|  |  | 
|  | { | 
|  | const BlockCountType split_point = 5; | 
|  | ReservedExtent latter(reserved_extent.SplitAt(split_point)); | 
|  | // After splitting, no reservations actually change. | 
|  | EXPECT_EQ(10u, reserver.ReservedBlockCount()); | 
|  |  | 
|  | // Verify the split extents contain the expected values. | 
|  | EXPECT_EQ(extent.Start(), reserved_extent.extent().Start()); | 
|  | EXPECT_EQ(split_point, reserved_extent.extent().Length()); | 
|  |  | 
|  | EXPECT_EQ(extent.Start() + split_point, latter.extent().Start()); | 
|  | EXPECT_EQ(block_count - split_point, latter.extent().Length()); | 
|  | } | 
|  |  | 
|  | // When the latter half of the reservation goes out of scope, the reservations | 
|  | // are cleaned up too. | 
|  | EXPECT_EQ(5u, reserver.ReservedBlockCount()); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  | }  // namespace blobfs |