| @@ -237,15 +237,67 @@ void init_utils(py::module m) { | |||||
| mgb::sys::TimedFuncInvoker::ins().fork_exec_impl_mainloop(user_data.c_str()); | mgb::sys::TimedFuncInvoker::ins().fork_exec_impl_mainloop(user_data.c_str()); | ||||
| }); | }); | ||||
| using mgb::PersistentCache; | 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: | public: | ||||
| mgb::Maybe<Blob> get(const std::string& category, const Blob& key) override { | 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 { | void put(const std::string& category, const Blob& key, const Blob& value) override { | ||||
| PYBIND11_OVERLOAD_PURE(void, PersistentCache, put, category, key, value); | PYBIND11_OVERLOAD_PURE(void, PersistentCache, put, category, key, value); | ||||
| } | } | ||||
| }; | }; | ||||
| py::class_<PersistentCache, PyPersistentCache, std::shared_ptr<PersistentCache>>(m, "PersistentCache") | py::class_<PersistentCache, PyPersistentCache, std::shared_ptr<PersistentCache>>(m, "PersistentCache") | ||||
| .def(py::init<>()) | .def(py::init<>()) | ||||