summaryrefslogtreecommitdiffstats
path: root/storage/src/tests/distributor/simplemaintenancescannertest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'storage/src/tests/distributor/simplemaintenancescannertest.cpp')
-rw-r--r--storage/src/tests/distributor/simplemaintenancescannertest.cpp220
1 files changed, 220 insertions, 0 deletions
diff --git a/storage/src/tests/distributor/simplemaintenancescannertest.cpp b/storage/src/tests/distributor/simplemaintenancescannertest.cpp
new file mode 100644
index 00000000000..512a10bbd9a
--- /dev/null
+++ b/storage/src/tests/distributor/simplemaintenancescannertest.cpp
@@ -0,0 +1,220 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/fastos/fastos.h>
+#include <vespa/vdstestlib/cppunit/macros.h>
+#include <vespa/storage/distributor/maintenance/simplemaintenancescanner.h>
+#include <vespa/storage/distributor/maintenance/simplebucketprioritydatabase.h>
+#include <vespa/storage/distributor/bucketdb/mapbucketdatabase.h>
+#include <tests/distributor/maintenancemocks.h>
+
+#include <string>
+#include <sstream>
+#include <memory>
+#include <algorithm>
+#include <iterator>
+
+namespace storage {
+
+namespace distributor {
+
+using document::BucketId;
+typedef MaintenancePriority Priority;
+
+class SimpleMaintenanceScannerTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(SimpleMaintenanceScannerTest);
+ CPPUNIT_TEST(testPrioritizeSingleBucket);
+ CPPUNIT_TEST(testPrioritizeMultipleBuckets);
+ CPPUNIT_TEST(testPendingMaintenanceOperationStatistics);
+ CPPUNIT_TEST(perNodeMaintenanceStatsAreTracked);
+ CPPUNIT_TEST(testReset);
+ CPPUNIT_TEST_SUITE_END();
+
+ using PendingStats = SimpleMaintenanceScanner::PendingMaintenanceStats;
+
+ std::string dumpPriorityDbToString(const BucketPriorityDatabase&) const;
+
+ std::unique_ptr<MockMaintenancePriorityGenerator> _priorityGenerator;
+ std::unique_ptr<MapBucketDatabase> _bucketDb;
+ std::unique_ptr<SimpleBucketPriorityDatabase> _priorityDb;
+ std::unique_ptr<SimpleMaintenanceScanner> _scanner;
+
+ void addBucketToDb(int bucketNum);
+
+ bool scanEntireDatabase(int expected);
+
+ std::string stringifyGlobalPendingStats(const PendingStats&) const;
+
+public:
+ void testPrioritizeSingleBucket();
+ void testPrioritizeMultipleBuckets();
+ void testPendingMaintenanceOperationStatistics();
+ void perNodeMaintenanceStatsAreTracked();
+ void testReset();
+
+ void setUp();
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(SimpleMaintenanceScannerTest);
+
+void
+SimpleMaintenanceScannerTest::setUp()
+{
+ _priorityGenerator.reset(new MockMaintenancePriorityGenerator());
+ _bucketDb.reset(new MapBucketDatabase());
+ _priorityDb.reset(new SimpleBucketPriorityDatabase());
+ _scanner.reset(new SimpleMaintenanceScanner(*_priorityDb, *_priorityGenerator, *_bucketDb));
+}
+
+void
+SimpleMaintenanceScannerTest::addBucketToDb(int bucketNum)
+{
+ BucketDatabase::Entry entry(BucketId(16, bucketNum), BucketInfo());
+ _bucketDb->update(entry);
+}
+
+std::string
+SimpleMaintenanceScannerTest::stringifyGlobalPendingStats(
+ const PendingStats& stats) const
+{
+ std::ostringstream ss;
+ ss << stats.global;
+ return ss.str();
+}
+
+void
+SimpleMaintenanceScannerTest::testPrioritizeSingleBucket()
+{
+ addBucketToDb(1);
+ std::string expected("PrioritizedBucket(BucketId(0x4000000000000001), pri VERY_HIGH)\n");
+
+ CPPUNIT_ASSERT(!_scanner->scanNext().isDone());
+ CPPUNIT_ASSERT_EQUAL(expected, _priorityDb->toString());
+
+ CPPUNIT_ASSERT(_scanner->scanNext().isDone());
+ CPPUNIT_ASSERT_EQUAL(expected, _priorityDb->toString());
+}
+
+namespace {
+ std::string sortLines(const std::string& source) {
+ vespalib::StringTokenizer st(source,"\n","");
+ std::vector<std::string> lines;
+ std::copy(st.begin(), st.end(), std::back_inserter(lines));
+ std::sort(lines.begin(), lines.end());
+ std::ostringstream ost;
+ for (auto& line : lines) {
+ ost << line << "\n";
+ }
+ return ost.str();
+ }
+}
+
+void
+SimpleMaintenanceScannerTest::testPrioritizeMultipleBuckets()
+{
+ addBucketToDb(1);
+ addBucketToDb(2);
+ addBucketToDb(3);
+ std::string expected("PrioritizedBucket(BucketId(0x4000000000000001), pri VERY_HIGH)\n"
+ "PrioritizedBucket(BucketId(0x4000000000000002), pri VERY_HIGH)\n"
+ "PrioritizedBucket(BucketId(0x4000000000000003), pri VERY_HIGH)\n");
+
+ CPPUNIT_ASSERT(scanEntireDatabase(3));
+ CPPUNIT_ASSERT_EQUAL(sortLines(expected),
+ sortLines(_priorityDb->toString()));
+}
+
+bool
+SimpleMaintenanceScannerTest::scanEntireDatabase(int expected)
+{
+ for (int i = 0; i < expected; ++i) {
+ if (_scanner->scanNext().isDone()) {
+ return false;
+ }
+ }
+ return _scanner->scanNext().isDone();
+}
+
+void
+SimpleMaintenanceScannerTest::testReset()
+{
+ addBucketToDb(1);
+ addBucketToDb(3);
+
+ CPPUNIT_ASSERT(scanEntireDatabase(2));
+ std::string expected("PrioritizedBucket(BucketId(0x4000000000000001), pri VERY_HIGH)\n"
+ "PrioritizedBucket(BucketId(0x4000000000000003), pri VERY_HIGH)\n");
+ CPPUNIT_ASSERT_EQUAL(expected, _priorityDb->toString());
+
+ addBucketToDb(2);
+ CPPUNIT_ASSERT(scanEntireDatabase(0));
+ CPPUNIT_ASSERT_EQUAL(expected, _priorityDb->toString());
+
+ _scanner->reset();
+ CPPUNIT_ASSERT(scanEntireDatabase(3));
+
+ expected = "PrioritizedBucket(BucketId(0x4000000000000001), pri VERY_HIGH)\n"
+ "PrioritizedBucket(BucketId(0x4000000000000002), pri VERY_HIGH)\n"
+ "PrioritizedBucket(BucketId(0x4000000000000003), pri VERY_HIGH)\n";
+ CPPUNIT_ASSERT_EQUAL(sortLines(expected), sortLines(_priorityDb->toString()));
+}
+
+void
+SimpleMaintenanceScannerTest::testPendingMaintenanceOperationStatistics()
+{
+ addBucketToDb(1);
+ addBucketToDb(3);
+
+ std::string expectedEmpty("delete bucket: 0, merge bucket: 0, "
+ "split bucket: 0, join bucket: 0, "
+ "set bucket state: 0, garbage collection: 0");
+ {
+ auto stats(_scanner->getPendingMaintenanceStats());
+ CPPUNIT_ASSERT_EQUAL(expectedEmpty, stringifyGlobalPendingStats(stats));
+ }
+
+ CPPUNIT_ASSERT(scanEntireDatabase(2));
+
+ // All mock operations generated have the merge type.
+ {
+ auto stats(_scanner->getPendingMaintenanceStats());
+ std::string expected("delete bucket: 0, merge bucket: 2, "
+ "split bucket: 0, join bucket: 0, "
+ "set bucket state: 0, garbage collection: 0");
+ CPPUNIT_ASSERT_EQUAL(expected, stringifyGlobalPendingStats(stats));
+ }
+
+ _scanner->reset();
+ {
+ auto stats(_scanner->getPendingMaintenanceStats());
+ CPPUNIT_ASSERT_EQUAL(expectedEmpty, stringifyGlobalPendingStats(stats));
+ }
+}
+
+void
+SimpleMaintenanceScannerTest::perNodeMaintenanceStatsAreTracked()
+{
+ addBucketToDb(1);
+ addBucketToDb(3);
+ {
+ auto stats(_scanner->getPendingMaintenanceStats());
+ NodeMaintenanceStats emptyStats;
+ CPPUNIT_ASSERT_EQUAL(emptyStats, stats.perNodeStats.forNode(0));
+ }
+ CPPUNIT_ASSERT(scanEntireDatabase(2));
+ // Mock is currently hardwired to increment movingOut for node 1 and
+ // copyingIn for node 2 per bucket iterated (we've got 2).
+ auto stats(_scanner->getPendingMaintenanceStats());
+ {
+ NodeMaintenanceStats wantedNode1Stats;
+ wantedNode1Stats.movingOut = 2;
+ CPPUNIT_ASSERT_EQUAL(wantedNode1Stats, stats.perNodeStats.forNode(1));
+ }
+ {
+ NodeMaintenanceStats wantedNode2Stats;
+ wantedNode2Stats.copyingIn = 2;
+ CPPUNIT_ASSERT_EQUAL(wantedNode2Stats, stats.perNodeStats.forNode(2));
+ }
+}
+
+}
+}