blob: 046e3dc3566e51ce5057801912f7cea693f2a94b [file] [log] [blame]
/*
* Copyright 2010 Google 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.
*/
// Author: jmarantz@google.com (Joshua Marantz)
// Unit-test the threadsafe cache. Creates an LRU-cache first, and then
// wraps a thread-safe cache around that and a mutex
#include "pagespeed/kernel/sharedmem/shared_mem_cache.h"
#include <vector>
#include "pagespeed/kernel/base/basictypes.h"
#include "pagespeed/kernel/base/google_message_handler.h"
#include "pagespeed/kernel/base/gtest.h"
#include "pagespeed/kernel/base/md5_hasher.h"
#include "pagespeed/kernel/base/scoped_ptr.h"
#include "pagespeed/kernel/base/shared_string.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/base/thread_system.h"
#include "pagespeed/kernel/base/timer.h"
#include "pagespeed/kernel/cache/cache_interface.h"
#include "pagespeed/kernel/cache/cache_spammer.h"
#include "pagespeed/kernel/cache/cache_test_base.h"
#include "pagespeed/kernel/sharedmem/inprocess_shared_mem.h"
#include "pagespeed/kernel/util/platform.h"
#include "pagespeed/kernel/base/abstract_shared_mem.h"
namespace {
const int kMaxSize = 100;
const int kNumThreads = 4;
const int kNumIters = 10000;
const int kNumInserts = 10;
const int kSectors = 128;
const char kSegmentName[] = "/shared_cache_spammer_test_segment";
}
namespace net_instaweb {
class SharedMemCacheSpammerTest : public testing::Test {
protected:
typedef SharedMemCache<64> ShmCache;
SharedMemCacheSpammerTest()
: timer_(Platform::CreateTimer()),
thread_system_(Platform::CreateThreadSystem()),
in_process_shared_mem_(thread_system_.get()) {
cache_.reset(MakeCache());
CHECK(cache_->Initialize());
CHECK(cache_->Attach());
}
~SharedMemCacheSpammerTest() {
ShmCache::GlobalCleanup(&in_process_shared_mem_,
kSegmentName,
&message_handler_);
}
ShmCache* MakeCache() {
int entries, blocks;
int64 size_cap;
ShmCache::ComputeDimensions(
kMaxSize /* size_kb */,
2 /* block/entry ratio, based empirically off load tests */,
kSectors, &entries, &blocks, &size_cap);
ShmCache* cache = new ShmCache(
&in_process_shared_mem_,
kSegmentName,
timer_.get(),
&hasher_,
kSectors,
entries, /* entries per sector */
blocks /* blocks per sector*/,
&message_handler_);
return cache;
}
void TestHelper(bool expecting_evictions, bool do_deletes,
const char* value_pattern) {
CacheSpammer::RunTests(kNumThreads, kNumIters, kNumInserts,
expecting_evictions, do_deletes, value_pattern,
cache_.get(),
thread_system_.get());
cache_->SanityCheck();
}
scoped_ptr<Timer> timer_;
scoped_ptr<ThreadSystem> thread_system_;
GoogleMessageHandler message_handler_;
MD5Hasher hasher_;
InProcessSharedMem in_process_shared_mem_;
scoped_ptr<ShmCache> cache_;
private:
DISALLOW_COPY_AND_ASSIGN(SharedMemCacheSpammerTest);
};
TEST_F(SharedMemCacheSpammerTest, BasicOperation) {
SharedString put_buffer("val");
cache_->Put("key", &put_buffer);
CacheTestBase::Callback callback;
cache_->Get("key", &callback);
EXPECT_TRUE(callback.called());
EXPECT_EQ(CacheInterface::kAvailable, callback.state());
EXPECT_EQ(GoogleString("val"), callback.value()->Value());
}
TEST_F(SharedMemCacheSpammerTest, SpamCacheEvictionsNoDeletions) {
// By writing 10 inserts, with 5 bytes of value "valu%d" plus 5 bytes
// of key, we should never evict anything. In this test the
// threads can each check that all their Gets succeed.
//
// We have expect_evictions set here to true. This is not actually because
// we expect evictions --- we are inserting just 10 small key/value pairs;
// but because SharedMemCache::Get happening concurrently to an in-progress
// Put to the same key will miss.
TestHelper(true, false, "valu");
}
TEST_F(SharedMemCacheSpammerTest, SpamCacheWithEvictions) {
// By writing 10 inserts, with 6 bytes of value "value%d" plus 5
// bytes of key, we may get evictions. In this test the threads
// ignores the return value from Get, but we ensure that the
// eviction logic in the cache is tested in a multi-threaded context.
TestHelper(true, false, "value");
}
TEST_F(SharedMemCacheSpammerTest, SpamCacheWithDeletions) {
// In this testcase, we expect no evictions, but we will be
// doing some deletions, so we do not require Gets to succeed.
TestHelper(false, true, "valu");
}
TEST_F(SharedMemCacheSpammerTest, SpamCacheWithDeletionsAndEvictions) {
// In this testcase, we expect evictions, and we will also be
// doing deletions.
TestHelper(true, true, "value");
}
} // namespace net_instaweb