mirror of
https://github.com/openappsec/openappsec.git
synced 2025-09-29 19:24:26 +03:00
First release of open-appsec source code
This commit is contained in:
220
core/include/general/table/entry_impl.h
Normal file
220
core/include/general/table/entry_impl.h
Normal file
@@ -0,0 +1,220 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (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.
|
||||
|
||||
#ifndef __ENTRY_IMPL_H__
|
||||
#define __ENTRY_IMPL_H__
|
||||
|
||||
#ifndef __TABLE_IMPL_H__
|
||||
#error "entry_impl.h should not be included directly"
|
||||
#endif // __TABLE_IMPL_H__
|
||||
|
||||
USE_DEBUG_FLAG(D_TABLE);
|
||||
|
||||
template <typename Key>
|
||||
class Table<Key>::Impl::Entry
|
||||
{
|
||||
using KeyNodePtr = TableHelper::KeyNodePtr<Key>;
|
||||
using ListInterface = TableHelper::I_InternalTableList<KeyNodePtr> *;
|
||||
using ExpirationInterface = TableHelper::I_InternalTableExpiration<Key, ExpIter> *;
|
||||
using ms = std::chrono::microseconds;
|
||||
public:
|
||||
Entry(ListInterface _table, ExpirationInterface _expiration, const Key &key, const KeyNodePtr &ptr, ms expire);
|
||||
bool hasState(std::type_index index) const;
|
||||
bool createState(const std::type_index &index, std::unique_ptr<TableOpaqueBase> &&ptr);
|
||||
bool delState(const std::type_index &index);
|
||||
TableOpaqueBase * getState(const std::type_index &index);
|
||||
void addKey(const Key &key, const KeyNodePtr &ptr);
|
||||
void removeSelf();
|
||||
void setExpiration(ms expire);
|
||||
std::chrono::microseconds getExpiration();
|
||||
std::vector<Key> getKeys();
|
||||
void uponEnteringContext();
|
||||
void uponLeavingContext();
|
||||
|
||||
template <class Archive>
|
||||
void save(Archive &ar) const;
|
||||
template <class Archive>
|
||||
void load(Archive &ar);
|
||||
|
||||
private:
|
||||
ListInterface table;
|
||||
ExpirationInterface expiration;
|
||||
std::unordered_map<Key, KeyNodePtr> keys;
|
||||
std::unordered_map<std::type_index, std::unique_ptr<TableOpaqueBase>> opaques;
|
||||
ExpIter expr_iter;
|
||||
};
|
||||
|
||||
template <typename Key>
|
||||
Table<Key>::Impl::Entry::Entry(
|
||||
ListInterface _table,
|
||||
ExpirationInterface _expiration,
|
||||
const Key &key,
|
||||
const KeyNodePtr &ptr,
|
||||
ms expire)
|
||||
:
|
||||
table(_table),
|
||||
expiration(_expiration)
|
||||
{
|
||||
addKey(key, ptr);
|
||||
expr_iter = expiration->addExpiration(expire, key);
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
bool
|
||||
Table<Key>::Impl::Entry::hasState(std::type_index index) const
|
||||
{
|
||||
return opaques.count(index) != 0;
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
bool
|
||||
Table<Key>::Impl::Entry::createState(const std::type_index &index, std::unique_ptr<TableOpaqueBase> &&ptr)
|
||||
{
|
||||
if (hasState(index)) {
|
||||
dbgError(D_TABLE) << "Failed to recreate a state of type " << index.name();
|
||||
return false;
|
||||
}
|
||||
|
||||
dbgTrace(D_TABLE) << "Creating a state of type " << index.name();
|
||||
return opaques.emplace(index, std::move(ptr)).second;
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
bool
|
||||
Table<Key>::Impl::Entry::delState(const std::type_index &index)
|
||||
{
|
||||
dbgTrace(D_TABLE) << "Deleting state of type " << index.name();
|
||||
auto iter = opaques.find(index);
|
||||
if (iter == opaques.end()) return false;
|
||||
opaques.erase(iter);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
TableOpaqueBase *
|
||||
Table<Key>::Impl::Entry::getState(const std::type_index &index)
|
||||
{
|
||||
auto iter = opaques.find(index);
|
||||
if (iter == opaques.end()) return nullptr;
|
||||
return iter->second.get();
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void
|
||||
Table<Key>::Impl::Entry::addKey(const Key &key, const KeyNodePtr &ptr)
|
||||
{
|
||||
keys[key] = ptr;
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void
|
||||
Table<Key>::Impl::Entry::removeSelf()
|
||||
{
|
||||
expiration->removeExpiration(expr_iter);
|
||||
for (auto &iter : keys) {
|
||||
table->removeKey(iter.second);
|
||||
}
|
||||
keys.clear();
|
||||
opaques.clear();
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void
|
||||
Table<Key>::Impl::Entry::setExpiration(ms expire)
|
||||
{
|
||||
expiration->removeExpiration(expr_iter);
|
||||
expr_iter = expiration->addExpiration(expire, keys.begin()->first);
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
std::chrono::microseconds
|
||||
Table<Key>::Impl::Entry::getExpiration()
|
||||
{
|
||||
return expr_iter->getExpiration();
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
std::vector<Key>
|
||||
Table<Key>::Impl::Entry::getKeys()
|
||||
{
|
||||
std::vector<Key> keys_vec;
|
||||
keys_vec.reserve(keys.size());
|
||||
for (auto &iter : keys) {
|
||||
keys_vec.emplace_back(iter.first);
|
||||
}
|
||||
return keys_vec;
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void
|
||||
Table<Key>::Impl::Entry::uponEnteringContext()
|
||||
{
|
||||
for (auto &opauqe : opaques) {
|
||||
opauqe.second->uponEnteringContext();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void
|
||||
Table<Key>::Impl::Entry::uponLeavingContext()
|
||||
{
|
||||
for (auto &opauqe : opaques) {
|
||||
opauqe.second->uponLeavingContext();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
template <class Archive>
|
||||
void
|
||||
Table<Key>::Impl::Entry::save(Archive &ar) const
|
||||
{
|
||||
std::vector<std::string> opaque_names;
|
||||
opaque_names.reserve(opaques.size());
|
||||
for (auto &iter : opaques) {
|
||||
opaque_names.emplace_back(iter.second->nameOpaque());
|
||||
}
|
||||
|
||||
ar(cereal::make_nvp("opaque_names", opaque_names));
|
||||
|
||||
for (auto &iter : opaques) {
|
||||
// 0 is used currently until supporting versions
|
||||
iter.second->saveOpaque(ar, 0);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
template <class Archive>
|
||||
void
|
||||
Table<Key>::Impl::Entry::load(Archive &ar)
|
||||
{
|
||||
std::vector<std::string> opaque_names;
|
||||
ar(cereal::make_nvp("opaque_names", opaque_names));
|
||||
|
||||
auto &rep = ::cereal::detail::StaticObject<TableOpaqueRep>::getInstance();
|
||||
for (auto &iter : opaque_names) {
|
||||
auto opaque = rep.getOpaqueByName(iter);
|
||||
if (!opaque) {
|
||||
dbgTrace(D_TABLE) << "Failed to load synced opaque " << iter;
|
||||
return;
|
||||
}
|
||||
|
||||
// 0 is used currently until supporting versions
|
||||
opaque->loadOpaque(ar, 0);
|
||||
|
||||
if (!createState(typeid(*opaque), move(opaque))) {
|
||||
dbgError(D_TABLE) << "Failed to create the state for opaque " << iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __ENTRY_IMPL_H__
|
117
core/include/general/table/expiration_impl.h
Normal file
117
core/include/general/table/expiration_impl.h
Normal file
@@ -0,0 +1,117 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (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.
|
||||
|
||||
#ifndef __EXPIRATION_IMPL_H__
|
||||
#define __EXPIRATION_IMPL_H__
|
||||
|
||||
#ifndef __TABLE_IMPL_H__
|
||||
#error "expiration_impl.h should not be included directly"
|
||||
#endif // __TABLE_IMPL_H__
|
||||
|
||||
template <typename Key>
|
||||
class Table<Key>::Impl::ExpirationEntry
|
||||
{
|
||||
public:
|
||||
ExpirationEntry(std::chrono::microseconds _expire, const Key &_key);
|
||||
bool isBeforeTime(std::chrono::microseconds other_expire) const;
|
||||
const Key & getKey() const;
|
||||
std::chrono::microseconds getExpiration() const;
|
||||
|
||||
private:
|
||||
std::chrono::microseconds expire;
|
||||
Key key;
|
||||
};
|
||||
|
||||
template <typename Key>
|
||||
Table<Key>::Impl::ExpirationEntry::ExpirationEntry(std::chrono::microseconds _expire, const Key &_key)
|
||||
:
|
||||
expire(_expire),
|
||||
key(_key)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
bool
|
||||
Table<Key>::Impl::ExpirationEntry::isBeforeTime(std::chrono::microseconds other_expire) const
|
||||
{
|
||||
return expire <= other_expire;
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
const Key &
|
||||
Table<Key>::Impl::ExpirationEntry::getKey() const
|
||||
{
|
||||
return key;
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
std::chrono::microseconds
|
||||
Table<Key>::Impl::ExpirationEntry::getExpiration() const
|
||||
{
|
||||
return expire;
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
class Table<Key>::Impl::ExpList
|
||||
:
|
||||
public TableHelper::I_InternalTableExpiration<Key, ExpIter>
|
||||
{
|
||||
public:
|
||||
ExpIter addExpiration(std::chrono::microseconds expire, const Key &key) override;
|
||||
void removeExpiration(const ExpIter &iter) override;
|
||||
bool shouldExpire(std::chrono::microseconds expire) const;
|
||||
const Key & getEarliest() const;
|
||||
|
||||
private:
|
||||
std::list<ExpirationEntry> list;
|
||||
};
|
||||
|
||||
template <typename Key>
|
||||
typename Table<Key>::Impl::ExpIter
|
||||
Table<Key>::Impl::ExpList::addExpiration(std::chrono::microseconds expire, const Key &key)
|
||||
{
|
||||
// The list is ordered from the highest value (in the far future) to the lowest (in the near future).
|
||||
// So we scan the list to enter before the first vlaue that is smaller than us (typically, the first one).
|
||||
for (auto iter = list.begin(); iter != list.end(); iter++) {
|
||||
if (iter->isBeforeTime(expire)) {
|
||||
return list.emplace(iter, expire, key);
|
||||
}
|
||||
}
|
||||
// There was no value that is closer to the current time, so it should be placed in at the end of the list.
|
||||
return list.emplace(list.end(), expire, key);
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void
|
||||
Table<Key>::Impl::ExpList::removeExpiration(const ExpIter &iter)
|
||||
{
|
||||
list.erase(iter);
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
bool
|
||||
Table<Key>::Impl::ExpList::shouldExpire(std::chrono::microseconds expire) const
|
||||
{
|
||||
if (list.empty()) return false;
|
||||
return list.back().isBeforeTime(expire);
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
const Key &
|
||||
Table<Key>::Impl::ExpList::getEarliest() const
|
||||
{
|
||||
dbgAssert(!list.empty()) << "Cannot access the earliest member of an empty list";
|
||||
return list.back().getKey();
|
||||
}
|
||||
|
||||
#endif // __EXPIRATION_IMPL_H__
|
55
core/include/general/table/table_helpers.h
Normal file
55
core/include/general/table/table_helpers.h
Normal file
@@ -0,0 +1,55 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (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.
|
||||
|
||||
#ifndef __TABLE_HELPERS_H__
|
||||
#define __TABLE_HELPERS_H__
|
||||
|
||||
#ifndef __TABLE_IMPL_H__
|
||||
#error "table_helpers.h should not be included directly"
|
||||
#endif // __TABLE_IMPL_H__
|
||||
|
||||
#include "context.h"
|
||||
|
||||
namespace TableHelper
|
||||
{
|
||||
|
||||
class Constant
|
||||
{
|
||||
protected:
|
||||
static const std::string primary_key;
|
||||
};
|
||||
|
||||
template <typename KeyPtr>
|
||||
class I_InternalTableList
|
||||
{
|
||||
public:
|
||||
virtual void removeKey(const KeyPtr &key) = 0;
|
||||
|
||||
protected:
|
||||
~I_InternalTableList() {}
|
||||
};
|
||||
|
||||
template <typename Key, typename ExpIter>
|
||||
class I_InternalTableExpiration
|
||||
{
|
||||
public:
|
||||
virtual ExpIter addExpiration(std::chrono::microseconds expire, const Key &key) = 0;
|
||||
virtual void removeExpiration(const ExpIter &iter) = 0;
|
||||
|
||||
protected:
|
||||
~I_InternalTableExpiration() {}
|
||||
};
|
||||
|
||||
} // TableHelper
|
||||
|
||||
#endif // __TABLE_HELPERS_H__
|
442
core/include/general/table/table_impl.h
Normal file
442
core/include/general/table/table_impl.h
Normal file
@@ -0,0 +1,442 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (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.
|
||||
|
||||
#ifndef __TABLE_IMPL_H__
|
||||
#define __TABLE_IMPL_H__
|
||||
|
||||
#ifndef __TABLE_H__
|
||||
#error "table_impl.h should not be included directly"
|
||||
#endif // __TABLE_H__
|
||||
|
||||
#include <sstream>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
#include "debug.h"
|
||||
#include "time_print.h"
|
||||
#include "singleton.h"
|
||||
#include "context.h"
|
||||
#include "table/table_helpers.h"
|
||||
#include "table/table_list.h"
|
||||
#include "table/opaque_repo.h"
|
||||
#include "config.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_TABLE);
|
||||
|
||||
template <typename Key>
|
||||
class Table<Key>::Impl
|
||||
:
|
||||
public TableHelper::Constant,
|
||||
public TableHelper::I_InternalTableList<TableHelper::KeyNodePtr<Key>>,
|
||||
public Singleton::Provide<I_Table>::From<Table<Key>>,
|
||||
public Singleton::Provide<I_TableSpecific<Key>>::template From<Table<Key>>
|
||||
{
|
||||
class ExpirationEntry;
|
||||
using ExpIter = typename std::list<ExpirationEntry>::iterator;
|
||||
class ExpList;
|
||||
|
||||
class Entry;
|
||||
using EntryRef = std::shared_ptr<Entry>;
|
||||
using EntryMap = std::unordered_map<Key, EntryRef>;
|
||||
|
||||
public:
|
||||
void init();
|
||||
void fini();
|
||||
|
||||
// I_InternalTableControl methods
|
||||
void removeKey(const TableHelper::KeyNodePtr<Key> &key) override;
|
||||
|
||||
// I_Table protected methods
|
||||
bool hasState (const std::type_index &index) const override;
|
||||
bool createState(const std::type_index &index, std::unique_ptr<TableOpaqueBase> &&ptr) override;
|
||||
bool deleteState(const std::type_index &index) override;
|
||||
TableOpaqueBase * getState (const std::type_index &index) override;
|
||||
|
||||
// I_Table public methods
|
||||
void setExpiration(std::chrono::milliseconds expire) override;
|
||||
bool doesKeyExists() const override;
|
||||
std::string keyToString () const override;
|
||||
TableIter begin () const override;
|
||||
TableIter end () const override;
|
||||
|
||||
// I_TableSpecific methods
|
||||
bool hasEntry (const Key &key) override;
|
||||
bool createEntry (const Key &key, std::chrono::microseconds expire) override;
|
||||
bool deleteEntry (const Key &key) override;
|
||||
bool addLinkToEntry(const Key &key, const Key &link) override;
|
||||
uint count () override;
|
||||
void expireEntries () override;
|
||||
bool setActiveKey (const Key &key) override;
|
||||
void unsetActiveKey() override;
|
||||
Maybe<Key, void> getCurrentKey () const override;
|
||||
void saveEntry (TableIter iter, SyncMode mode, cereal::BinaryOutputArchive &ar) const override;
|
||||
void loadEntry (cereal::BinaryInputArchive &ar) override;
|
||||
|
||||
private:
|
||||
EntryRef getCurrEntry() const;
|
||||
|
||||
// Members
|
||||
EntryMap entries;
|
||||
ExpList expiration;
|
||||
TableHelper::KeyList<Key> list;
|
||||
Context ctx;
|
||||
// Interfaces
|
||||
I_TimeGet *timer = nullptr;
|
||||
I_Environment *env = nullptr;
|
||||
};
|
||||
|
||||
#include "table/entry_impl.h"
|
||||
#include "table/expiration_impl.h"
|
||||
|
||||
template <typename Key>
|
||||
void
|
||||
Table<Key>::Impl::init()
|
||||
{
|
||||
env = Singleton::Consume<I_Environment>::by<Table<Key>>();
|
||||
timer = Singleton::Consume<I_TimeGet>::by<Table<Key>>();
|
||||
auto mainloop = Singleton::Consume<I_MainLoop>::by<Table<Key>>();
|
||||
mainloop->addRecurringRoutine(
|
||||
I_MainLoop::RoutineType::Timer,
|
||||
std::chrono::milliseconds(100),
|
||||
[&] () { expireEntries(); },
|
||||
"Delete expired table entries"
|
||||
);
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void
|
||||
Table<Key>::Impl::fini()
|
||||
{
|
||||
while (count() > 0) {
|
||||
deleteEntry(expiration.getEarliest());
|
||||
}
|
||||
|
||||
env = nullptr;
|
||||
timer = nullptr;
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void
|
||||
Table<Key>::Impl::removeKey(const TableHelper::KeyNodePtr<Key> &key)
|
||||
{
|
||||
if (!key) {
|
||||
dbgError(D_TABLE) << "Function called without a key";
|
||||
return;
|
||||
}
|
||||
auto iter = entries.find(key->getKey());
|
||||
if (iter == entries.end()) {
|
||||
dbgError(D_TABLE) << "Trying to remove a non-existing key " << key;
|
||||
return;
|
||||
}
|
||||
dbgTrace(D_TABLE) << "Removing the key " << key;
|
||||
entries.erase(iter);
|
||||
list.removeKey(key);
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
bool
|
||||
Table<Key>::Impl::hasState(const std::type_index &index) const
|
||||
{
|
||||
dbgTrace(D_TABLE) << "Checking if there is a state of type " << index.name();
|
||||
auto entry = getCurrEntry();
|
||||
if (!entry) return false;
|
||||
return entry->hasState(index);
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
bool
|
||||
Table<Key>::Impl::createState(const std::type_index &index, std::unique_ptr<TableOpaqueBase> &&ptr)
|
||||
{
|
||||
auto ent = getCurrEntry();
|
||||
if (ent == nullptr) {
|
||||
dbgError(D_TABLE) << "Trying to create a state without an entry";
|
||||
return false;
|
||||
}
|
||||
return ent->createState(index, std::move(ptr));
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
bool
|
||||
Table<Key>::Impl::deleteState(const std::type_index &index)
|
||||
{
|
||||
auto ent = getCurrEntry();
|
||||
if (ent) return ent->delState(index);
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
TableOpaqueBase *
|
||||
Table<Key>::Impl::getState(const std::type_index &index)
|
||||
{
|
||||
auto ent = getCurrEntry();
|
||||
dbgTrace(D_TABLE) << "Getting a state of type " << index.name();
|
||||
if (!ent) return nullptr;
|
||||
return ent->getState(index);
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void
|
||||
Table<Key>::Impl::setExpiration(std::chrono::milliseconds expire)
|
||||
{
|
||||
auto ent = getCurrEntry();
|
||||
if (!ent) return;
|
||||
auto curr_time = timer->getMonotonicTime();
|
||||
ent->setExpiration(curr_time + expire);
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
bool
|
||||
Table<Key>::Impl::doesKeyExists() const
|
||||
{
|
||||
auto key = env->get<Key>(primary_key);
|
||||
if (!key.ok()) return false;
|
||||
return entries.find(key.unpack()) != entries.end();
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
std::string
|
||||
Table<Key>::Impl::keyToString() const
|
||||
{
|
||||
auto key = env->get<Key>(primary_key);
|
||||
if (!key.ok()) return "";
|
||||
std::ostringstream os;
|
||||
os << key.unpack();
|
||||
return os.str();
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
TableIter
|
||||
Table<Key>::Impl::begin() const
|
||||
{
|
||||
return TableIter(list.begin());
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
TableIter
|
||||
Table<Key>::Impl::end() const
|
||||
{
|
||||
return TableIter(list.end());
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
bool
|
||||
Table<Key>::Impl::hasEntry(const Key &key)
|
||||
{
|
||||
return entries.find(key) != entries.end();
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
bool
|
||||
Table<Key>::Impl::createEntry(const Key &key, std::chrono::microseconds expire)
|
||||
{
|
||||
if (entries.find(key) != entries.end()) {
|
||||
dbgWarning(D_TABLE) << "Trying to recreate an entry with the key " << key;
|
||||
return false;
|
||||
}
|
||||
auto curr_time = timer->getMonotonicTime();
|
||||
auto expire_time = curr_time + expire;
|
||||
dbgTrace(D_TABLE) << "Creating an entry with the key " << key << " for " << expire;
|
||||
entries.emplace(key, std::make_shared<Entry>(this, &expiration, key, list.addKey(key), expire_time));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
bool
|
||||
Table<Key>::Impl::deleteEntry(const Key &key)
|
||||
{
|
||||
auto iter = entries.find(key);
|
||||
if (iter == entries.end()) {
|
||||
dbgWarning(D_TABLE) << "Trying to delete a non-existing entry of the key " << key;
|
||||
return false;
|
||||
}
|
||||
auto ent = iter->second; // Important, since we don't want the entry to disappear before we leave the function.
|
||||
dbgTrace(D_TABLE) << "Deleting an entry of the key " << key;
|
||||
ent->removeSelf();
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
bool
|
||||
Table<Key>::Impl::addLinkToEntry(const Key &key, const Key &link)
|
||||
{
|
||||
auto iter = entries.find(key);
|
||||
if (iter == entries.end()) {
|
||||
dbgWarning(D_TABLE) << "No entry, to which to add a key";
|
||||
return false;
|
||||
}
|
||||
bool success = entries.emplace(link, iter->second).second;
|
||||
if (!success) {
|
||||
dbgWarning(D_TABLE) << "Attempting to re-enter a key " <<link;
|
||||
return false;
|
||||
}
|
||||
dbgTrace(D_TABLE) << "Linking the key " << link << " with the key " << key;
|
||||
iter->second->addKey(link, list.addKey(link));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
uint
|
||||
Table<Key>::Impl::count()
|
||||
{
|
||||
return entries.size();
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void
|
||||
Table<Key>::Impl::expireEntries()
|
||||
{
|
||||
auto curr_time = timer->getMonotonicTime();
|
||||
while (expiration.shouldExpire(curr_time)) {
|
||||
auto key = expiration.getEarliest();
|
||||
ScopedContext ctx;
|
||||
ctx.registerValue(primary_key, key);
|
||||
deleteEntry(key);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
bool
|
||||
Table<Key>::Impl::setActiveKey(const Key &key)
|
||||
{
|
||||
auto entry = entries.find(key);
|
||||
if (entry == entries.end()) return false;
|
||||
ctx.registerValue(primary_key, key);
|
||||
ctx.activate();
|
||||
entry->second->uponEnteringContext();
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void
|
||||
Table<Key>::Impl::unsetActiveKey()
|
||||
{
|
||||
auto entry = getCurrEntry();
|
||||
if (entry == nullptr) {
|
||||
dbgError(D_TABLE) << "Unsetting the active key when there is no active entry";
|
||||
return;
|
||||
}
|
||||
entry->uponLeavingContext();
|
||||
ctx.deactivate();
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
Maybe<Key, void>
|
||||
Table<Key>::Impl::getCurrentKey() const
|
||||
{
|
||||
return env->get<Key>(primary_key);
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
typename Table<Key>::Impl::EntryRef
|
||||
Table<Key>::Impl::getCurrEntry() const
|
||||
{
|
||||
auto key = env->get<Key>(primary_key);
|
||||
if (!key.ok()) {
|
||||
dbgTrace(D_TABLE) << "Key was not found";
|
||||
return nullptr;
|
||||
}
|
||||
auto iter = entries.find(key.unpack());
|
||||
if (iter == entries.end()) {
|
||||
dbgTrace(D_TABLE) << "No entry matches the key " << key.unpack();
|
||||
return nullptr;
|
||||
}
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void
|
||||
Table<Key>::Impl::saveEntry(TableIter iter, SyncMode mode, cereal::BinaryOutputArchive &ar) const
|
||||
{
|
||||
iter.setEntry();
|
||||
auto ent = getCurrEntry();
|
||||
ar(
|
||||
cereal::make_nvp("keys_vec", ent->getKeys()),
|
||||
cereal::make_nvp("expire", ent->getExpiration())
|
||||
);
|
||||
|
||||
ent->save(ar);
|
||||
|
||||
if (mode == SyncMode::TRANSFER_ENTRY) {
|
||||
std::string key = keyToString();
|
||||
ent->removeSelf();
|
||||
dbgTrace(D_TABLE) << "Key '" << key <<"' was removed";
|
||||
}
|
||||
iter.unsetEntry();
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void
|
||||
Table<Key>::Impl::loadEntry(cereal::BinaryInputArchive &ar)
|
||||
{
|
||||
std::vector<Key> keys_vec;
|
||||
std::chrono::microseconds expire;
|
||||
|
||||
ar(
|
||||
cereal::make_nvp("keys_vec", keys_vec),
|
||||
cereal::make_nvp("expire", expire)
|
||||
);
|
||||
|
||||
if (keys_vec.size() == 0) {
|
||||
dbgError(D_TABLE) << "No Keys to load";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!createEntry(keys_vec[0], expire)) {
|
||||
dbgError(D_TABLE) << "Cannot create a new entry";
|
||||
return;
|
||||
}
|
||||
|
||||
for (decltype(keys_vec.size()) index=1; index<keys_vec.size(); index++) {
|
||||
if (!addLinkToEntry(keys_vec[0], keys_vec[index])) {
|
||||
dbgError(D_TABLE) << "Cannot add link to an entry";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto entry_iter = entries.find(keys_vec[0]);
|
||||
if (entry_iter == entries.end()) return;
|
||||
auto ent = entry_iter->second;
|
||||
ent->load(ar);
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
Table<Key>::Table() : Component("Table"), pimpl(std::make_unique<Table::Impl>())
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
Table<Key>::~Table()
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void
|
||||
Table<Key>::init()
|
||||
{
|
||||
pimpl->init();
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void
|
||||
Table<Key>::fini()
|
||||
{
|
||||
pimpl->fini();
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void
|
||||
Table<Key>::preload()
|
||||
{
|
||||
}
|
||||
|
||||
#endif // __TABLE_IMPL_H__
|
96
core/include/general/table/table_list.h
Normal file
96
core/include/general/table/table_list.h
Normal file
@@ -0,0 +1,96 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (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.
|
||||
|
||||
#ifndef __TABLE_LIST_H__
|
||||
#define __TABLE_LIST_H__
|
||||
|
||||
#ifndef __TABLE_IMPL_H__
|
||||
#error "table_list.h should not be included directly"
|
||||
#endif // __TABLE_IMPL_H__
|
||||
|
||||
#include "table/table_list_node.h"
|
||||
#include "table/table_list_iter.h"
|
||||
#include "debug.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_TABLE);
|
||||
|
||||
namespace TableHelper
|
||||
{
|
||||
|
||||
template <typename Key>
|
||||
class KeyList
|
||||
{
|
||||
public:
|
||||
KeyNodePtr<Key> addKey(const Key &key);
|
||||
void removeKey(const KeyNodePtr<Key> &val);
|
||||
std::shared_ptr<I_TableIter> begin() const;
|
||||
std::shared_ptr<I_TableIter> end() const;
|
||||
|
||||
private:
|
||||
KeyNodePtr<Key> first;
|
||||
KeyNodePtr<Key> last;
|
||||
};
|
||||
|
||||
template <typename Key>
|
||||
KeyNodePtr<Key>
|
||||
KeyList<Key>::addKey(const Key &key)
|
||||
{
|
||||
KeyNodePtr<Key> new_entry = std::make_shared<KeyNode<Key>>(key);
|
||||
if (!first) {
|
||||
first = new_entry;
|
||||
} else {
|
||||
last->setNext(new_entry);
|
||||
}
|
||||
last = new_entry;
|
||||
return new_entry;
|
||||
};
|
||||
|
||||
template <typename Key>
|
||||
void
|
||||
KeyList<Key>::removeKey(const KeyNodePtr<Key> &val)
|
||||
{
|
||||
val->deactivate();
|
||||
|
||||
if (val == first) {
|
||||
first = first->getNext();
|
||||
if (last == val) last = first; // `val` was the only member of the list
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto iter = first; iter != last; iter = iter->getNext()) {
|
||||
if (iter->getNext() == val) {
|
||||
if (iter->getNext() == last) last = iter;
|
||||
iter->setNext(iter->getNext()->getNext());
|
||||
return;
|
||||
}
|
||||
}
|
||||
dbgError(D_TABLE) << "Iterator was not found in the table key list";
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
std::shared_ptr<I_TableIter>
|
||||
KeyList<Key>::begin() const
|
||||
{
|
||||
return std::make_shared<KeyNodeIter<Key>>(first);
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
std::shared_ptr<I_TableIter>
|
||||
KeyList<Key>::end() const
|
||||
{
|
||||
return std::make_shared<KeyNodeIter<Key>>(nullptr);
|
||||
}
|
||||
|
||||
} // TableHelper
|
||||
|
||||
#endif // __TABLE_LIST_H__
|
98
core/include/general/table/table_list_iter.h
Normal file
98
core/include/general/table/table_list_iter.h
Normal file
@@ -0,0 +1,98 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (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.
|
||||
|
||||
#ifndef __TABLE_LIST_ITER_H__
|
||||
#define __TABLE_LIST_ITER_H__
|
||||
|
||||
#ifndef __TABLE_IMPL_H__
|
||||
#error "table_list_iter.h should not be included directly"
|
||||
#endif // __TABLE_IMPL_H__
|
||||
|
||||
#include "context.h"
|
||||
|
||||
namespace TableHelper
|
||||
{
|
||||
|
||||
template <typename Key>
|
||||
class KeyNodeIter : public I_TableIter, public Constant
|
||||
{
|
||||
public:
|
||||
KeyNodeIter(const KeyNodePtr<Key> &iter);
|
||||
void operator++() override;
|
||||
void operator++(int) override;
|
||||
void setEntry() override;
|
||||
void unsetEntry() override;
|
||||
void * getUniqueId() const override;
|
||||
|
||||
private:
|
||||
void moveNext();
|
||||
|
||||
KeyNodePtr<Key> curr;
|
||||
Context ctx;
|
||||
};
|
||||
|
||||
template <typename Key>
|
||||
KeyNodeIter<Key>::KeyNodeIter(const KeyNodePtr<Key> &iter) : curr(iter)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void
|
||||
KeyNodeIter<Key>::operator++()
|
||||
{
|
||||
moveNext();
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void
|
||||
KeyNodeIter<Key>::operator++(int)
|
||||
{
|
||||
moveNext();
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void
|
||||
KeyNodeIter<Key>::setEntry()
|
||||
{
|
||||
if (!curr || !curr->isActive()) return;
|
||||
ctx.registerValue(primary_key, curr->getKey());
|
||||
ctx.activate();
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void
|
||||
KeyNodeIter<Key>::unsetEntry()
|
||||
{
|
||||
ctx.deactivate();
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void *
|
||||
KeyNodeIter<Key>::getUniqueId() const
|
||||
{
|
||||
return curr.get();
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void
|
||||
KeyNodeIter<Key>::moveNext()
|
||||
{
|
||||
while (curr != nullptr) {
|
||||
curr = curr->getNext();
|
||||
if (curr != nullptr && curr->isActive()) return;
|
||||
}
|
||||
}
|
||||
|
||||
} // TableHelper
|
||||
|
||||
#endif // __TABLE_LIST_ITER_H__
|
87
core/include/general/table/table_list_node.h
Normal file
87
core/include/general/table/table_list_node.h
Normal file
@@ -0,0 +1,87 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (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.
|
||||
|
||||
#ifndef __TABLE_LIST_NODE_H__
|
||||
#define __TABLE_LIST_NODE_H__
|
||||
|
||||
#ifndef __TABLE_IMPL_H__
|
||||
#error "table_list_node.h should not be included directly"
|
||||
#endif // __TABLE_IMPL_H__
|
||||
|
||||
namespace TableHelper
|
||||
{
|
||||
|
||||
template <typename Key>
|
||||
class KeyNode
|
||||
{
|
||||
public:
|
||||
KeyNode(const Key &_key);
|
||||
void setNext(const std::shared_ptr<KeyNode> &_next);
|
||||
const Key & getKey() const;
|
||||
const std::shared_ptr<KeyNode> & getNext() const;
|
||||
bool isActive() const;
|
||||
void deactivate();
|
||||
|
||||
private:
|
||||
Key key;
|
||||
std::shared_ptr<KeyNode> next;
|
||||
bool is_active = true;
|
||||
};
|
||||
|
||||
template <typename Key>
|
||||
KeyNode<Key>::KeyNode(const Key &_key)
|
||||
:
|
||||
key(_key)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void
|
||||
KeyNode<Key>::setNext(const std::shared_ptr<KeyNode> &_next)
|
||||
{
|
||||
next = _next;
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
const Key &
|
||||
KeyNode<Key>::getKey() const
|
||||
{
|
||||
return key;
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
const std::shared_ptr<KeyNode<Key>> &
|
||||
KeyNode<Key>::getNext() const
|
||||
{
|
||||
return next;
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
bool
|
||||
KeyNode<Key>::isActive() const
|
||||
{
|
||||
return is_active;
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void
|
||||
KeyNode<Key>::deactivate()
|
||||
{
|
||||
is_active = false;
|
||||
}
|
||||
|
||||
template <typename Key> using KeyNodePtr = std::shared_ptr<KeyNode<Key>>;
|
||||
|
||||
} // TableHelper
|
||||
|
||||
#endif // __TABLE_LIST_NODE_H__
|
Reference in New Issue
Block a user