speedup for expireover on timecaf
Richard Michael Todd
rmtodd at mailhost.ecn.ou.edu
Wed Aug 25 05:09:29 UTC 1999
This patch should speed up expireover handling of timecaf spool regions. The
patch implements caching of CAF file TOC data in order to speed up
SMretrieve(..., RETR_STAT) requests, so any stats of articles in a CAF file
that this process has already seen will not require further disk I/O to
complete.
Index: storage/timecaf/timecaf.c
===================================================================
RCS file: /home/rmtodd/TempCVS/Temp-CVS-Repository/inn-current/storage/timecaf/timecaf.c,v
retrieving revision 1.1.1.2
diff -u -r1.1.1.2 timecaf.c
--- timecaf.c 1999/06/04 01:47:23 1.1.1.2
+++ timecaf.c 1999/08/22 04:53:33
@@ -55,6 +55,49 @@
typedef enum {FIND_DIR, FIND_CAF, FIND_TOPDIR} FINDTYPE;
+/*
+** Structures for the cache for stat information (to make expireover etc.
+** faster.
+**
+** The first structure contains the TOC info for a single CAF file. The 2nd
+** one has pointers to the info for up to 256 CAF files, indexed
+** by the 2nd least significant byte of the arrival time.
+*/
+
+struct caftoccacheent {
+ CAFTOCENT *toc;
+ CAFHEADER header;
+};
+typedef struct caftoccacheent CAFTOCCACHEENT;
+
+struct caftocl1cache {
+ CAFTOCCACHEENT *entries[256];
+};
+typedef struct caftocl1cache CAFTOCL1CACHE;
+
+/*
+** and similar structures indexed by the 3rd and 4th bytes of the arrival time.
+** pointing to the lower level structures. Note that the top level structure
+** (the one indexed by the MSByte of the timestamp) is likely to have only
+** one active pointer, unless your spool keeps more than 194 days of articles,
+** but it doesn't cost much to keep that one structure around and keep the
+** code general.
+*/
+
+struct caftocl2cache {
+ CAFTOCL1CACHE *l1ptr[256];
+};
+typedef struct caftocl2cache CAFTOCL2CACHE;
+
+struct caftocl3cache {
+ CAFTOCL2CACHE *l2ptr[256];
+};
+typedef struct caftocl3cache CAFTOCL3CACHE;
+
+static CAFTOCL3CACHE *TOCCache[256]; /* indexed by storage class! */
+static int TOCCacheHits, TOCCacheMisses;
+
+
static TOKEN MakeToken(time_t time, int seqnum, STORAGECLASS class, TOKEN *oldtoken) {
TOKEN token;
unsigned int i;
@@ -128,6 +171,134 @@
return TRUE;
}
+/*
+** Routines for managing the 'TOC cache' (cache of TOCs of various CAF files)
+**
+** Attempt to look up a given TOC entry in the cache. Takes the timestamp
+** as arguments.
+*/
+
+static CAFTOCCACHEENT *
+CheckTOCCache(int timestamp, int tokenclass)
+{
+ CAFTOCL2CACHE *l2;
+ CAFTOCL1CACHE *l1;
+ CAFTOCCACHEENT *cent;
+ unsigned char tmp;
+
+ if (TOCCache[tokenclass] == NULL) return NULL; /* cache is empty */
+
+ tmp = (timestamp>>16) & 0xff;
+ l2 = TOCCache[tokenclass]->l2ptr[tmp];
+ if (l2 == NULL) return NULL;
+
+ tmp = (timestamp>>8) & 0xff;
+ l1 = l2->l1ptr[tmp];
+ if (l1 == NULL) return NULL;
+
+ tmp = (timestamp) & 0xff;
+ cent = l1->entries[tmp];
+
+ ++TOCCacheHits;
+ return cent;
+}
+
+/*
+** Add given TOC and header to the cache. Assume entry is not already in
+** cache.
+*/
+static CAFTOCCACHEENT *
+AddTOCCache(int timestamp, CAFTOCENT *toc, CAFHEADER head, int tokenclass)
+{
+ CAFTOCL2CACHE *l2;
+ CAFTOCL1CACHE *l1;
+ CAFTOCCACHEENT *cent;
+ unsigned char tmp;
+ int i;
+
+ if (TOCCache[tokenclass] == NULL) {
+ TOCCache[tokenclass] = NEW(CAFTOCL3CACHE, 1);
+ for (i = 0 ; i < 256 ; ++i) TOCCache[tokenclass]->l2ptr[i] = NULL;
+ }
+
+ tmp = (timestamp>>16) & 0xff;
+ l2 = TOCCache[tokenclass]->l2ptr[tmp];
+ if (l2 == NULL) {
+ TOCCache[tokenclass]->l2ptr[tmp] = l2 = NEW(CAFTOCL2CACHE, 1);
+ for (i = 0 ; i < 256 ; ++i) l2->l1ptr[i] = NULL;
+ }
+
+ tmp = (timestamp>>8) & 0xff;
+ l1 = l2->l1ptr[tmp];
+ if (l1 == NULL) {
+ l2->l1ptr[tmp] = l1 = NEW(CAFTOCL1CACHE, 1);
+ for (i = 0 ; i < 256 ; ++i) l1->entries[i] = NULL;
+ }
+
+ tmp = (timestamp) & 0xff;
+ cent = NEW(CAFTOCCACHEENT, 1);
+ l1->entries[tmp] = cent;
+
+ cent->header = head;
+ cent->toc = toc;
+ ++TOCCacheMisses;
+ return cent;
+}
+
+/*
+** Do stating of an article, going thru the TOC cache if possible.
+*/
+
+static ARTHANDLE *
+StatArticle(int timestamp, ARTNUM artnum, int tokenclass)
+{
+ CAFTOCCACHEENT *cent;
+ CAFTOCENT *toc;
+ CAFHEADER head;
+ char *path;
+ CAFTOCENT *tocentry;
+ ARTHANDLE *art;
+
+ cent = CheckTOCCache(timestamp,tokenclass);
+ if (cent == NULL) {
+ path = MakePath(timestamp, tokenclass);
+ toc = CAFReadTOC(path, &head);
+ if (toc == NULL) {
+ if (caf_error == CAF_ERR_ARTNOTHERE) {
+ SMseterror(SMERR_NOENT, NULL);
+ } else {
+ SMseterror(SMERR_UNDEFINED, NULL);
+ }
+ DISPOSE(path);
+ return NULL;
+ }
+ cent = AddTOCCache(timestamp, toc, head, tokenclass);
+ DISPOSE(path);
+ }
+
+ /* check current TOC for the given artnum. */
+ if (artnum < cent->header.Low || artnum > cent->header.High) {
+ SMseterror(SMERR_NOENT, NULL);
+ return NULL;
+ }
+
+ tocentry = &(cent->toc[artnum - cent->header.Low]);
+ if (tocentry->Size == 0) {
+ /* no article with that article number present */
+ SMseterror(SMERR_NOENT, NULL);
+ return NULL;
+ }
+
+ /* stat is a success, so build a null art struct to represent that. */
+ art = NEW(ARTHANDLE, 1);
+ art->type = TOKEN_TIMECAF;
+ art->data = NULL;
+ art->len = 0;
+ art->private = NULL;
+ return art;
+}
+
+
static void
CloseOpenFile(CAFOPENFILE *foo) {
if (foo->fd >= 0) {
@@ -334,6 +505,7 @@
char *path;
ARTHANDLE *art;
static TOKEN ret_token;
+ time_t now;
if (token.type != TOKEN_TIMECAF) {
SMseterror(SMERR_INTERNAL, NULL);
@@ -341,6 +513,26 @@
}
BreakToken(token, ×tamp, &artnum);
+
+ /*
+ ** Do a possible shortcut on RETR_STAT requests, going thru the "TOC cache"
+ ** we mentioned above. We only try to go thru the TOC Cache under these
+ ** conditions:
+ ** 1) SMpreopen is TRUE (so we're "preopening" the TOCs.)
+ ** 2) the timestamp is older than the timestamp corresponding to current
+ ** time. Any timestamp that matches current time (to within 256 secondsf
+ ** would be in a CAF file that innd is actively
+ ** writing, in which case we would not want to cache the TOC for that
+ ** CAF file.
+ */
+
+ if (SMpreopen && amount == RETR_STAT) {
+ now = time(NULL);
+ if (timestamp < ((now >> 8) & 0xffffff)) {
+ return StatArticle(timestamp, artnum, token.class);
+ }
+ }
+
path = MakePath(timestamp, token.class);
if ((art = OpenArticle(path, artnum, amount)) != (ARTHANDLE *)NULL) {
art->arrived = timestamp<<8; /* XXX not quite accurate arrival time,
More information about the inn-patches
mailing list