blob: 540a1c12ebb1b1e15f45a8e4384ef0276f6cc46d [file] [log] [blame]
// Copyright 2019 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 <blobfs/unbuffered-operations-builder.h>
#include <lib/zx/vmo.h>
#include <zxtest/zxtest.h>
namespace blobfs {
namespace {
constexpr size_t kVmoSize = 8192;
TEST(UnbufferedOperationsBuilderTest, NoRequest) {
UnbufferedOperationsBuilder builder;
EXPECT_EQ(0, builder.BlockCount());
auto requests = builder.TakeOperations();
EXPECT_TRUE(requests.is_empty());
EXPECT_EQ(0, builder.BlockCount());
}
TEST(UnbufferedOperationsBuilderTest, EmptyRequest) {
UnbufferedOperationsBuilder builder;
zx::vmo vmo;
ASSERT_OK(zx::vmo::create(kVmoSize, 0, &vmo));
UnbufferedOperation operation;
operation.vmo = zx::unowned_vmo(vmo.get());
operation.op.type = OperationType::kWrite;
operation.op.vmo_offset = 0;
operation.op.dev_offset = 0;
operation.op.length = 0;
builder.Add(operation);
EXPECT_EQ(0, builder.BlockCount());
auto requests = builder.TakeOperations();
EXPECT_EQ(0, BlockCount(requests));
EXPECT_TRUE(requests.is_empty());
}
TEST(UnbufferedOperationsBuilderTest, OneRequest) {
UnbufferedOperationsBuilder builder;
zx::vmo vmo;
ASSERT_OK(zx::vmo::create(kVmoSize, 0, &vmo));
UnbufferedOperation operation;
operation.vmo = zx::unowned_vmo(vmo.get());
operation.op.type = OperationType::kWrite;
operation.op.vmo_offset = 0;
operation.op.dev_offset = 0;
operation.op.length = 1;
builder.Add(operation);
ASSERT_EQ(1, builder.BlockCount());
auto requests = builder.TakeOperations();
ASSERT_EQ(1, BlockCount(requests));
ASSERT_EQ(1, requests.size());
EXPECT_EQ(requests[0].vmo->get(), vmo.get());
EXPECT_EQ(requests[0].op.vmo_offset, operation.op.vmo_offset);
EXPECT_EQ(requests[0].op.dev_offset, operation.op.dev_offset);
EXPECT_EQ(requests[0].op.length, operation.op.length);
EXPECT_EQ(0, builder.BlockCount());
}
TEST(UnbufferedOperationsBuilderTest, TwoRequestsDifferentVmos) {
UnbufferedOperationsBuilder builder;
zx::vmo vmos[2];
ASSERT_OK(zx::vmo::create(kVmoSize, 0, &vmos[0]));
ASSERT_OK(zx::vmo::create(kVmoSize, 0, &vmos[1]));
UnbufferedOperation operations[2];
operations[0].vmo = zx::unowned_vmo(vmos[0].get());
operations[0].op.type = OperationType::kWrite;
operations[0].op.vmo_offset = 0;
operations[0].op.dev_offset = 0;
operations[0].op.length = 1;
builder.Add( operations[0]);
operations[1].vmo = zx::unowned_vmo(vmos[1].get());
operations[1].op.type = OperationType::kWrite;
operations[1].op.vmo_offset = 1;
operations[1].op.dev_offset = 1;
operations[1].op.length = 2;
builder.Add(operations[1]);
EXPECT_EQ(3, builder.BlockCount());
auto requests = builder.TakeOperations();
EXPECT_EQ(3, BlockCount(requests));
ASSERT_EQ(2, requests.size());
for (size_t i = 0; i < 2; i++) {
EXPECT_EQ(requests[i].vmo->get(), vmos[i].get());
EXPECT_EQ(requests[i].op.vmo_offset, operations[i].op.vmo_offset);
EXPECT_EQ(requests[i].op.dev_offset, operations[i].op.dev_offset);
EXPECT_EQ(requests[i].op.length, operations[i].op.length);
}
}
TEST(UnbufferedOperationsBuilderTest, TwoRequestsSameVmoUnalignedVmoOffset) {
UnbufferedOperationsBuilder builder;
zx::vmo vmo;
ASSERT_OK(zx::vmo::create(kVmoSize, 0, &vmo));
UnbufferedOperation operations[2];
operations[0].vmo = zx::unowned_vmo(vmo.get());
operations[0].op.type = OperationType::kWrite;
operations[0].op.vmo_offset = 0;
operations[0].op.dev_offset = 0;
operations[0].op.length = 1;
builder.Add(operations[0]);
operations[1].vmo = zx::unowned_vmo(vmo.get());
operations[1].op.type = OperationType::kWrite;
operations[1].op.vmo_offset = 2;
operations[1].op.dev_offset = 1;
operations[1].op.length = 2;
builder.Add(operations[1]);
EXPECT_EQ(3, builder.BlockCount());
auto requests = builder.TakeOperations();
EXPECT_EQ(3, BlockCount(requests));
ASSERT_EQ(2, requests.size());
for (size_t i = 0; i < 2; i++) {
EXPECT_EQ(requests[i].vmo->get(), vmo.get());
EXPECT_EQ(requests[i].op.vmo_offset, operations[i].op.vmo_offset);
EXPECT_EQ(requests[i].op.dev_offset, operations[i].op.dev_offset);
EXPECT_EQ(requests[i].op.length, operations[i].op.length);
}
}
TEST(UnbufferedOperationsBuilderTest, TwoRequestsSameVmoUnalignedVmoOffsetReverseOrder) {
UnbufferedOperationsBuilder builder;
zx::vmo vmo;
ASSERT_OK(zx::vmo::create(kVmoSize, 0, &vmo));
UnbufferedOperation operations[2];
operations[0].vmo = zx::unowned_vmo(vmo.get());
operations[0].op.type = OperationType::kWrite;
operations[0].op.vmo_offset = 2;
operations[0].op.dev_offset = 1;
operations[0].op.length = 2;
builder.Add(operations[0]);
operations[1].vmo = zx::unowned_vmo(vmo.get());
operations[1].op.type = OperationType::kWrite;
operations[1].op.vmo_offset = 0;
operations[1].op.dev_offset = 0;
operations[1].op.length = 1;
builder.Add(operations[1]);
EXPECT_EQ(3, builder.BlockCount());
auto requests = builder.TakeOperations();
ASSERT_EQ(2, requests.size());
for (size_t i = 0; i < 2; i++) {
EXPECT_EQ(requests[i].vmo->get(), vmo.get());
EXPECT_EQ(requests[i].op.vmo_offset, operations[i].op.vmo_offset);
EXPECT_EQ(requests[i].op.dev_offset, operations[i].op.dev_offset);
EXPECT_EQ(requests[i].op.length, operations[i].op.length);
}
}
TEST(UnbufferedOperationsBuilderTest, TwoRequestsSameVmoUnalignedDevOffset) {
UnbufferedOperationsBuilder builder;
zx::vmo vmo;
ASSERT_OK(zx::vmo::create(kVmoSize, 0, &vmo));
UnbufferedOperation operations[2];
operations[0].vmo = zx::unowned_vmo(vmo.get());
operations[0].op.type = OperationType::kWrite;
operations[0].op.vmo_offset = 0;
operations[0].op.dev_offset = 0;
operations[0].op.length = 1;
builder.Add(operations[0]);
operations[1].vmo = zx::unowned_vmo(vmo.get());
operations[1].op.type = OperationType::kWrite;
operations[1].op.vmo_offset = 1;
operations[1].op.dev_offset = 2;
operations[1].op.length = 2;
builder.Add(operations[1]);
EXPECT_EQ(3, builder.BlockCount());
auto requests = builder.TakeOperations();
ASSERT_EQ(2, requests.size());
for (size_t i = 0; i < 2; i++) {
EXPECT_EQ(requests[i].vmo->get(), vmo.get());
EXPECT_EQ(requests[i].op.vmo_offset, operations[i].op.vmo_offset);
EXPECT_EQ(requests[i].op.dev_offset, operations[i].op.dev_offset);
EXPECT_EQ(requests[i].op.length, operations[i].op.length);
}
}
TEST(UnbufferedOperationsBuilderTest, TwoRequestsSameVmoUnalignedDevOffsetReverseOrder) {
UnbufferedOperationsBuilder builder;
zx::vmo vmo;
ASSERT_OK(zx::vmo::create(kVmoSize, 0, &vmo));
UnbufferedOperation operations[2];
operations[0].vmo = zx::unowned_vmo(vmo.get());
operations[0].op.type = OperationType::kWrite;
operations[0].op.vmo_offset = 1;
operations[0].op.dev_offset = 2;
operations[0].op.length = 2;
builder.Add(operations[0]);
operations[1].vmo = zx::unowned_vmo(vmo.get());
operations[1].op.type = OperationType::kWrite;
operations[1].op.vmo_offset = 0;
operations[1].op.dev_offset = 0;
operations[1].op.length = 1;
builder.Add(operations[1]);
EXPECT_EQ(3, builder.BlockCount());
auto requests = builder.TakeOperations();
ASSERT_EQ(2, requests.size());
for (size_t i = 0; i < 2; i++) {
EXPECT_EQ(requests[i].vmo->get(), vmo.get());
EXPECT_EQ(requests[i].op.vmo_offset, operations[i].op.vmo_offset);
EXPECT_EQ(requests[i].op.dev_offset, operations[i].op.dev_offset);
EXPECT_EQ(requests[i].op.length, operations[i].op.length);
}
}
TEST(UnbufferedOperationsBuilderTest, TwoRequestsSameVmoDifferentTypes) {
UnbufferedOperationsBuilder builder;
zx::vmo vmo;
ASSERT_OK(zx::vmo::create(kVmoSize, 0, &vmo));
UnbufferedOperation operations[2];
operations[0].vmo = zx::unowned_vmo(vmo.get());
operations[0].op.type = OperationType::kWrite;
operations[0].op.vmo_offset = 0;
operations[0].op.dev_offset = 0;
operations[0].op.length = 1;
builder.Add(operations[0]);
operations[1].vmo = zx::unowned_vmo(vmo.get());
operations[1].op.type = OperationType::kRead;
operations[1].op.vmo_offset = 1;
operations[1].op.dev_offset = 1;
operations[1].op.length = 2;
builder.Add(operations[1]);
EXPECT_EQ(3, builder.BlockCount());
auto requests = builder.TakeOperations();
ASSERT_EQ(2, requests.size());
EXPECT_EQ(requests[0].vmo->get(), vmo.get());
EXPECT_EQ(requests[0].op.type, operations[0].op.type);
EXPECT_EQ(requests[0].op.vmo_offset, operations[0].op.vmo_offset);
EXPECT_EQ(requests[0].op.dev_offset, operations[0].op.dev_offset);
EXPECT_EQ(requests[0].op.length, operations[0].op.length);
EXPECT_EQ(requests[1].vmo->get(), vmo.get());
EXPECT_EQ(requests[1].op.type, operations[1].op.type);
EXPECT_EQ(requests[1].op.vmo_offset, operations[1].op.vmo_offset);
EXPECT_EQ(requests[1].op.dev_offset, operations[1].op.dev_offset);
EXPECT_EQ(requests[1].op.length, operations[1].op.length);
}
TEST(UnbufferedOperationsBuilderTest, TwoRequestsSameVmoDifferentStartCoalesced) {
UnbufferedOperationsBuilder builder;
zx::vmo vmo;
ASSERT_OK(zx::vmo::create(kVmoSize, 0, &vmo));
UnbufferedOperation operations[2];
operations[0].vmo = zx::unowned_vmo(vmo.get());
operations[0].op.type = OperationType::kWrite;
operations[0].op.vmo_offset = 0;
operations[0].op.dev_offset = 0;
operations[0].op.length = 1;
builder.Add(operations[0]);
operations[1].vmo = zx::unowned_vmo(vmo.get());
operations[1].op.type = OperationType::kWrite;
operations[1].op.vmo_offset = 1;
operations[1].op.dev_offset = 1;
operations[1].op.length = 2;
builder.Add(operations[1]);
EXPECT_EQ(3, builder.BlockCount());
auto requests = builder.TakeOperations();
ASSERT_EQ(1, requests.size());
EXPECT_EQ(requests[0].vmo->get(), vmo.get());
EXPECT_EQ(requests[0].op.vmo_offset, operations[0].op.vmo_offset);
EXPECT_EQ(requests[0].op.dev_offset, operations[0].op.dev_offset);
EXPECT_EQ(requests[0].op.length, operations[0].op.length + operations[1].op.length);
}
TEST(UnbufferedOperationsBuilderTest, TwoRequestsSameVmoDifferentStartCoalescedReverseOrder) {
UnbufferedOperationsBuilder builder;
zx::vmo vmo;
ASSERT_OK(zx::vmo::create(kVmoSize, 0, &vmo));
UnbufferedOperation operations[2];
operations[0].vmo = zx::unowned_vmo(vmo.get());
operations[0].op.type = OperationType::kWrite;
operations[0].op.vmo_offset = 1;
operations[0].op.dev_offset = 1;
operations[0].op.length = 2;
builder.Add(operations[0]);
operations[1].vmo = zx::unowned_vmo(vmo.get());
operations[1].op.type = OperationType::kWrite;
operations[1].op.vmo_offset = 0;
operations[1].op.dev_offset = 0;
operations[1].op.length = 1;
builder.Add(operations[1]);
EXPECT_EQ(3, builder.BlockCount());
auto requests = builder.TakeOperations();
ASSERT_EQ(1, requests.size());
EXPECT_EQ(requests[0].vmo->get(), vmo.get());
EXPECT_EQ(requests[0].op.vmo_offset, operations[1].op.vmo_offset);
EXPECT_EQ(requests[0].op.dev_offset, operations[1].op.dev_offset);
EXPECT_EQ(requests[0].op.length, operations[0].op.length + operations[1].op.length);
}
TEST(UnbufferedOperationsBuilderTest, TwoRequestsSameVmoDifferentStartPartialCoalesced) {
UnbufferedOperationsBuilder builder;
zx::vmo vmo;
ASSERT_OK(zx::vmo::create(kVmoSize, 0, &vmo));
UnbufferedOperation operations[2];
operations[0].vmo = zx::unowned_vmo(vmo.get());
operations[0].op.type = OperationType::kWrite;
operations[0].op.vmo_offset = 0;
operations[0].op.dev_offset = 0;
operations[0].op.length = 2;
builder.Add(operations[0]);
operations[1].vmo = zx::unowned_vmo(vmo.get());
operations[1].op.type = OperationType::kWrite;
operations[1].op.vmo_offset = 1;
operations[1].op.dev_offset = 1;
operations[1].op.length = 2;
builder.Add(operations[1]);
EXPECT_EQ(3, builder.BlockCount());
auto requests = builder.TakeOperations();
ASSERT_EQ(1, requests.size());
EXPECT_EQ(requests[0].vmo->get(), vmo.get());
EXPECT_EQ(requests[0].op.vmo_offset, operations[0].op.vmo_offset);
EXPECT_EQ(requests[0].op.dev_offset, operations[0].op.dev_offset);
EXPECT_EQ(requests[0].op.length, 3);
}
TEST(UnbufferedOperationsBuilderTest,
TwoRequestsSameVmoDifferentStartPartialCoalescedReverseOrder) {
UnbufferedOperationsBuilder builder;
zx::vmo vmo;
ASSERT_OK(zx::vmo::create(kVmoSize, 0, &vmo));
UnbufferedOperation operations[2];
operations[0].vmo = zx::unowned_vmo(vmo.get());
operations[0].op.type = OperationType::kWrite;
operations[0].op.vmo_offset = 1;
operations[0].op.dev_offset = 1;
operations[0].op.length = 2;
builder.Add(operations[0]);
operations[1].vmo = zx::unowned_vmo(vmo.get());
operations[1].op.type = OperationType::kWrite;
operations[1].op.vmo_offset = 0;
operations[1].op.dev_offset = 0;
operations[1].op.length = 2;
builder.Add(operations[1]);
EXPECT_EQ(3, builder.BlockCount());
auto requests = builder.TakeOperations();
ASSERT_EQ(1, requests.size());
EXPECT_EQ(requests[0].vmo->get(), vmo.get());
EXPECT_EQ(requests[0].op.vmo_offset, operations[1].op.vmo_offset);
EXPECT_EQ(requests[0].op.dev_offset, operations[1].op.dev_offset);
EXPECT_EQ(requests[0].op.length, 3);
}
TEST(UnbufferedOperationsBuilderTest, TwoRequestsSameVmoSameStartCoalesced) {
UnbufferedOperationsBuilder builder;
zx::vmo vmo;
ASSERT_OK(zx::vmo::create(kVmoSize, 0, &vmo));
UnbufferedOperation operations[2];
operations[0].vmo = zx::unowned_vmo(vmo.get());
operations[0].op.type = OperationType::kWrite;
operations[0].op.vmo_offset = 0;
operations[0].op.dev_offset = 0;
operations[0].op.length = 1;
builder.Add(operations[0]);
operations[1].vmo = zx::unowned_vmo(vmo.get());
operations[1].op.type = OperationType::kWrite;
operations[1].op.vmo_offset = 0;
operations[1].op.dev_offset = 0;
operations[1].op.length = 2;
builder.Add(operations[1]);
ASSERT_EQ(2, builder.BlockCount());
auto requests = builder.TakeOperations();
ASSERT_EQ(1, requests.size());
EXPECT_EQ(requests[0].vmo->get(), vmo.get());
EXPECT_EQ(requests[0].op.vmo_offset, operations[0].op.vmo_offset);
EXPECT_EQ(requests[0].op.dev_offset, operations[0].op.dev_offset);
EXPECT_EQ(requests[0].op.length, operations[1].op.length);
}
TEST(UnbufferedOperationsBuilderTest, TwoRequestsSameVmoSameStartCoalescedReverseOrder) {
UnbufferedOperationsBuilder builder;
zx::vmo vmo;
ASSERT_OK(zx::vmo::create(kVmoSize, 0, &vmo));
UnbufferedOperation operations[2];
operations[0].vmo = zx::unowned_vmo(vmo.get());
operations[0].op.type = OperationType::kWrite;
operations[0].op.vmo_offset = 0;
operations[0].op.dev_offset = 0;
operations[0].op.length = 2;
builder.Add(operations[0]);
operations[1].vmo = zx::unowned_vmo(vmo.get());
operations[1].op.type = OperationType::kWrite;
operations[1].op.vmo_offset = 0;
operations[1].op.dev_offset = 0;
operations[1].op.length = 1;
builder.Add(operations[1]);
ASSERT_EQ(2, builder.BlockCount());
auto requests = builder.TakeOperations();
ASSERT_EQ(1, requests.size());
EXPECT_EQ(requests[0].vmo->get(), vmo.get());
EXPECT_EQ(requests[0].op.vmo_offset, operations[0].op.vmo_offset);
EXPECT_EQ(requests[0].op.dev_offset, operations[0].op.dev_offset);
EXPECT_EQ(requests[0].op.length, operations[0].op.length);
}
TEST(UnbufferedOperationsBuilderTest, TwoRequestsSameVmoSubsumeRequest) {
UnbufferedOperationsBuilder builder;
zx::vmo vmo;
ASSERT_OK(zx::vmo::create(kVmoSize, 0, &vmo));
UnbufferedOperation operations[2];
operations[0].vmo = zx::unowned_vmo(vmo.get());
operations[0].op.type = OperationType::kWrite;
operations[0].op.vmo_offset = 1;
operations[0].op.dev_offset = 1;
operations[0].op.length = 1;
builder.Add(operations[0]);
operations[1].vmo = zx::unowned_vmo(vmo.get());
operations[1].op.type = OperationType::kWrite;
operations[1].op.vmo_offset = 0;
operations[1].op.dev_offset = 0;
operations[1].op.length = 3;
builder.Add(operations[1]);
EXPECT_EQ(3, builder.BlockCount());
auto requests = builder.TakeOperations();
ASSERT_EQ(1, requests.size());
EXPECT_EQ(requests[0].vmo->get(), vmo.get());
EXPECT_EQ(requests[0].op.vmo_offset, operations[1].op.vmo_offset);
EXPECT_EQ(requests[0].op.dev_offset, operations[1].op.dev_offset);
EXPECT_EQ(requests[0].op.length, operations[1].op.length);
}
TEST(UnbufferedOperationsBuilderTest, TwoRequestsSameVmoSubsumeRequestReverse) {
UnbufferedOperationsBuilder builder;
zx::vmo vmo;
ASSERT_OK(zx::vmo::create(kVmoSize, 0, &vmo));
UnbufferedOperation operations[2];
operations[0].vmo = zx::unowned_vmo(vmo.get());
operations[0].op.type = OperationType::kWrite;
operations[0].op.vmo_offset = 0;
operations[0].op.dev_offset = 0;
operations[0].op.length = 3;
builder.Add(operations[0]);
operations[1].vmo = zx::unowned_vmo(vmo.get());
operations[1].op.type = OperationType::kWrite;
operations[1].op.vmo_offset = 1;
operations[1].op.dev_offset = 1;
operations[1].op.length = 1;
builder.Add(operations[1]);
EXPECT_EQ(3, builder.BlockCount());
auto requests = builder.TakeOperations();
ASSERT_EQ(1, requests.size());
EXPECT_EQ(requests[0].vmo->get(), vmo.get());
EXPECT_EQ(requests[0].op.vmo_offset, operations[0].op.vmo_offset);
EXPECT_EQ(requests[0].op.dev_offset, operations[0].op.dev_offset);
EXPECT_EQ(requests[0].op.length, operations[0].op.length);
}
} // namespace
} // namespace blobfs