mirror of
https://github.com/zeek/zeek.git
synced 2025-10-06 16:48:19 +00:00
Remove StateAccess class.
This commit is contained in:
parent
02214dafc4
commit
31ddca863c
8 changed files with 14 additions and 744 deletions
|
@ -12,7 +12,7 @@ DebugLogger debug_logger;
|
||||||
// Same order here as in DebugStream.
|
// Same order here as in DebugStream.
|
||||||
DebugLogger::Stream DebugLogger::streams[NUM_DBGS] = {
|
DebugLogger::Stream DebugLogger::streams[NUM_DBGS] = {
|
||||||
{ "serial", 0, false }, { "rules", 0, false },
|
{ "serial", 0, false }, { "rules", 0, false },
|
||||||
{ "state", 0, false }, {"string", 0, false },
|
{ "string", 0, false },
|
||||||
{ "notifiers", 0, false }, { "main-loop", 0, false },
|
{ "notifiers", 0, false }, { "main-loop", 0, false },
|
||||||
{ "dpd", 0, false }, { "tm", 0, false },
|
{ "dpd", 0, false }, { "tm", 0, false },
|
||||||
{ "logging", 0, false }, {"input", 0, false },
|
{ "logging", 0, false }, {"input", 0, false },
|
||||||
|
|
|
@ -16,9 +16,8 @@
|
||||||
enum DebugStream {
|
enum DebugStream {
|
||||||
DBG_SERIAL, // Serialization
|
DBG_SERIAL, // Serialization
|
||||||
DBG_RULES, // Signature matching
|
DBG_RULES, // Signature matching
|
||||||
DBG_STATE, // StateAccess logging
|
|
||||||
DBG_STRING, // String code
|
DBG_STRING, // String code
|
||||||
DBG_NOTIFIERS, // Notifiers (see StateAccess.h)
|
DBG_NOTIFIERS, // Notifiers
|
||||||
DBG_MAINLOOP, // Main IOSource loop
|
DBG_MAINLOOP, // Main IOSource loop
|
||||||
DBG_ANALYZER, // Analyzer framework
|
DBG_ANALYZER, // Analyzer framework
|
||||||
DBG_TM, // Time-machine packet input via Brocolli
|
DBG_TM, // Time-machine packet input via Brocolli
|
||||||
|
|
|
@ -79,7 +79,7 @@ void ID::SetVal(Val* v, Opcode op, bool arg_weak_ref)
|
||||||
#else
|
#else
|
||||||
if ( debug_logger.IsVerbose() || props )
|
if ( debug_logger.IsVerbose() || props )
|
||||||
#endif
|
#endif
|
||||||
StateAccess::Log(new StateAccess(op, this, v, val));
|
notifiers.Modified(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! weak_ref )
|
if ( ! weak_ref )
|
||||||
|
|
|
@ -4,538 +4,6 @@
|
||||||
#include "NetVar.h"
|
#include "NetVar.h"
|
||||||
#include "DebugLogger.h"
|
#include "DebugLogger.h"
|
||||||
|
|
||||||
int StateAccess::replaying = 0;
|
|
||||||
|
|
||||||
StateAccess::StateAccess(Opcode arg_opcode,
|
|
||||||
const MutableVal* arg_target, const Val* arg_op1,
|
|
||||||
const Val* arg_op2, const Val* arg_op3)
|
|
||||||
{
|
|
||||||
opcode = arg_opcode;
|
|
||||||
target.val = const_cast<MutableVal*>(arg_target);
|
|
||||||
target_type = TYPE_MVAL;
|
|
||||||
op1.val = const_cast<Val*>(arg_op1);
|
|
||||||
op1_type = TYPE_VAL;
|
|
||||||
op2 = const_cast<Val*>(arg_op2);
|
|
||||||
op3 = const_cast<Val*>(arg_op3);
|
|
||||||
delete_op1_key = false;
|
|
||||||
|
|
||||||
RefThem();
|
|
||||||
}
|
|
||||||
|
|
||||||
StateAccess::StateAccess(Opcode arg_opcode,
|
|
||||||
const ID* arg_target, const Val* arg_op1,
|
|
||||||
const Val* arg_op2, const Val* arg_op3)
|
|
||||||
{
|
|
||||||
opcode = arg_opcode;
|
|
||||||
target.id = const_cast<ID*>(arg_target);
|
|
||||||
target_type = TYPE_ID;
|
|
||||||
op1.val = const_cast<Val*>(arg_op1);
|
|
||||||
op1_type = TYPE_VAL;
|
|
||||||
op2 = const_cast<Val*>(arg_op2);
|
|
||||||
op3 = const_cast<Val*>(arg_op3);
|
|
||||||
delete_op1_key = false;
|
|
||||||
|
|
||||||
RefThem();
|
|
||||||
}
|
|
||||||
|
|
||||||
StateAccess::StateAccess(Opcode arg_opcode,
|
|
||||||
const ID* arg_target, const HashKey* arg_op1,
|
|
||||||
const Val* arg_op2, const Val* arg_op3)
|
|
||||||
{
|
|
||||||
opcode = arg_opcode;
|
|
||||||
target.id = const_cast<ID*>(arg_target);
|
|
||||||
target_type = TYPE_ID;
|
|
||||||
op1.key = new HashKey(arg_op1->Key(), arg_op1->Size(), arg_op1->Hash());
|
|
||||||
op1_type = TYPE_KEY;
|
|
||||||
op2 = const_cast<Val*>(arg_op2);
|
|
||||||
op3 = const_cast<Val*>(arg_op3);
|
|
||||||
delete_op1_key = true;
|
|
||||||
|
|
||||||
RefThem();
|
|
||||||
}
|
|
||||||
|
|
||||||
StateAccess::StateAccess(Opcode arg_opcode,
|
|
||||||
const MutableVal* arg_target, const HashKey* arg_op1,
|
|
||||||
const Val* arg_op2, const Val* arg_op3)
|
|
||||||
{
|
|
||||||
opcode = arg_opcode;
|
|
||||||
target.val = const_cast<MutableVal*>(arg_target);
|
|
||||||
target_type = TYPE_MVAL;
|
|
||||||
op1.key = new HashKey(arg_op1->Key(), arg_op1->Size(), arg_op1->Hash());
|
|
||||||
op1_type = TYPE_KEY;
|
|
||||||
op2 = const_cast<Val*>(arg_op2);
|
|
||||||
op3 = const_cast<Val*>(arg_op3);
|
|
||||||
delete_op1_key = true;
|
|
||||||
|
|
||||||
RefThem();
|
|
||||||
}
|
|
||||||
|
|
||||||
StateAccess::StateAccess(const StateAccess& sa)
|
|
||||||
{
|
|
||||||
opcode = sa.opcode;
|
|
||||||
target_type = sa.target_type;
|
|
||||||
op1_type = sa.op1_type;
|
|
||||||
delete_op1_key = false;
|
|
||||||
|
|
||||||
if ( target_type == TYPE_ID )
|
|
||||||
target.id = sa.target.id;
|
|
||||||
else
|
|
||||||
target.val = sa.target.val;
|
|
||||||
|
|
||||||
if ( op1_type == TYPE_VAL )
|
|
||||||
op1.val = sa.op1.val;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// We need to copy the key as the pointer may not be
|
|
||||||
// valid anymore later.
|
|
||||||
op1.key = new HashKey(sa.op1.key->Key(), sa.op1.key->Size(),
|
|
||||||
sa.op1.key->Hash());
|
|
||||||
delete_op1_key = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
op2 = sa.op2;
|
|
||||||
op3 = sa.op3;
|
|
||||||
|
|
||||||
RefThem();
|
|
||||||
}
|
|
||||||
|
|
||||||
StateAccess::~StateAccess()
|
|
||||||
{
|
|
||||||
if ( target_type == TYPE_ID )
|
|
||||||
Unref(target.id);
|
|
||||||
else
|
|
||||||
Unref(target.val);
|
|
||||||
|
|
||||||
if ( op1_type == TYPE_VAL )
|
|
||||||
Unref(op1.val);
|
|
||||||
else if ( delete_op1_key )
|
|
||||||
delete op1.key;
|
|
||||||
|
|
||||||
Unref(op2);
|
|
||||||
Unref(op3);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StateAccess::RefThem()
|
|
||||||
{
|
|
||||||
if ( target_type == TYPE_ID )
|
|
||||||
Ref(target.id);
|
|
||||||
else
|
|
||||||
Ref(target.val);
|
|
||||||
|
|
||||||
if ( op1_type == TYPE_VAL && op1.val )
|
|
||||||
Ref(op1.val);
|
|
||||||
|
|
||||||
if ( op2 )
|
|
||||||
Ref(op2);
|
|
||||||
if ( op3 )
|
|
||||||
Ref(op3);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Val* GetInteger(bro_int_t n, TypeTag t)
|
|
||||||
{
|
|
||||||
if ( t == TYPE_INT )
|
|
||||||
return val_mgr->GetInt(n);
|
|
||||||
|
|
||||||
return val_mgr->GetCount(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StateAccess::Replay()
|
|
||||||
{
|
|
||||||
// For simplicity we assume that we only replay unserialized accesses.
|
|
||||||
assert(target_type == TYPE_ID && op1_type == TYPE_VAL);
|
|
||||||
|
|
||||||
if ( ! target.id )
|
|
||||||
return;
|
|
||||||
|
|
||||||
Val* v = target.id->ID_Val();
|
|
||||||
TypeTag t = v ? v->Type()->Tag() : TYPE_VOID;
|
|
||||||
|
|
||||||
if ( opcode != OP_ASSIGN && ! v )
|
|
||||||
{
|
|
||||||
// FIXME: I think this warrants an internal error,
|
|
||||||
// but let's check that first ...
|
|
||||||
// reporter->InternalError("replay id lacking a value");
|
|
||||||
reporter->Error("replay id lacks a value");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++replaying;
|
|
||||||
|
|
||||||
switch ( opcode ) {
|
|
||||||
case OP_ASSIGN:
|
|
||||||
assert(op1.val);
|
|
||||||
// There mustn't be a direct assignment to a unique ID.
|
|
||||||
assert(target.id->Name()[0] != '#');
|
|
||||||
|
|
||||||
target.id->SetVal(op1.val->Ref());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OP_INCR:
|
|
||||||
if ( IsIntegral(t) )
|
|
||||||
{
|
|
||||||
assert(op1.val && op2);
|
|
||||||
// We derive the amount as difference between old
|
|
||||||
// and new value.
|
|
||||||
bro_int_t amount =
|
|
||||||
op1.val->CoerceToInt() - op2->CoerceToInt();
|
|
||||||
|
|
||||||
target.id->SetVal(GetInteger(v->CoerceToInt() + amount, t),
|
|
||||||
OP_INCR);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OP_ASSIGN_IDX:
|
|
||||||
assert(op1.val);
|
|
||||||
|
|
||||||
if ( t == TYPE_TABLE )
|
|
||||||
{
|
|
||||||
assert(op2);
|
|
||||||
v->AsTableVal()->Assign(op1.val, op2 ? op2->Ref() : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if ( t == TYPE_RECORD )
|
|
||||||
{
|
|
||||||
const char* field = op1.val->AsString()->CheckString();
|
|
||||||
int idx = v->Type()->AsRecordType()->FieldOffset(field);
|
|
||||||
|
|
||||||
if ( idx >= 0 )
|
|
||||||
v->AsRecordVal()->Assign(idx, op2 ? op2->Ref() : 0);
|
|
||||||
else
|
|
||||||
reporter->Error("access replay: unknown record field %s for assign", field);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if ( t == TYPE_VECTOR )
|
|
||||||
{
|
|
||||||
assert(op2);
|
|
||||||
bro_uint_t index = op1.val->AsCount();
|
|
||||||
v->AsVectorVal()->Assign(index, op2 ? op2->Ref() : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
reporter->InternalError("unknown type in replaying index assign");
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OP_INCR_IDX:
|
|
||||||
{
|
|
||||||
assert(op1.val && op2 && op3);
|
|
||||||
|
|
||||||
// We derive the amount as the difference between old
|
|
||||||
// and new value.
|
|
||||||
bro_int_t amount = op2->CoerceToInt() - op3->CoerceToInt();
|
|
||||||
|
|
||||||
if ( t == TYPE_TABLE )
|
|
||||||
{
|
|
||||||
t = v->Type()->AsTableType()->YieldType()->Tag();
|
|
||||||
Val* lookup_op1 = v->AsTableVal()->Lookup(op1.val);
|
|
||||||
int delta = lookup_op1->CoerceToInt() + amount;
|
|
||||||
Val* new_val = GetInteger(delta, t);
|
|
||||||
v->AsTableVal()->Assign(op1.val, new_val, OP_INCR );
|
|
||||||
}
|
|
||||||
|
|
||||||
else if ( t == TYPE_RECORD )
|
|
||||||
{
|
|
||||||
const char* field = op1.val->AsString()->CheckString();
|
|
||||||
int idx = v->Type()->AsRecordType()->FieldOffset(field);
|
|
||||||
if ( idx >= 0 )
|
|
||||||
{
|
|
||||||
t = v->Type()->AsRecordType()->FieldType(idx)->Tag();
|
|
||||||
Val* lookup_field =
|
|
||||||
v->AsRecordVal()->Lookup(idx);
|
|
||||||
bro_int_t delta =
|
|
||||||
lookup_field->CoerceToInt() + amount;
|
|
||||||
Val* new_val = GetInteger(delta, t);
|
|
||||||
v->AsRecordVal()->Assign(idx, new_val, OP_INCR);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
reporter->Error("access replay: unknown record field %s for assign", field);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if ( t == TYPE_VECTOR )
|
|
||||||
{
|
|
||||||
bro_uint_t index = op1.val->AsCount();
|
|
||||||
t = v->Type()->AsVectorType()->YieldType()->Tag();
|
|
||||||
Val* lookup_op1 = v->AsVectorVal()->Lookup(index);
|
|
||||||
int delta = lookup_op1->CoerceToInt() + amount;
|
|
||||||
Val* new_val = GetInteger(delta, t);
|
|
||||||
v->AsVectorVal()->Assign(index, new_val);
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
reporter->InternalError("unknown type in replaying index increment");
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case OP_ADD:
|
|
||||||
assert(op1.val);
|
|
||||||
if ( t == TYPE_TABLE )
|
|
||||||
{
|
|
||||||
v->AsTableVal()->Assign(op1.val, 0);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OP_DEL:
|
|
||||||
assert(op1.val);
|
|
||||||
if ( t == TYPE_TABLE )
|
|
||||||
{
|
|
||||||
Unref(v->AsTableVal()->Delete(op1.val));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OP_EXPIRE:
|
|
||||||
assert(op1.val);
|
|
||||||
if ( t == TYPE_TABLE )
|
|
||||||
{
|
|
||||||
// No old check for expire. It may have already
|
|
||||||
// been deleted by ourselves. Furthermore, we
|
|
||||||
// ignore the expire_func's return value.
|
|
||||||
TableVal* tv = v->AsTableVal();
|
|
||||||
if ( tv->Lookup(op1.val, false) )
|
|
||||||
{
|
|
||||||
// We want to propagate state updates which
|
|
||||||
// are performed in the expire_func.
|
|
||||||
StateAccess::ResumeReplay();
|
|
||||||
|
|
||||||
tv->CallExpireFunc(op1.val->Ref());
|
|
||||||
|
|
||||||
StateAccess::SuspendReplay();
|
|
||||||
|
|
||||||
Unref(tv->AsTableVal()->Delete(op1.val));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OP_PRINT:
|
|
||||||
assert(op1.val);
|
|
||||||
reporter->InternalError("access replay for print not implemented");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OP_READ_IDX:
|
|
||||||
if ( t == TYPE_TABLE )
|
|
||||||
{
|
|
||||||
assert(op1.val);
|
|
||||||
TableVal* tv = v->AsTableVal();
|
|
||||||
|
|
||||||
// Update the timestamp if we have a read_expire.
|
|
||||||
if ( tv->FindAttr(ATTR_EXPIRE_READ) )
|
|
||||||
{
|
|
||||||
tv->UpdateTimestamp(op1.val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
reporter->Error("read for non-table");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
reporter->InternalError("access replay: unknown opcode for StateAccess");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
--replaying;
|
|
||||||
}
|
|
||||||
|
|
||||||
ID* StateAccess::Target() const
|
|
||||||
{
|
|
||||||
return target_type == TYPE_ID ? target.id : target.val->UniqueID();
|
|
||||||
}
|
|
||||||
|
|
||||||
void StateAccess::Describe(ODesc* d) const
|
|
||||||
{
|
|
||||||
const ID* id;
|
|
||||||
const char* id_str = "";
|
|
||||||
const char* unique_str = "";
|
|
||||||
|
|
||||||
d->SetShort();
|
|
||||||
|
|
||||||
if ( target_type == TYPE_ID )
|
|
||||||
{
|
|
||||||
id = target.id;
|
|
||||||
|
|
||||||
if ( ! id )
|
|
||||||
{
|
|
||||||
d->Add("(unknown id)");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
id_str = id->Name();
|
|
||||||
|
|
||||||
if ( id->ID_Val() && id->ID_Val()->IsMutableVal() &&
|
|
||||||
id->Name()[0] != '#' )
|
|
||||||
unique_str = fmt(" [id] (%s)", id->ID_Val()->AsMutableVal()->UniqueID()->Name());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
id = target.val->UniqueID();
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
if ( target.val->GetID() )
|
|
||||||
{
|
|
||||||
id_str = target.val->GetID()->Name();
|
|
||||||
unique_str = fmt(" [val] (%s)", id->Name());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
id_str = id->Name();
|
|
||||||
}
|
|
||||||
|
|
||||||
const Val* op1 = op1_type == TYPE_VAL ?
|
|
||||||
this->op1.val :
|
|
||||||
id->ID_Val()->AsTableVal()->RecoverIndex(this->op1.key);
|
|
||||||
|
|
||||||
switch ( opcode ) {
|
|
||||||
case OP_ASSIGN:
|
|
||||||
assert(op1);
|
|
||||||
d->Add(id_str);
|
|
||||||
d->Add(" = ");
|
|
||||||
op1->Describe(d);
|
|
||||||
if ( op2 )
|
|
||||||
{
|
|
||||||
d->Add(" (");
|
|
||||||
op2->Describe(d);
|
|
||||||
d->Add(")");
|
|
||||||
}
|
|
||||||
d->Add(unique_str);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OP_INCR:
|
|
||||||
assert(op1 && op2);
|
|
||||||
d->Add(id_str);
|
|
||||||
d->Add(" += ");
|
|
||||||
d->Add(op1->CoerceToInt() - op2->CoerceToInt());
|
|
||||||
d->Add(unique_str);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OP_ASSIGN_IDX:
|
|
||||||
assert(op1);
|
|
||||||
d->Add(id_str);
|
|
||||||
d->Add("[");
|
|
||||||
op1->Describe(d);
|
|
||||||
d->Add("]");
|
|
||||||
d->Add(" = ");
|
|
||||||
if ( op2 )
|
|
||||||
op2->Describe(d);
|
|
||||||
else
|
|
||||||
d->Add("(null)");
|
|
||||||
if ( op3 )
|
|
||||||
{
|
|
||||||
d->Add(" (");
|
|
||||||
op3->Describe(d);
|
|
||||||
d->Add(")");
|
|
||||||
}
|
|
||||||
d->Add(unique_str);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OP_INCR_IDX:
|
|
||||||
assert(op1 && op2 && op3);
|
|
||||||
d->Add(id_str);
|
|
||||||
d->Add("[");
|
|
||||||
op1->Describe(d);
|
|
||||||
d->Add("]");
|
|
||||||
d->Add(" += ");
|
|
||||||
d->Add(op2->CoerceToInt() - op3->CoerceToInt());
|
|
||||||
d->Add(unique_str);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OP_ADD:
|
|
||||||
assert(op1);
|
|
||||||
d->Add("add ");
|
|
||||||
d->Add(id_str);
|
|
||||||
d->Add("[");
|
|
||||||
op1->Describe(d);
|
|
||||||
d->Add("]");
|
|
||||||
if ( op2 )
|
|
||||||
{
|
|
||||||
d->Add(" (");
|
|
||||||
op2->Describe(d);
|
|
||||||
d->Add(")");
|
|
||||||
}
|
|
||||||
d->Add(unique_str);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OP_DEL:
|
|
||||||
assert(op1);
|
|
||||||
d->Add("del ");
|
|
||||||
d->Add(id_str);
|
|
||||||
d->Add("[");
|
|
||||||
op1->Describe(d);
|
|
||||||
d->Add("]");
|
|
||||||
if ( op2 )
|
|
||||||
{
|
|
||||||
d->Add(" (");
|
|
||||||
op2->Describe(d);
|
|
||||||
d->Add(")");
|
|
||||||
}
|
|
||||||
d->Add(unique_str);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OP_EXPIRE:
|
|
||||||
assert(op1);
|
|
||||||
d->Add("expire ");
|
|
||||||
d->Add(id_str);
|
|
||||||
d->Add("[");
|
|
||||||
op1->Describe(d);
|
|
||||||
d->Add("]");
|
|
||||||
if ( op2 )
|
|
||||||
{
|
|
||||||
d->Add(" (");
|
|
||||||
op2->Describe(d);
|
|
||||||
d->Add(")");
|
|
||||||
}
|
|
||||||
d->Add(unique_str);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OP_PRINT:
|
|
||||||
assert(op1);
|
|
||||||
d->Add("print ");
|
|
||||||
d->Add(id_str);
|
|
||||||
op1->Describe(d);
|
|
||||||
d->Add(unique_str);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OP_READ_IDX:
|
|
||||||
assert(op1);
|
|
||||||
d->Add("read ");
|
|
||||||
d->Add(id_str);
|
|
||||||
d->Add("[");
|
|
||||||
op1->Describe(d);
|
|
||||||
d->Add("]");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
reporter->InternalError("unknown opcode for StateAccess");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( op1_type != TYPE_VAL )
|
|
||||||
Unref(const_cast<Val*>(op1));
|
|
||||||
}
|
|
||||||
|
|
||||||
void StateAccess::Log(StateAccess* access)
|
|
||||||
{
|
|
||||||
if ( access->target_type == TYPE_ID )
|
|
||||||
{
|
|
||||||
if ( access->target.id->FindAttr(ATTR_TRACKED) )
|
|
||||||
notifiers.Modified(access->target.id);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ( access->target.val->GetProperties() & MutableVal::TRACKED )
|
|
||||||
notifiers.Modified(access->target.val);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
ODesc desc;
|
|
||||||
access->Describe(&desc);
|
|
||||||
DBG_LOG(DBG_STATE, "operation: %s%s",
|
|
||||||
desc.Description(), replaying > 0 ? " (replay)" : "");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
delete access;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
NotifierRegistry notifiers;
|
NotifierRegistry notifiers;
|
||||||
|
|
||||||
NotifierRegistry::~NotifierRegistry()
|
NotifierRegistry::~NotifierRegistry()
|
||||||
|
|
|
@ -27,69 +27,6 @@ enum Opcode { // Op1 Op2 Op3 (Vals)
|
||||||
OP_READ_IDX, // idx
|
OP_READ_IDX, // idx
|
||||||
};
|
};
|
||||||
|
|
||||||
class StateAccess {
|
|
||||||
public:
|
|
||||||
StateAccess(Opcode opcode, const ID* target, const Val* op1,
|
|
||||||
const Val* op2 = 0, const Val* op3 = 0);
|
|
||||||
StateAccess(Opcode opcode, const MutableVal* target, const Val* op1,
|
|
||||||
const Val* op2 = 0, const Val* op3 = 0);
|
|
||||||
|
|
||||||
// For tables, the idx operand may be given as an index HashKey.
|
|
||||||
// This is for efficiency. While we need to reconstruct the index
|
|
||||||
// if we are actually going to serialize the access, we can at
|
|
||||||
// least skip it if we don't.
|
|
||||||
StateAccess(Opcode opcode, const ID* target, const HashKey* op1,
|
|
||||||
const Val* op2 = 0, const Val* op3 = 0);
|
|
||||||
StateAccess(Opcode opcode, const MutableVal* target, const HashKey* op1,
|
|
||||||
const Val* op2 = 0, const Val* op3 = 0);
|
|
||||||
|
|
||||||
StateAccess(const StateAccess& sa);
|
|
||||||
|
|
||||||
virtual ~StateAccess();
|
|
||||||
|
|
||||||
// Replays this access in the our environment.
|
|
||||||
void Replay();
|
|
||||||
|
|
||||||
// Returns target ID which may be an internal one for unbound vals.
|
|
||||||
ID* Target() const;
|
|
||||||
|
|
||||||
void Describe(ODesc* d) const;
|
|
||||||
|
|
||||||
// Main entry point when StateAcesses are performed.
|
|
||||||
// For every state-changing operation, this has to be called.
|
|
||||||
static void Log(StateAccess* access);
|
|
||||||
|
|
||||||
// If we're going to make additional non-replaying accesses during a
|
|
||||||
// Replay(), we have to call these.
|
|
||||||
static void SuspendReplay() { --replaying; }
|
|
||||||
static void ResumeReplay() { ++replaying; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
StateAccess() { target.id = 0; op1.val = op2 = op3 = 0; }
|
|
||||||
void RefThem();
|
|
||||||
|
|
||||||
Opcode opcode;
|
|
||||||
union {
|
|
||||||
ID* id;
|
|
||||||
MutableVal* val;
|
|
||||||
} target;
|
|
||||||
|
|
||||||
union {
|
|
||||||
Val* val;
|
|
||||||
const HashKey* key;
|
|
||||||
} op1;
|
|
||||||
|
|
||||||
Val* op2;
|
|
||||||
Val* op3;
|
|
||||||
|
|
||||||
enum Type { TYPE_ID, TYPE_VAL, TYPE_MVAL, TYPE_KEY };
|
|
||||||
Type target_type;
|
|
||||||
Type op1_type;
|
|
||||||
bool delete_op1_key;
|
|
||||||
|
|
||||||
static int replaying;
|
|
||||||
};
|
|
||||||
|
|
||||||
// We provide a notifier framework to inform interested parties of
|
// We provide a notifier framework to inform interested parties of
|
||||||
// modifications to selected global IDs/Vals. To get notified about a change,
|
// modifications to selected global IDs/Vals. To get notified about a change,
|
||||||
// derive a class from Notifier and register the interesting IDs/Vals with
|
// derive a class from Notifier and register the interesting IDs/Vals with
|
||||||
|
|
130
src/Val.cc
130
src/Val.cc
|
@ -438,8 +438,6 @@ ID* MutableVal::Bind() const
|
||||||
"%u", ++id_counter);
|
"%u", ++id_counter);
|
||||||
name[MAX_NAME_SIZE-1] = '\0';
|
name[MAX_NAME_SIZE-1] = '\0';
|
||||||
|
|
||||||
// DBG_LOG(DBG_STATE, "new unique ID %s", name);
|
|
||||||
|
|
||||||
id = new ID(name, SCOPE_GLOBAL, true);
|
id = new ID(name, SCOPE_GLOBAL, true);
|
||||||
id->SetType(const_cast<MutableVal*>(this)->Type()->Ref());
|
id->SetType(const_cast<MutableVal*>(this)->Type()->Ref());
|
||||||
|
|
||||||
|
@ -457,8 +455,6 @@ void MutableVal::TransferUniqueID(MutableVal* mv)
|
||||||
if ( ! id )
|
if ( ! id )
|
||||||
Bind();
|
Bind();
|
||||||
|
|
||||||
DBG_LOG(DBG_STATE, "transfering ID (new %s, old/alias %s)", new_name, id->Name());
|
|
||||||
|
|
||||||
// Keep old name as alias.
|
// Keep old name as alias.
|
||||||
aliases.push_back(id);
|
aliases.push_back(id);
|
||||||
|
|
||||||
|
@ -1178,55 +1174,6 @@ int TableVal::Assign(Val* index, HashKey* k, Val* new_val, Opcode op)
|
||||||
subnets->Insert(index, new_entry_val);
|
subnets->Insert(index, new_entry_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( LoggingAccess() && op != OP_NONE )
|
|
||||||
{
|
|
||||||
Val* rec_index = 0;
|
|
||||||
if ( ! index )
|
|
||||||
index = rec_index = RecoverIndex(&k_copy);
|
|
||||||
|
|
||||||
if ( new_val )
|
|
||||||
{
|
|
||||||
// A table.
|
|
||||||
if ( new_val->IsMutableVal() )
|
|
||||||
new_val->AsMutableVal()->AddProperties(GetProperties());
|
|
||||||
|
|
||||||
bool unref_old_val = false;
|
|
||||||
Val* old_val = old_entry_val ?
|
|
||||||
old_entry_val->Value() : 0;
|
|
||||||
if ( op == OP_INCR && ! old_val )
|
|
||||||
// If it's an increment, somebody has already
|
|
||||||
// checked that the index is there. If it's
|
|
||||||
// not, that can only be due to using the
|
|
||||||
// default.
|
|
||||||
{
|
|
||||||
old_val = Default(index);
|
|
||||||
unref_old_val = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(op != OP_INCR || old_val);
|
|
||||||
|
|
||||||
StateAccess::Log(
|
|
||||||
new StateAccess(
|
|
||||||
op == OP_INCR ?
|
|
||||||
OP_INCR_IDX : OP_ASSIGN_IDX,
|
|
||||||
this, index, new_val, old_val));
|
|
||||||
|
|
||||||
if ( unref_old_val )
|
|
||||||
Unref(old_val);
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// A set.
|
|
||||||
StateAccess::Log(
|
|
||||||
new StateAccess(OP_ADD, this,
|
|
||||||
index, 0, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( rec_index )
|
|
||||||
Unref(rec_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep old expiration time if necessary.
|
// Keep old expiration time if necessary.
|
||||||
if ( old_entry_val && attrs && attrs->FindAttr(ATTR_EXPIRE_CREATE) )
|
if ( old_entry_val && attrs && attrs->FindAttr(ATTR_EXPIRE_CREATE) )
|
||||||
new_entry_val->SetExpireAccess(old_entry_val->ExpireAccessTime());
|
new_entry_val->SetExpireAccess(old_entry_val->ExpireAccessTime());
|
||||||
|
@ -1237,6 +1184,7 @@ int TableVal::Assign(Val* index, HashKey* k, Val* new_val, Opcode op)
|
||||||
delete old_entry_val;
|
delete old_entry_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Modified();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1556,11 +1504,7 @@ Val* TableVal::Lookup(Val* index, bool use_default_val)
|
||||||
if ( v )
|
if ( v )
|
||||||
{
|
{
|
||||||
if ( attrs && attrs->FindAttr(ATTR_EXPIRE_READ) )
|
if ( attrs && attrs->FindAttr(ATTR_EXPIRE_READ) )
|
||||||
{
|
|
||||||
v->SetExpireAccess(network_time);
|
v->SetExpireAccess(network_time);
|
||||||
if ( LoggingAccess() && ExpirationEnabled() )
|
|
||||||
ReadOperation(index, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
return v->Value() ? v->Value() : this;
|
return v->Value() ? v->Value() : this;
|
||||||
}
|
}
|
||||||
|
@ -1587,11 +1531,7 @@ Val* TableVal::Lookup(Val* index, bool use_default_val)
|
||||||
if ( v )
|
if ( v )
|
||||||
{
|
{
|
||||||
if ( attrs && attrs->FindAttr(ATTR_EXPIRE_READ) )
|
if ( attrs && attrs->FindAttr(ATTR_EXPIRE_READ) )
|
||||||
{
|
|
||||||
v->SetExpireAccess(network_time);
|
v->SetExpireAccess(network_time);
|
||||||
if ( LoggingAccess() && ExpirationEnabled() )
|
|
||||||
ReadOperation(index, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
return v->Value() ? v->Value() : this;
|
return v->Value() ? v->Value() : this;
|
||||||
}
|
}
|
||||||
|
@ -1645,11 +1585,7 @@ TableVal* TableVal::LookupSubnetValues(const SubNetVal* search)
|
||||||
if ( entry )
|
if ( entry )
|
||||||
{
|
{
|
||||||
if ( attrs && attrs->FindAttr(ATTR_EXPIRE_READ) )
|
if ( attrs && attrs->FindAttr(ATTR_EXPIRE_READ) )
|
||||||
{
|
|
||||||
entry->SetExpireAccess(network_time);
|
entry->SetExpireAccess(network_time);
|
||||||
if ( LoggingAccess() && ExpirationEnabled() )
|
|
||||||
ReadOperation(s, entry);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Unref(s); // assign does not consume index
|
Unref(s); // assign does not consume index
|
||||||
|
@ -1679,8 +1615,6 @@ bool TableVal::UpdateTimestamp(Val* index)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
v->SetExpireAccess(network_time);
|
v->SetExpireAccess(network_time);
|
||||||
if ( LoggingAccess() && attrs->FindAttr(ATTR_EXPIRE_READ) )
|
|
||||||
ReadOperation(index, v);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1699,25 +1633,10 @@ Val* TableVal::Delete(const Val* index)
|
||||||
if ( subnets && ! subnets->Remove(index) )
|
if ( subnets && ! subnets->Remove(index) )
|
||||||
reporter->InternalWarning("index not in prefix table");
|
reporter->InternalWarning("index not in prefix table");
|
||||||
|
|
||||||
if ( LoggingAccess() )
|
|
||||||
{
|
|
||||||
if ( v )
|
|
||||||
{
|
|
||||||
// A set.
|
|
||||||
Val* has_old_val = val_mgr->GetInt(1);
|
|
||||||
StateAccess::Log(
|
|
||||||
new StateAccess(OP_DEL, this, index,
|
|
||||||
has_old_val));
|
|
||||||
Unref(has_old_val);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
StateAccess::Log(
|
|
||||||
new StateAccess(OP_DEL, this, index, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
delete k;
|
delete k;
|
||||||
delete v;
|
delete v;
|
||||||
|
|
||||||
|
Modified();
|
||||||
return va;
|
return va;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1736,9 +1655,7 @@ Val* TableVal::Delete(const HashKey* k)
|
||||||
|
|
||||||
delete v;
|
delete v;
|
||||||
|
|
||||||
if ( LoggingAccess() )
|
Modified();
|
||||||
StateAccess::Log(new StateAccess(OP_DEL, this, k));
|
|
||||||
|
|
||||||
return va;
|
return va;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1949,6 +1866,7 @@ void TableVal::DoExpire(double t)
|
||||||
HashKey* k = 0;
|
HashKey* k = 0;
|
||||||
TableEntryVal* v = 0;
|
TableEntryVal* v = 0;
|
||||||
TableEntryVal* v_saved = 0;
|
TableEntryVal* v_saved = 0;
|
||||||
|
bool modified = false;
|
||||||
|
|
||||||
for ( int i = 0; i < table_incremental_step &&
|
for ( int i = 0; i < table_incremental_step &&
|
||||||
(v = tbl->NextEntry(k, expire_cookie)); ++i )
|
(v = tbl->NextEntry(k, expire_cookie)); ++i )
|
||||||
|
@ -2001,18 +1919,18 @@ void TableVal::DoExpire(double t)
|
||||||
Unref(index);
|
Unref(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( LoggingAccess() )
|
|
||||||
StateAccess::Log(
|
|
||||||
new StateAccess(OP_EXPIRE, this, k));
|
|
||||||
|
|
||||||
tbl->RemoveEntry(k);
|
tbl->RemoveEntry(k);
|
||||||
Unref(v->Value());
|
Unref(v->Value());
|
||||||
delete v;
|
delete v;
|
||||||
|
modified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete k;
|
delete k;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( modified )
|
||||||
|
Modified();
|
||||||
|
|
||||||
if ( ! v )
|
if ( ! v )
|
||||||
{
|
{
|
||||||
expire_cookie = 0;
|
expire_cookie = 0;
|
||||||
|
@ -2124,11 +2042,8 @@ void TableVal::ReadOperation(Val* index, TableEntryVal* v)
|
||||||
// practical issues such as latency, we send one update every half
|
// practical issues such as latency, we send one update every half
|
||||||
// &read_expire.
|
// &read_expire.
|
||||||
if ( network_time - v->LastReadUpdate() > timeout / 2 )
|
if ( network_time - v->LastReadUpdate() > timeout / 2 )
|
||||||
{
|
|
||||||
StateAccess::Log(new StateAccess(OP_READ_IDX, this, index));
|
|
||||||
v->SetLastReadUpdate(network_time);
|
v->SetLastReadUpdate(network_time);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Val* TableVal::DoClone(CloneState* state)
|
Val* TableVal::DoClone(CloneState* state)
|
||||||
{
|
{
|
||||||
|
@ -2307,21 +2222,8 @@ RecordVal::~RecordVal()
|
||||||
void RecordVal::Assign(int field, Val* new_val, Opcode op)
|
void RecordVal::Assign(int field, Val* new_val, Opcode op)
|
||||||
{
|
{
|
||||||
Val* old_val = AsNonConstRecord()->replace(field, new_val);
|
Val* old_val = AsNonConstRecord()->replace(field, new_val);
|
||||||
|
|
||||||
if ( LoggingAccess() && op != OP_NONE )
|
|
||||||
{
|
|
||||||
if ( new_val && new_val->IsMutableVal() )
|
|
||||||
new_val->AsMutableVal()->AddProperties(GetProperties());
|
|
||||||
|
|
||||||
StringVal* index = new StringVal(Type()->AsRecordType()->FieldName(field));
|
|
||||||
StateAccess::Log(
|
|
||||||
new StateAccess(
|
|
||||||
op == OP_INCR ? OP_INCR_IDX : OP_ASSIGN_IDX,
|
|
||||||
this, index, new_val, old_val));
|
|
||||||
Unref(index); // The logging may keep a cached copy.
|
|
||||||
}
|
|
||||||
|
|
||||||
Unref(old_val);
|
Unref(old_val);
|
||||||
|
Modified();
|
||||||
}
|
}
|
||||||
|
|
||||||
Val* RecordVal::Lookup(int field) const
|
Val* RecordVal::Lookup(int field) const
|
||||||
|
@ -2627,19 +2529,6 @@ bool VectorVal::Assign(unsigned int index, Val* element, Opcode op)
|
||||||
else
|
else
|
||||||
val.vector_val->resize(index + 1);
|
val.vector_val->resize(index + 1);
|
||||||
|
|
||||||
if ( LoggingAccess() && op != OP_NONE )
|
|
||||||
{
|
|
||||||
if ( element->IsMutableVal() )
|
|
||||||
element->AsMutableVal()->AddProperties(GetProperties());
|
|
||||||
|
|
||||||
Val* ival = val_mgr->GetCount(index);
|
|
||||||
|
|
||||||
StateAccess::Log(new StateAccess(op == OP_INCR ?
|
|
||||||
OP_INCR_IDX : OP_ASSIGN_IDX,
|
|
||||||
this, ival, element, val_at_index));
|
|
||||||
Unref(ival);
|
|
||||||
}
|
|
||||||
|
|
||||||
Unref(val_at_index);
|
Unref(val_at_index);
|
||||||
|
|
||||||
// Note: we do *not* Ref() the element, if any, at this point.
|
// Note: we do *not* Ref() the element, if any, at this point.
|
||||||
|
@ -2647,6 +2536,7 @@ bool VectorVal::Assign(unsigned int index, Val* element, Opcode op)
|
||||||
// to do it similarly.
|
// to do it similarly.
|
||||||
(*val.vector_val)[index] = element;
|
(*val.vector_val)[index] = element;
|
||||||
|
|
||||||
|
Modified();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
15
src/Val.h
15
src/Val.h
|
@ -51,8 +51,6 @@ class StringVal;
|
||||||
class EnumVal;
|
class EnumVal;
|
||||||
class MutableVal;
|
class MutableVal;
|
||||||
|
|
||||||
class StateAccess;
|
|
||||||
|
|
||||||
class VectorVal;
|
class VectorVal;
|
||||||
|
|
||||||
class TableEntryVal;
|
class TableEntryVal;
|
||||||
|
@ -532,17 +530,6 @@ public:
|
||||||
virtual bool AddProperties(Properties state);
|
virtual bool AddProperties(Properties state);
|
||||||
virtual bool RemoveProperties(Properties state);
|
virtual bool RemoveProperties(Properties state);
|
||||||
|
|
||||||
// Whether StateAccess:LogAccess needs to be called.
|
|
||||||
bool LoggingAccess() const
|
|
||||||
{
|
|
||||||
#ifndef DEBUG
|
|
||||||
return props & TRACKED;
|
|
||||||
#else
|
|
||||||
return debug_logger.IsVerbose() ||
|
|
||||||
(props & TRACKED);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit MutableVal(BroType* t) : Val(t)
|
explicit MutableVal(BroType* t) : Val(t)
|
||||||
{ props = 0; id = 0; }
|
{ props = 0; id = 0; }
|
||||||
|
@ -553,6 +540,7 @@ protected:
|
||||||
friend class Val;
|
friend class Val;
|
||||||
|
|
||||||
void SetID(ID* arg_id) { Unref(id); id = arg_id; }
|
void SetID(ID* arg_id) { Unref(id); id = arg_id; }
|
||||||
|
void Modified() { notifiers.Modified(this); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ID* Bind() const;
|
ID* Bind() const;
|
||||||
|
@ -957,7 +945,6 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class Val;
|
friend class Val;
|
||||||
friend class StateAccess;
|
|
||||||
TableVal() {}
|
TableVal() {}
|
||||||
|
|
||||||
void Init(TableType* t);
|
void Init(TableType* t);
|
||||||
|
|
11
src/bro.bif
11
src/bro.bif
|
@ -1843,17 +1843,6 @@ function global_ids%(%): id_table
|
||||||
TableVal* ids = new TableVal(id_table);
|
TableVal* ids = new TableVal(id_table);
|
||||||
PDict(ID)* globals = global_scope()->Vars();
|
PDict(ID)* globals = global_scope()->Vars();
|
||||||
IterCookie* c = globals->InitForIteration();
|
IterCookie* c = globals->InitForIteration();
|
||||||
#ifdef DEBUG
|
|
||||||
/**
|
|
||||||
* Explanation time: c needs to be a robust cookie when one is in debug mode,
|
|
||||||
* otherwise the Zeek process will crash in ~80% of cases when -B all is specified.
|
|
||||||
* The reason for this are the RecordVals that we create. RecordVal::Assign triggers
|
|
||||||
* a StateAccess::Log, which in turn (only in debug mode) triggers StateAccess::Describe,
|
|
||||||
* which creates a UniqueID for the variable, which triggers an insert into global_scope.
|
|
||||||
* Which invalidates the iteration cookie if it is not robust.
|
|
||||||
**/
|
|
||||||
globals->MakeRobustCookie(c);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ID* id;
|
ID* id;
|
||||||
while ( (id = globals->NextEntry(c)) )
|
while ( (id = globals->NextEntry(c)) )
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue