blob: 60537a9fc8b384825e0d056311ba7a38146e98f4 [file] [log] [blame]
/**
* Copyright 2015 Pivotal Software, Inc.
*
* Licensed 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 <atomic>
#include <cstddef>
#include <memory>
#include <string>
#include <vector>
#include "gtest/gtest.h"
#include "catalog/CatalogConfig.h"
#include "storage/EvictionPolicy.hpp"
#include "storage/StorageBlob.hpp"
#include "storage/StorageBlockInfo.hpp"
#include "storage/StorageConstants.hpp"
#include "storage/StorageManager.hpp"
#include "utility/ShardedLockManager.hpp"
#ifdef QUICKSTEP_HAVE_LIBNUMA
#include <numa.h>
#endif
namespace quickstep {
TEST(StorageManagerTest, NUMAAgnosticBlobTest) {
std::unique_ptr<StorageManager> storage_manager;
static constexpr std::size_t kNumSlots = 10;
storage_manager.reset(new StorageManager("temp_storage"));
// Create kNumSlots * kSlotSizeBytes of memory.
block_id blob_id = storage_manager->createBlob(kNumSlots);
MutableBlobReference blob_obj = storage_manager->getBlobMutable(blob_id);
char *blob_memory = static_cast<char*>(blob_obj->getMemoryMutable());
// Write some contents into the blob's memory.
for (std::size_t i = 0; i < kNumSlots * kSlotSizeBytes; ++i) {
blob_memory[i] = static_cast<char>(i);
}
// Dereference the blob.
blob_obj.release();
BlobReference new_blob_obj = storage_manager->getBlob(blob_id);
const char *new_blob_memory = static_cast<const char*>(new_blob_obj->getMemory());
// Read the contents of the blob and verify if they
// match with what was written previously.
for (std::size_t i = 0; i < kNumSlots * kSlotSizeBytes; ++i) {
EXPECT_EQ(static_cast<char>(i), new_blob_memory[i]);
}
}
#ifdef QUICKSTEP_HAVE_LIBNUMA
TEST(StorageManagerTest, NUMAAwareBlobTest) {
std::unique_ptr<StorageManager> storage_manager;
static constexpr std::size_t kNumSlots = 10;
storage_manager.reset(new StorageManager("temp_storage"));
const std::size_t num_numa_nodes = numa_num_configured_nodes();
block_id blob_id;
MutableBlobReference blob_obj;
char* blob_memory;
BlobReference new_blob_obj;
const char* new_blob_memory;
for (std::size_t numa_node = 0; numa_node < num_numa_nodes; ++numa_node) {
blob_id = storage_manager->createBlob(kNumSlots, numa_node);
blob_obj =
storage_manager->getBlobMutable(blob_id, numa_node);
blob_memory =
static_cast<char*>(blob_obj->getMemoryMutable());
// Write some contents into the memory.
for (std::size_t i = 0; i < kNumSlots * kSlotSizeBytes; ++i) {
blob_memory[i] = static_cast<char>(i);
}
// Dereference the blob.
blob_obj.release();
new_blob_obj =
storage_manager->getBlob(blob_id, numa_node);
new_blob_memory =
static_cast<const char*>(new_blob_obj->getMemory());
// Read the contents of the blob on the same NUMA node on which the blob was
// created and verify if they match with what we wrote into the blob.
for (std::size_t i = 0; i < kNumSlots * kSlotSizeBytes; ++i) {
EXPECT_EQ(static_cast<char>(i), new_blob_memory[i]);
}
}
}
TEST(StorageManagerTest, DifferentNUMANodeBlobTest) {
std::unique_ptr<StorageManager> storage_manager;
static constexpr std::size_t kNumSlots = 10;
storage_manager.reset(new StorageManager("temp_storage"));
const std::size_t num_numa_nodes = numa_num_configured_nodes();
block_id blob_id;
MutableBlobReference blob_obj;
char* blob_memory;
BlobReference new_blob_obj;
const char* new_blob_memory;
std::size_t new_numa_node = 0;
for (std::size_t numa_node = 0; numa_node < num_numa_nodes; ++numa_node) {
blob_id = storage_manager->createBlob(kNumSlots, numa_node);
blob_obj =
storage_manager->getBlobMutable(blob_id, numa_node);
blob_memory =
static_cast<char*>(blob_obj->getMemoryMutable());
// Write some contents into the memory.
for (std::size_t i = 0; i < kNumSlots * kSlotSizeBytes; ++i) {
blob_memory[i] = static_cast<char>(i);
}
// Dereference the blob.
blob_obj.release();
new_numa_node = (numa_node + 1) % num_numa_nodes;
new_blob_obj =
storage_manager->getBlob(blob_id, new_numa_node);
new_blob_memory =
static_cast<const char*>(new_blob_obj->getMemory());
// Read the contents of the blob by giving a different NUMA node hint and
// verify if we still read the same blob that we actually wrote to.
for (std::size_t i = 0; i < kNumSlots * kSlotSizeBytes; ++i) {
EXPECT_EQ(static_cast<char>(i), new_blob_memory[i]);
}
}
}
TEST(StorageManagerTest, DifferentNUMANodeBlobTestWithEviction) {
EvictionPolicy *eviction_policy = LRUKEvictionPolicyFactory::ConstructLRUKEvictionPolicy(
2, std::chrono::seconds(100));
EvictionPolicy::Status status;
static constexpr std::size_t kNumSlots = 10;
const block_id_domain block_domain = 1000;
// Set the max_memory_usage to 4 GB.
const size_t max_memory_usage = 2000;
std::unique_ptr<StorageManager> storage_manager;
storage_manager.reset(
new StorageManager("temp_storage", block_domain, max_memory_usage, eviction_policy));
const std::size_t num_numa_nodes = numa_num_configured_nodes();
block_id blob_id;
MutableBlobReference blob_obj;
char* blob_memory;
BlobReference new_blob_obj;
const char* new_blob_memory;
std::size_t new_numa_node = 0;
for (std::size_t numa_node = 0; numa_node < num_numa_nodes; ++numa_node) {
blob_id = storage_manager->createBlob(kNumSlots, numa_node);
blob_obj =
storage_manager->getBlobMutable(blob_id, numa_node);
blob_memory =
static_cast<char*>(blob_obj->getMemoryMutable());
// Write some contents into the memory.
for (std::size_t i = 0; i < kNumSlots * kSlotSizeBytes; ++i) {
blob_memory[i] = static_cast<char>(i);
}
// Dereference the blob.
blob_obj.release();
// Choose a blob for eviction.
status = storage_manager->eviction_policy_->chooseBlockToEvict(&blob_id);
ASSERT_EQ(EvictionPolicy::Status::kOk, status);
// Save the blob to disk.
storage_manager->saveBlockOrBlob(blob_id, true);
// Evict the blob from the buffer pool.
storage_manager->evictBlockOrBlob(blob_id);
// Inform the eviction policy that this blob has been evicted.
storage_manager->eviction_policy_->blockEvicted(blob_id);
new_numa_node = (numa_node + 1) % num_numa_nodes;
new_blob_obj =
storage_manager->getBlob(blob_id, new_numa_node);
new_blob_memory =
static_cast<const char*>(new_blob_obj->getMemory());
// Read the contents of the blob by giving a different NUMA node hint and
// verify if we still read the same blob that we actually wrote to.
for (std::size_t i = 0; i < kNumSlots * kSlotSizeBytes; ++i) {
EXPECT_EQ(static_cast<char>(i), new_blob_memory[i]);
}
}
}
#endif // QUICKSTEP_HAVE_LIBNUMA
} // namespace quickstep