|
|
@@ -237,15 +237,67 @@ void init_utils(py::module m) { |
|
|
|
mgb::sys::TimedFuncInvoker::ins().fork_exec_impl_mainloop(user_data.c_str()); |
|
|
|
}); |
|
|
|
using mgb::PersistentCache; |
|
|
|
class PyPersistentCache: public mgb::PersistentCache{ |
|
|
|
class PyPersistentCache: public mgb::PersistentCache { |
|
|
|
private: |
|
|
|
using KeyPair = std::pair<std::string, std::string>; |
|
|
|
using BlobPtr = std::unique_ptr<Blob, void(*)(Blob*)>; |
|
|
|
|
|
|
|
static size_t hash_key_pair(const KeyPair& kp) { |
|
|
|
std::hash<std::string> hasher; |
|
|
|
return hasher(kp.first) ^ hasher(kp.second); |
|
|
|
} |
|
|
|
|
|
|
|
std::string blob_to_str(const Blob& key) { |
|
|
|
return std::string(reinterpret_cast<const char*>(key.ptr), key.size); |
|
|
|
} |
|
|
|
|
|
|
|
BlobPtr copy_blob(const Blob& blob) { |
|
|
|
auto blob_deleter = [](Blob* blob){ |
|
|
|
if (blob) { |
|
|
|
std::free(const_cast<void*>(blob->ptr)); |
|
|
|
delete blob; |
|
|
|
} |
|
|
|
}; |
|
|
|
auto blob_ptr = BlobPtr{ new Blob(), blob_deleter }; |
|
|
|
blob_ptr->ptr = std::malloc(blob.size); |
|
|
|
std::memcpy(const_cast<void*>(blob_ptr->ptr), blob.ptr, blob.size); |
|
|
|
blob_ptr->size = blob.size; |
|
|
|
return blob_ptr; |
|
|
|
} |
|
|
|
|
|
|
|
BlobPtr str_to_blob(const std::string& str) { |
|
|
|
auto blob = Blob{ str.data(), str.size() }; |
|
|
|
return copy_blob(blob); |
|
|
|
} |
|
|
|
|
|
|
|
std::unique_ptr<Blob, void(*)(Blob*)> empty_blob() { |
|
|
|
return BlobPtr{ nullptr, [](Blob* blob){} }; |
|
|
|
} |
|
|
|
public: |
|
|
|
mgb::Maybe<Blob> get(const std::string& category, const Blob& key) override { |
|
|
|
PYBIND11_OVERLOAD_PURE(mgb::Maybe<Blob>, PersistentCache, get, category, key); |
|
|
|
thread_local std::unordered_map<KeyPair, BlobPtr, mgb::pairhash> m_local_cache; |
|
|
|
auto py_get = [this](const std::string& category, const Blob& key) -> mgb::Maybe<Blob> { |
|
|
|
PYBIND11_OVERLOAD_PURE(mgb::Maybe<Blob>, PersistentCache, get, category, key); |
|
|
|
}; |
|
|
|
KeyPair kp = { category, blob_to_str(key) }; |
|
|
|
auto iter = m_local_cache.find(kp); |
|
|
|
if (iter == m_local_cache.end()) { |
|
|
|
auto py_ret = py_get(category, key); |
|
|
|
if (!py_ret.valid()) { |
|
|
|
iter = m_local_cache.insert({kp, empty_blob()}).first; |
|
|
|
} else { |
|
|
|
iter = m_local_cache.insert({kp, copy_blob(py_ret.val())}).first; |
|
|
|
} |
|
|
|
} |
|
|
|
if (iter->second) { |
|
|
|
return *iter->second; |
|
|
|
} else { |
|
|
|
return {}; |
|
|
|
} |
|
|
|
} |
|
|
|
void put(const std::string& category, const Blob& key, const Blob& value) override { |
|
|
|
PYBIND11_OVERLOAD_PURE(void, PersistentCache, put, category, key, value); |
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
py::class_<PersistentCache, PyPersistentCache, std::shared_ptr<PersistentCache>>(m, "PersistentCache") |
|
|
|
.def(py::init<>()) |
|
|
|