blob: 922e617a2b24114194373e812737f4eb3200290d [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#include <glog/logging.h>
#include <glog/stl_logging.h>
#include <gtest/gtest.h>
#include "kudu/fs/block_manager.h"
#include "kudu/fs/fs_manager.h"
#include "kudu/gutil/strings/util.h"
#include "kudu/util/metrics.h"
#include "kudu/util/test_macros.h"
#include "kudu/util/test_util.h"
using std::shared_ptr;
namespace kudu {
class FsManagerTestBase : public KuduTest {
public:
void SetUp() OVERRIDE {
KuduTest::SetUp();
// Initialize File-System Layout
ReinitFsManager();
ASSERT_OK(fs_manager_->CreateInitialFileSystemLayout());
ASSERT_OK(fs_manager_->Open());
}
void ReinitFsManager() {
ReinitFsManager(GetTestPath("fs_root"), { GetTestPath("fs_root")} );
}
void ReinitFsManager(const string& wal_path, const vector<string>& data_paths) {
// Blow away the old memtrackers first.
fs_manager_.reset();
FsManagerOpts opts;
opts.wal_path = wal_path;
opts.data_paths = data_paths;
fs_manager_.reset(new FsManager(env_.get(), opts));
}
void TestReadWriteDataFile(const Slice& data) {
uint8_t buffer[64];
DCHECK_LT(data.size(), sizeof(buffer));
// Test Write
gscoped_ptr<fs::WritableBlock> writer;
ASSERT_OK(fs_manager()->CreateNewBlock(&writer));
ASSERT_OK(writer->Append(data));
ASSERT_OK(writer->Close());
// Test Read
Slice result;
gscoped_ptr<fs::ReadableBlock> reader;
ASSERT_OK(fs_manager()->OpenBlock(writer->id(), &reader));
ASSERT_OK(reader->Read(0, data.size(), &result, buffer));
ASSERT_EQ(data.size(), result.size());
ASSERT_EQ(0, result.compare(data));
}
FsManager *fs_manager() const { return fs_manager_.get(); }
private:
gscoped_ptr<FsManager> fs_manager_;
};
TEST_F(FsManagerTestBase, TestBaseOperations) {
fs_manager()->DumpFileSystemTree(std::cout);
TestReadWriteDataFile(Slice("test0"));
TestReadWriteDataFile(Slice("test1"));
fs_manager()->DumpFileSystemTree(std::cout);
}
TEST_F(FsManagerTestBase, TestIllegalPaths) {
vector<string> illegal = { "", "asdf", "/foo\n\t" };
for (const string& path : illegal) {
ReinitFsManager(path, { path });
ASSERT_TRUE(fs_manager()->CreateInitialFileSystemLayout().IsIOError());
}
}
TEST_F(FsManagerTestBase, TestMultiplePaths) {
string wal_path = GetTestPath("a");
vector<string> data_paths = { GetTestPath("a"), GetTestPath("b"), GetTestPath("c") };
ReinitFsManager(wal_path, data_paths);
ASSERT_OK(fs_manager()->CreateInitialFileSystemLayout());
ASSERT_OK(fs_manager()->Open());
}
TEST_F(FsManagerTestBase, TestMatchingPathsWithMismatchedSlashes) {
string wal_path = GetTestPath("foo");
vector<string> data_paths = { wal_path + "/" };
ReinitFsManager(wal_path, data_paths);
ASSERT_OK(fs_manager()->CreateInitialFileSystemLayout());
}
TEST_F(FsManagerTestBase, TestDuplicatePaths) {
string path = GetTestPath("foo");
ReinitFsManager(path, { path, path, path });
ASSERT_OK(fs_manager()->CreateInitialFileSystemLayout());
ASSERT_EQ(vector<string>({ JoinPathSegments(path, fs_manager()->kDataDirName) }),
fs_manager()->GetDataRootDirs());
}
TEST_F(FsManagerTestBase, TestListTablets) {
vector<string> tablet_ids;
ASSERT_OK(fs_manager()->ListTabletIds(&tablet_ids));
ASSERT_EQ(0, tablet_ids.size());
string path = fs_manager()->GetTabletMetadataDir();
gscoped_ptr<WritableFile> writer;
ASSERT_OK(env_->NewWritableFile(
JoinPathSegments(path, "foo.tmp"), &writer));
ASSERT_OK(env_->NewWritableFile(
JoinPathSegments(path, "foo.tmp.abc123"), &writer));
ASSERT_OK(env_->NewWritableFile(
JoinPathSegments(path, ".hidden"), &writer));
ASSERT_OK(env_->NewWritableFile(
JoinPathSegments(path, "a_tablet_sort_of"), &writer));
ASSERT_OK(fs_manager()->ListTabletIds(&tablet_ids));
ASSERT_EQ(1, tablet_ids.size()) << tablet_ids;
}
TEST_F(FsManagerTestBase, TestCannotUseNonEmptyFsRoot) {
string path = GetTestPath("new_fs_root");
ASSERT_OK(env_->CreateDir(path));
{
gscoped_ptr<WritableFile> writer;
ASSERT_OK(env_->NewWritableFile(
JoinPathSegments(path, "some_file"), &writer));
}
// Try to create the FS layout. It should fail.
ReinitFsManager(path, { path });
ASSERT_TRUE(fs_manager()->CreateInitialFileSystemLayout().IsAlreadyPresent());
}
TEST_F(FsManagerTestBase, TestEmptyWALPath) {
ReinitFsManager("", vector<string>());
Status s = fs_manager()->CreateInitialFileSystemLayout();
ASSERT_TRUE(s.IsIOError());
ASSERT_STR_CONTAINS(s.ToString(), "directory (fs_wal_dir) not provided");
}
TEST_F(FsManagerTestBase, TestOnlyWALPath) {
string path = GetTestPath("new_fs_root");
ASSERT_OK(env_->CreateDir(path));
ReinitFsManager(path, vector<string>());
ASSERT_OK(fs_manager()->CreateInitialFileSystemLayout());
ASSERT_TRUE(HasPrefixString(fs_manager()->GetWalsRootDir(), path));
ASSERT_TRUE(HasPrefixString(fs_manager()->GetConsensusMetadataDir(), path));
ASSERT_TRUE(HasPrefixString(fs_manager()->GetTabletMetadataDir(), path));
vector<string> data_dirs = fs_manager()->GetDataRootDirs();
ASSERT_EQ(1, data_dirs.size());
ASSERT_TRUE(HasPrefixString(data_dirs[0], path));
}
} // namespace kudu