Make news item merging deterministic and safe for year 2038

News reporting merges news items into recent items with same contents.
For that purpuse, we keep a small cache of recent items.  When a new
item can't be merged into an item in the cache, the oldest item gets
evicted to make space for the new one.

ncache() evicts the first item with the smallest timestamp (struct
nwsstr member nws_when).  Timestamps are in seconds, therefore clashes
are common, and eviction depends on exact timing.  Such indeterminism
can make the smoke test fail.

Moreover, ncache() assumes timestamps cannot exceed 0x7fffffff.  If
they do, it always evicts the slot 0.  They will in 2038.

Fix by evicting round robin.  This always evicts the oldest item.
This commit is contained in:
Markus Armbruster 2012-12-27 14:43:43 +01:00
parent e9fdc200e4
commit 5738e399c4

View file

@ -30,7 +30,7 @@
* Dave Pare, 1994 * Dave Pare, 1994
* Steve McClure, 1997 * Steve McClure, 1997
* Ron Koenderink, 2005 * Ron Koenderink, 2005
* Markus Armbruster, 2004-2011 * Markus Armbruster, 2004-2012
*/ */
#include <config.h> #include <config.h>
@ -49,6 +49,7 @@ struct newscache {
}; };
static struct newscache cache[MAXNOC][SLOTS]; static struct newscache cache[MAXNOC][SLOTS];
static unsigned char cache_oldest[MAXNOC];
static int news_tail; static int news_tail;
static struct newscache * static struct newscache *
@ -157,18 +158,12 @@ ncache(int actor, int event, int victim, int times)
{ {
struct newscache *np; struct newscache *np;
int i; int i;
int oldslot; unsigned oldslot;
time_t oldtime, dur; time_t dur;
time_t now = time(NULL); time_t now = time(NULL);
oldslot = -1;
oldtime = 0x7fffffff;
for (i = 0; i < SLOTS; i++) { for (i = 0; i < SLOTS; i++) {
np = &cache[actor][i]; np = &cache[actor][i];
if (np->news.nws_when < oldtime) {
oldslot = i;
oldtime = np->news.nws_when;
}
if (np->news.nws_vrb == 0) if (np->news.nws_vrb == 0)
continue; continue;
dur = now - np->news.nws_when; dur = now - np->news.nws_when;
@ -181,11 +176,13 @@ ncache(int actor, int event, int victim, int times)
return np; return np;
} }
} }
if (CANT_HAPPEN(oldslot < 0))
oldslot = 0;
if (CANT_HAPPEN(!strstr(rpt[event].r_newstory[0], "%s") && victim != 0)) if (CANT_HAPPEN(!strstr(rpt[event].r_newstory[0], "%s") && victim != 0))
victim = 0; victim = 0;
oldslot = cache_oldest[actor];
if (CANT_HAPPEN(oldslot >= SLOTS))
oldslot = 0;
np = &cache[actor][oldslot]; np = &cache[actor][oldslot];
cache_oldest[actor] = (oldslot + 1) % SLOTS;
ef_blank(EF_NEWS, news_tail, &np->news); ef_blank(EF_NEWS, news_tail, &np->news);
np->news.nws_ano = actor; np->news.nws_ano = actor;
np->news.nws_vrb = event; np->news.nws_vrb = event;