mirror of
https://github.com/zeek/zeek.git
synced 2025-10-06 16:48:19 +00:00
Fixed table expiration evaluation.
The expiration attribute expression is now evaluated for every use. Thus later adjustments of the value (e.g. by redefining a const) will now take effect. Values less than 0 will disable expiration.
This commit is contained in:
parent
f662989c09
commit
8a87055fcc
4 changed files with 98 additions and 31 deletions
77
src/Val.cc
77
src/Val.cc
|
@ -1323,7 +1323,7 @@ void TableVal::Init(TableType* t)
|
||||||
{
|
{
|
||||||
::Ref(t);
|
::Ref(t);
|
||||||
table_type = t;
|
table_type = t;
|
||||||
expire_expr = 0;
|
expire_func = 0;
|
||||||
expire_time = 0;
|
expire_time = 0;
|
||||||
expire_cookie = 0;
|
expire_cookie = 0;
|
||||||
timer = 0;
|
timer = 0;
|
||||||
|
@ -1350,7 +1350,8 @@ TableVal::~TableVal()
|
||||||
delete subnets;
|
delete subnets;
|
||||||
Unref(attrs);
|
Unref(attrs);
|
||||||
Unref(def_val);
|
Unref(def_val);
|
||||||
Unref(expire_expr);
|
Unref(expire_func);
|
||||||
|
Unref(expire_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TableVal::RemoveAll()
|
void TableVal::RemoveAll()
|
||||||
|
@ -1399,8 +1400,8 @@ void TableVal::SetAttrs(Attributes* a)
|
||||||
Attr* ef = attrs->FindAttr(ATTR_EXPIRE_FUNC);
|
Attr* ef = attrs->FindAttr(ATTR_EXPIRE_FUNC);
|
||||||
if ( ef )
|
if ( ef )
|
||||||
{
|
{
|
||||||
expire_expr = ef->AttrExpr();
|
expire_func = ef->AttrExpr();
|
||||||
expire_expr->Ref();
|
expire_func->Ref();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1410,14 +1411,8 @@ void TableVal::CheckExpireAttr(attr_tag at)
|
||||||
|
|
||||||
if ( a )
|
if ( a )
|
||||||
{
|
{
|
||||||
Val* timeout = a->AttrExpr()->Eval(0);
|
expire_time = a->AttrExpr();
|
||||||
if ( ! timeout )
|
expire_time->Ref();
|
||||||
{
|
|
||||||
a->AttrExpr()->Error("value of timeout not fixed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
expire_time = timeout->AsInterval();
|
|
||||||
|
|
||||||
if ( timer )
|
if ( timer )
|
||||||
timer_mgr->Cancel(timer);
|
timer_mgr->Cancel(timer);
|
||||||
|
@ -1791,7 +1786,7 @@ Val* TableVal::Lookup(Val* index, bool use_default_val)
|
||||||
if ( attrs && attrs->FindAttr(ATTR_EXPIRE_READ) )
|
if ( attrs && attrs->FindAttr(ATTR_EXPIRE_READ) )
|
||||||
{
|
{
|
||||||
v->SetExpireAccess(network_time);
|
v->SetExpireAccess(network_time);
|
||||||
if ( LoggingAccess() && expire_time )
|
if ( LoggingAccess() && ExpirationEnabled() )
|
||||||
ReadOperation(index, v);
|
ReadOperation(index, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1822,7 +1817,7 @@ Val* TableVal::Lookup(Val* index, bool use_default_val)
|
||||||
if ( attrs && attrs->FindAttr(ATTR_EXPIRE_READ) )
|
if ( attrs && attrs->FindAttr(ATTR_EXPIRE_READ) )
|
||||||
{
|
{
|
||||||
v->SetExpireAccess(network_time);
|
v->SetExpireAccess(network_time);
|
||||||
if ( LoggingAccess() && expire_time )
|
if ( LoggingAccess() && ExpirationEnabled() )
|
||||||
ReadOperation(index, v);
|
ReadOperation(index, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1880,7 +1875,7 @@ TableVal* TableVal::LookupSubnetValues(const SubNetVal* search)
|
||||||
if ( attrs && attrs->FindAttr(ATTR_EXPIRE_READ) )
|
if ( attrs && attrs->FindAttr(ATTR_EXPIRE_READ) )
|
||||||
{
|
{
|
||||||
entry->SetExpireAccess(network_time);
|
entry->SetExpireAccess(network_time);
|
||||||
if ( LoggingAccess() && expire_time )
|
if ( LoggingAccess() && ExpirationEnabled() )
|
||||||
ReadOperation(s, entry);
|
ReadOperation(s, entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2174,6 +2169,10 @@ void TableVal::DoExpire(double t)
|
||||||
if ( ! type )
|
if ( ! type )
|
||||||
return; // FIX ME ###
|
return; // FIX ME ###
|
||||||
|
|
||||||
|
double timeout = GetExpireTime();
|
||||||
|
if ( timeout < 0 )
|
||||||
|
return; // Skip in case of invalid expiration value
|
||||||
|
|
||||||
PDict(TableEntryVal)* tbl = AsNonConstTable();
|
PDict(TableEntryVal)* tbl = AsNonConstTable();
|
||||||
|
|
||||||
if ( ! expire_cookie )
|
if ( ! expire_cookie )
|
||||||
|
@ -2197,11 +2196,11 @@ void TableVal::DoExpire(double t)
|
||||||
// correct, so we just need to wait.
|
// correct, so we just need to wait.
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ( v->ExpireAccessTime() + expire_time < t )
|
else if ( v->ExpireAccessTime() + timeout < t )
|
||||||
{
|
{
|
||||||
Val* val = v->Value();
|
Val* val = v->Value();
|
||||||
|
|
||||||
if ( expire_expr )
|
if ( expire_func )
|
||||||
{
|
{
|
||||||
Val* idx = RecoverIndex(k);
|
Val* idx = RecoverIndex(k);
|
||||||
double secs = CallExpireFunc(idx);
|
double secs = CallExpireFunc(idx);
|
||||||
|
@ -2221,7 +2220,7 @@ void TableVal::DoExpire(double t)
|
||||||
{
|
{
|
||||||
// User doesn't want us to expire
|
// User doesn't want us to expire
|
||||||
// this now.
|
// this now.
|
||||||
v->SetExpireAccess(network_time - expire_time + secs);
|
v->SetExpireAccess(network_time - timeout + secs);
|
||||||
delete k;
|
delete k;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -2258,9 +2257,29 @@ void TableVal::DoExpire(double t)
|
||||||
InitTimer(table_expire_delay);
|
InitTimer(table_expire_delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double TableVal::GetExpireTime()
|
||||||
|
{
|
||||||
|
if ( expire_time )
|
||||||
|
{
|
||||||
|
Val* timeout = expire_time->Eval(0);
|
||||||
|
if ( timeout && (timeout->AsInterval() >= 0) )
|
||||||
|
{
|
||||||
|
return timeout->AsInterval();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// invalid expiration interval
|
||||||
|
expire_time = 0;
|
||||||
|
if ( timer )
|
||||||
|
timer_mgr->Cancel(timer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
double TableVal::CallExpireFunc(Val* idx)
|
double TableVal::CallExpireFunc(Val* idx)
|
||||||
{
|
{
|
||||||
if ( ! expire_expr )
|
if ( ! expire_func )
|
||||||
{
|
{
|
||||||
Unref(idx);
|
Unref(idx);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2285,7 +2304,7 @@ double TableVal::CallExpireFunc(Val* idx)
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Val* vf = expire_expr->Eval(0);
|
Val* vf = expire_func->Eval(0);
|
||||||
|
|
||||||
if ( ! vf )
|
if ( ! vf )
|
||||||
{
|
{
|
||||||
|
@ -2319,11 +2338,15 @@ double TableVal::CallExpireFunc(Val* idx)
|
||||||
|
|
||||||
void TableVal::ReadOperation(Val* index, TableEntryVal* v)
|
void TableVal::ReadOperation(Val* index, TableEntryVal* v)
|
||||||
{
|
{
|
||||||
|
// Skip in case of invalid expiration value
|
||||||
|
double timeout = GetExpireTime();
|
||||||
|
if ( timeout < 0 )
|
||||||
|
return;
|
||||||
// In theory we need to only propagate one update per &read_expire
|
// In theory we need to only propagate one update per &read_expire
|
||||||
// interval to prevent peers from expiring intervals. To account for
|
// interval to prevent peers from expiring intervals. To account for
|
||||||
// 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() > expire_time / 2 )
|
if ( network_time - v->LastReadUpdate() > timeout / 2 )
|
||||||
{
|
{
|
||||||
StateAccess::Log(new StateAccess(OP_READ_IDX, this, index));
|
StateAccess::Log(new StateAccess(OP_READ_IDX, this, index));
|
||||||
v->SetLastReadUpdate(network_time);
|
v->SetLastReadUpdate(network_time);
|
||||||
|
@ -2362,11 +2385,9 @@ bool TableVal::DoSerialize(SerialInfo* info) const
|
||||||
state->did_index = false;
|
state->did_index = false;
|
||||||
info->s->WriteOpenTag(table_type->IsSet() ? "set" : "table");
|
info->s->WriteOpenTag(table_type->IsSet() ? "set" : "table");
|
||||||
|
|
||||||
if ( ! SERIALIZE(expire_time) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
SERIALIZE_OPTIONAL(attrs);
|
SERIALIZE_OPTIONAL(attrs);
|
||||||
SERIALIZE_OPTIONAL(expire_expr);
|
SERIALIZE_OPTIONAL(expire_time);
|
||||||
|
SERIALIZE_OPTIONAL(expire_func);
|
||||||
|
|
||||||
// Make sure nobody kills us in between.
|
// Make sure nobody kills us in between.
|
||||||
const_cast<TableVal*>(this)->Ref();
|
const_cast<TableVal*>(this)->Ref();
|
||||||
|
@ -2491,13 +2512,11 @@ bool TableVal::DoUnserialize(UnserialInfo* info)
|
||||||
{
|
{
|
||||||
DO_UNSERIALIZE(MutableVal);
|
DO_UNSERIALIZE(MutableVal);
|
||||||
|
|
||||||
if ( ! UNSERIALIZE(&expire_time) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Init((TableType*) type);
|
Init((TableType*) type);
|
||||||
|
|
||||||
UNSERIALIZE_OPTIONAL(attrs, Attributes::Unserialize(info));
|
UNSERIALIZE_OPTIONAL(attrs, Attributes::Unserialize(info));
|
||||||
UNSERIALIZE_OPTIONAL(expire_expr, Expr::Unserialize(info));
|
UNSERIALIZE_OPTIONAL(expire_time, Expr::Unserialize(info));
|
||||||
|
UNSERIALIZE_OPTIONAL(expire_func, Expr::Unserialize(info));
|
||||||
|
|
||||||
while ( true )
|
while ( true )
|
||||||
{
|
{
|
||||||
|
|
|
@ -862,6 +862,11 @@ protected:
|
||||||
// Calculates default value for index. Returns 0 if none.
|
// Calculates default value for index. Returns 0 if none.
|
||||||
Val* Default(Val* index);
|
Val* Default(Val* index);
|
||||||
|
|
||||||
|
// Returns true if item expiration is defined.
|
||||||
|
bool ExpirationEnabled() { return expire_time != 0; }
|
||||||
|
// Returns the expiration time defined by create, read
|
||||||
|
// or write expire attribute or -1 for invalid values.
|
||||||
|
double GetExpireTime();
|
||||||
// Calls &expire_func and returns its return interval;
|
// Calls &expire_func and returns its return interval;
|
||||||
// takes ownership of the reference.
|
// takes ownership of the reference.
|
||||||
double CallExpireFunc(Val *idx);
|
double CallExpireFunc(Val *idx);
|
||||||
|
@ -874,8 +879,8 @@ protected:
|
||||||
TableType* table_type;
|
TableType* table_type;
|
||||||
CompositeHash* table_hash;
|
CompositeHash* table_hash;
|
||||||
Attributes* attrs;
|
Attributes* attrs;
|
||||||
double expire_time;
|
Expr* expire_time;
|
||||||
Expr* expire_expr;
|
Expr* expire_func;
|
||||||
TableValTimer* timer;
|
TableValTimer* timer;
|
||||||
IterCookie* expire_cookie;
|
IterCookie* expire_cookie;
|
||||||
PrefixTable* subnets;
|
PrefixTable* subnets;
|
||||||
|
|
5
testing/btest/Baseline/language.expire-redef/output
Normal file
5
testing/btest/Baseline/language.expire-redef/output
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
Run 0
|
||||||
|
Run 1
|
||||||
|
Run 2
|
||||||
|
Expired: 0 --> some data
|
||||||
|
Run 3
|
38
testing/btest/language/expire-redef.bro
Normal file
38
testing/btest/language/expire-redef.bro
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
# @TEST-EXEC: btest-bg-run broproc bro %INPUT
|
||||||
|
# @TEST-EXEC: btest-bg-wait -k 5
|
||||||
|
# @TEST-EXEC: cat broproc/.stdout > output
|
||||||
|
# @TEST-EXEC: btest-diff output
|
||||||
|
|
||||||
|
|
||||||
|
@load frameworks/communication/listen
|
||||||
|
|
||||||
|
const exp_val = -1sec &redef;
|
||||||
|
|
||||||
|
global expired: function(tbl: table[int] of string, idx: int): interval;
|
||||||
|
global data: table[int] of string &write_expire=exp_val &expire_func=expired;
|
||||||
|
|
||||||
|
redef table_expire_interval = 1sec;
|
||||||
|
redef exp_val = 3sec;
|
||||||
|
|
||||||
|
global runs = 0;
|
||||||
|
event do_it()
|
||||||
|
{
|
||||||
|
print fmt("Run %s", runs);
|
||||||
|
|
||||||
|
++runs;
|
||||||
|
if ( runs < 4 )
|
||||||
|
schedule 1sec { do_it() };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function expired(tbl: table[int] of string, idx: int): interval
|
||||||
|
{
|
||||||
|
print fmt("Expired: %s --> %s", idx, tbl[idx]);
|
||||||
|
return 0sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
event bro_init() &priority=-10
|
||||||
|
{
|
||||||
|
data[0] = "some data";
|
||||||
|
schedule 1sec { do_it() };
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue