Ensure table/set HashKey buffer reservation and writes happen in same order

This takes the existing sorting for table index hashkeys we had in place during
hash key writes and applies it also during buffer size reservation. It changes
the approach slightly: the underlying map now points to the TableVal entry index
vals directly, rather than to the numerical index into an additional list that
gets built up to store those indexes. Doing so removes the need for that list.
This commit is contained in:
Christian Kreibich 2021-09-16 17:14:16 -07:00
parent 1260f6b585
commit 5fc8d89897

View file

@ -18,6 +18,42 @@
namespace zeek::detail namespace zeek::detail
{ {
// A comparison callable to assist with consistent iteration order over tables
// during reservation & writes.
struct HashKeyComparer
{
bool operator()(const std::unique_ptr<HashKey>& a, const std::unique_ptr<HashKey>& b) const
{
if ( a->Hash() != b->Hash() )
return a->Hash() < b->Hash();
if ( a->Size() != b->Size() )
return a->Size() < b->Size();
return memcmp(a->Key(), b->Key(), a->Size()) < 0;
}
};
using HashkeyMap = std::map<std::unique_ptr<HashKey>, ListValPtr, HashKeyComparer>;
using HashkeyMapPtr = std::unique_ptr<HashkeyMap>;
// Helper that produces a table from HashKeys to the ListVal indexes into the
// table, that we can iterate over in sorted-Hashkey order.
const HashkeyMapPtr ordered_hashkeys(const TableVal* tv)
{
auto res = std::make_unique<HashkeyMap>();
auto tbl = tv->AsTable();
auto idx = 0;
for ( const auto& entry : *tbl )
{
auto k = entry.GetHashKey();
// Do we have to recreate here? Could we reuse the existing key?
auto lv = tv->RecreateIndex(*k);
res->insert_or_assign(std::move(k), lv);
}
return res;
}
CompositeHash::CompositeHash(TypeListPtr composite_type) : type(std::move(composite_type)) CompositeHash::CompositeHash(TypeListPtr composite_type) : type(std::move(composite_type))
{ {
singleton_tag = TYPE_INTERNAL_ERROR; singleton_tag = TYPE_INTERNAL_ERROR;
@ -209,38 +245,11 @@ char* CompositeHash::SingleValHash(bool type_check, char* kp0, Type* bt, Val* v,
*kp = tv->Size(); *kp = tv->Size();
kp1 = reinterpret_cast<char*>(kp + 1); kp1 = reinterpret_cast<char*>(kp + 1);
auto tbl = tv->AsTable(); auto hashkeys = ordered_hashkeys(tv);
auto lv = make_intrusive<ListVal>(TYPE_ANY);
struct HashKeyComparer for ( auto& kv : *hashkeys )
{ {
bool operator()(const std::unique_ptr<HashKey>& a, auto key = kv.second;
const std::unique_ptr<HashKey>& b) const
{
if ( a->Hash() != b->Hash() )
return a->Hash() < b->Hash();
if ( a->Size() != b->Size() )
return a->Size() < b->Size();
return strncmp(static_cast<const char*>(a->Key()),
static_cast<const char*>(b->Key()),
a->Size()) < 0;
}
};
std::map<std::unique_ptr<HashKey>, int, HashKeyComparer> hashkeys;
auto idx = 0;
for ( const auto& entry : *tbl )
{
auto k = entry.GetHashKey();
lv->Append(tv->RecreateIndex(*k));
hashkeys[std::move(k)] = idx++;
}
for ( auto& kv : hashkeys )
{
auto idx = kv.second;
const auto& key = lv->Idx(idx);
if ( ! (kp1 = SingleValHash(type_check, kp1, key->GetType().get(), if ( ! (kp1 = SingleValHash(type_check, kp1, key->GetType().get(),
key.get(), false)) ) key.get(), false)) )
@ -541,11 +550,12 @@ int CompositeHash::SingleTypeKeySize(Type* bt, const Val* v, bool type_check, in
return (optional && ! calc_static_size) ? sz : 0; return (optional && ! calc_static_size) ? sz : 0;
sz = SizeAlign(sz, sizeof(int)); sz = SizeAlign(sz, sizeof(int));
TableVal* tv = const_cast<TableVal*>(v->AsTableVal()); auto tv = v->AsTableVal();
auto lv = tv->ToListVal(); auto hashkeys = ordered_hashkeys(tv);
for ( int i = 0; i < tv->Size(); ++i )
for ( auto& kv : *hashkeys )
{ {
const auto& key = lv->Idx(i); auto key = kv.second;
sz = SingleTypeKeySize(key->GetType().get(), key.get(), type_check, sz = SingleTypeKeySize(key->GetType().get(), key.get(), type_check,
sz, false, calc_static_size); sz, false, calc_static_size);
if ( ! sz ) if ( ! sz )
@ -553,7 +563,7 @@ int CompositeHash::SingleTypeKeySize(Type* bt, const Val* v, bool type_check, in
if ( ! bt->IsSet() ) if ( ! bt->IsSet() )
{ {
auto val = tv->FindOrDefault(key); auto val = const_cast<TableVal*>(tv)->FindOrDefault(key);
sz = SingleTypeKeySize(val->GetType().get(), val.get(), sz = SingleTypeKeySize(val->GetType().get(), val.get(),
type_check, sz, false, calc_static_size); type_check, sz, false, calc_static_size);
if ( ! sz ) if ( ! sz )