diff --git a/examples/M/.gitignore b/examples/M/.gitignore new file mode 100644 index 0000000..f5341a4 --- /dev/null +++ b/examples/M/.gitignore @@ -0,0 +1 @@ +volatile diff --git a/examples/M/CMakeLists.txt b/examples/M/CMakeLists.txt new file mode 100644 index 0000000..a28bb6a --- /dev/null +++ b/examples/M/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# 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. + +cmake_minimum_required (VERSION 3.12) + +project (cachelib-cmake-test-project VERSION 0.1) + +find_package(cachelib CONFIG REQUIRED) + +add_executable(multitier-cache-example main.cpp) + +target_link_libraries(multitier-cache-example cachelib) diff --git a/examples/M/README.txt b/examples/M/README.txt new file mode 100644 index 0000000..a377b17 --- /dev/null +++ b/examples/M/README.txt @@ -0,0 +1,12 @@ +Using pmem as a tier in cachelib + +This example is intended for C++ programmers. + +This is example consists of these files: + +main.cpp -- ecample creating a mult-tier cache using pmem +build.sh -- rules for building this example +run.sh -- one way to run this example to illustrate what it does + +To build this example run: ./build.sh +To run it and see what it illustrates run: ./run.sh diff --git a/examples/M/build.sh b/examples/M/build.sh new file mode 100755 index 0000000..5833384 --- /dev/null +++ b/examples/M/build.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# 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. + +set -e + +# Root directory for the CacheLib project +#CLBASE="$PWD/../.." +CLBASE="/CacheLib" + +# Additional "FindXXX.cmake" files are here (e.g. FindSodium.cmake) +CLCMAKE="$CLBASE/cachelib/cmake" + +# After ensuring we are in the correct directory, set the installation prefix" +PREFIX="$CLBASE/opt/cachelib/" + +CMAKE_PARAMS="-DCMAKE_INSTALL_PREFIX='$PREFIX' -DCMAKE_MODULE_PATH='$CLCMAKE'" + +CMAKE_PREFIX_PATH="$PREFIX/lib/cmake:$PREFIX/lib64/cmake:$PREFIX/lib:$PREFIX/lib64:$PREFIX:${CMAKE_PREFIX_PATH:-}" +export CMAKE_PREFIX_PATH +PKG_CONFIG_PATH="$PREFIX/lib/pkgconfig:$PREFIX/lib64/pkgconfig:${PKG_CONFIG_PATH:-}" +export PKG_CONFIG_PATH +LD_LIBRARY_PATH="$PREFIX/lib:$PREFIX/lib64:${LD_LIBRARY_PATH:-}" +export LD_LIBRARY_PATH + +mkdir -p build +cd build +cmake $CMAKE_PARAMS .. +make diff --git a/examples/M/main.cpp b/examples/M/main.cpp new file mode 100644 index 0000000..e2836de --- /dev/null +++ b/examples/M/main.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * 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 "cachelib/allocator/CacheAllocator.h" +#include "cachelib/allocator/MemoryTierCacheConfig.h" +#include "folly/init/Init.h" + +namespace facebook { +namespace cachelib_examples { +using Cache = cachelib::LruAllocator; // or Lru2QAllocator, or TinyLFUAllocator +using CacheConfig = typename Cache::Config; +using CacheKey = typename Cache::Key; +using CacheItemHandle = typename Cache::ReadHandle; +using MemoryTierCacheConfig = typename cachelib::MemoryTierCacheConfig; + +// Global cache object and a default cache pool +std::unique_ptr gCache_; +cachelib::PoolId defaultPool_; + +void initializeCache() { + CacheConfig config; + config + .setCacheSize(48 * 1024 * 1024) // 48 MB + .setCacheName("MultiTier Cache") + .enableCachePersistence("/tmp") + .setAccessConfig( + {25 /* bucket power */, 10 /* lock power */}) // assuming caching 20 + // million items + .configureMemoryTiers({ + MemoryTierCacheConfig::fromShm().setRatio(1), + MemoryTierCacheConfig::fromFile("/pmem/file1").setRatio(2)}) + .validate(); // will throw if bad config + gCache_ = std::make_unique(Cache::SharedMemNew, config); + defaultPool_ = + gCache_->addPool("default", gCache_->getCacheMemoryStats().cacheSize); +} + +void destroyCache() { gCache_.reset(); } + +CacheItemHandle get(CacheKey key) { return gCache_->find(key); } + +bool put(CacheKey key, const std::string& value) { + auto handle = gCache_->allocate(defaultPool_, key, value.size()); + if (!handle) { + return false; // cache may fail to evict due to too many pending writes + } + std::memcpy(handle->getMemory(), value.data(), value.size()); + gCache_->insertOrReplace(handle); + return true; +} +} // namespace cachelib_examples +} // namespace facebook + +using namespace facebook::cachelib_examples; + +int main(int argc, char** argv) { + folly::init(&argc, &argv); + + initializeCache(); + + std::string value(4*1024, 'X'); // 4 KB value + const size_t NUM_ITEMS = 13000; + + // Use cache + { + for(size_t i = 0; i < NUM_ITEMS; ++i) { + std::string key = "key" + std::to_string(i); + auto res = put(key, value); + + std::ignore = res; + assert(res); + } + + size_t nFound = 0; + size_t nNotFound = 0; + for(size_t i = 0; i < NUM_ITEMS; ++i) { + std::string key = "key" + std::to_string(i); + auto item = get(key); + if(item) { + ++nFound; + folly::StringPiece sp{reinterpret_cast(item->getMemory()), + item->getSize()}; + std::ignore = sp; + assert(sp == value); + } else { + ++nNotFound; + } + } + std::cout << "Found:\t\t" << nFound << " items\n" + << "Not found:\t" << nNotFound << " items" << std::endl; + } + + destroyCache(); +} diff --git a/examples/M/run.sh b/examples/M/run.sh new file mode 100755 index 0000000..5746c93 --- /dev/null +++ b/examples/M/run.sh @@ -0,0 +1,7 @@ +#!/bin/bash -ex +# +# shell commands to run this example +# + +# run the example program on pmem +./build/multitier-cache-example