// Copyright (c) 2016, Facebook, Inc. All rights reserved. // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). #pragma once #if defined(LUA) && !defined(ROCKSDB_LITE) // lua headers extern "C" { #include #include #include } #include #include #include #include "rocksdb/compaction_filter.h" #include "rocksdb/env.h" #include "rocksdb/slice.h" #include "rocksdb/utilities/lua/rocks_lua_custom_library.h" #include "rocksdb/utilities/lua/rocks_lua_util.h" namespace rocksdb { namespace lua { struct RocksLuaCompactionFilterOptions { // The lua script in string that implements all necessary CompactionFilter // virtual functions. The specified lua_script must implement the following // functions, which are Name and Filter, as described below. // // 0. The Name function simply returns a string representing the name of // the lua script. If there's any erorr in the Name function, an // empty string will be used. // --- Example // function Name() // return "DefaultLuaCompactionFilter" // end // // // 1. The script must contains a function called Filter, which implements // CompactionFilter::Filter() , takes three input arguments, and returns // three values as the following API: // // function Filter(level, key, existing_value) // ... // return is_filtered, is_changed, new_value // end // // Note that if ignore_value is set to true, then Filter should implement // the following API: // // function Filter(level, key) // ... // return is_filtered // end // // If there're any error in the Filter() function, then it will keep // the input key / value pair. // // -- Input // The function must take three arguments (integer, string, string), // which map to "level", "key", and "existing_value" passed from // RocksDB. // // -- Output // The function must return three values (boolean, boolean, string). // - is_filtered: if the first return value is true, then it indicates // the input key / value pair should be filtered. // - is_changed: if the second return value is true, then it indicates // the existing_value needs to be changed, and the resulting value // is stored in the third return value. // - new_value: if the second return value is true, then this third // return value stores the new value of the input key / value pair. // // -- Examples // -- a filter that keeps all key-value pairs // function Filter(level, key, existing_value) // return false, false, "" // end // // -- a filter that keeps all keys and change their values to "Rocks" // function Filter(level, key, existing_value) // return false, true, "Rocks" // end std::string lua_script; // If set to true, then existing_value will not be passed to the Filter // function, and the Filter function only needs to return a single boolean // flag indicating whether to filter out this key or not. // // function Filter(level, key) // ... // return is_filtered // end bool ignore_value = false; // A boolean flag to determine whether to ignore snapshots. bool ignore_snapshots = false; // When specified a non-null pointer, the first "error_limit_per_filter" // errors of each CompactionFilter that is lua related will be included // in this log. std::shared_ptr error_log; // The number of errors per CompactionFilter will be printed // to error_log. int error_limit_per_filter = 1; // A string to luaL_reg array map that allows the Lua CompactionFilter // to use custom C library. The string will be used as the library // name in Lua. std::vector> libraries; /////////////////////////////////////////////////////////////////////////// // NOT YET SUPPORTED // The name of the Lua function in "lua_script" that implements // CompactionFilter::FilterMergeOperand(). The function must take // three input arguments (integer, string, string), which map to "level", // "key", and "operand" passed from the RocksDB. In addition, the // function must return a single boolean value, indicating whether // to filter the input key / operand. // // DEFAULT: the default implementation always returns false. // @see CompactionFilter::FilterMergeOperand }; class RocksLuaCompactionFilterFactory : public CompactionFilterFactory { public: explicit RocksLuaCompactionFilterFactory( const RocksLuaCompactionFilterOptions opt); virtual ~RocksLuaCompactionFilterFactory() {} std::unique_ptr CreateCompactionFilter( const CompactionFilter::Context& context) override; // Change the Lua script so that the next compaction after this // function call will use the new Lua script. void SetScript(const std::string& new_script); // Obtain the current Lua script std::string GetScript(); const char* Name() const override; private: RocksLuaCompactionFilterOptions opt_; std::string name_; // A lock to protect "opt_" to make it dynamically changeable. std::mutex opt_mutex_; }; // A wrapper class that invokes Lua script to perform CompactionFilter // functions. class RocksLuaCompactionFilter : public rocksdb::CompactionFilter { public: explicit RocksLuaCompactionFilter(const RocksLuaCompactionFilterOptions& opt) : options_(opt), lua_state_wrapper_(opt.lua_script, opt.libraries), error_count_(0), name_("") {} virtual bool Filter(int level, const Slice& key, const Slice& existing_value, std::string* new_value, bool* value_changed) const override; // Not yet supported virtual bool FilterMergeOperand(int level, const Slice& key, const Slice& operand) const override { return false; } virtual bool IgnoreSnapshots() const override; virtual const char* Name() const override; protected: void LogLuaError(const char* format, ...) const; RocksLuaCompactionFilterOptions options_; LuaStateWrapper lua_state_wrapper_; mutable int error_count_; mutable std::string name_; }; } // namespace lua } // namespace rocksdb #endif // defined(LUA) && !defined(ROCKSDB_LITE)