/* Copyright (C) 1995 EGLE Magic, New Zealand, All rights reserved. */ #include #include #include #include "emsg.h" #include "str.h" #include "group.h" #include "lib.h" #include "item.h" #include "dnews.h" #include "sary.h" #include "hist.h" #include "nntp.h" #include "suck.h" #include "expire.h" /* Do in blocks of 100 items so background is not badly affected. Do history file until have 100,000 items to delete. Then sort in group order, and for each group file. Read file, delete items, write file. Do 1 files at a time. Change main loop so if 'background' then it calls background after checking there is no 'real' work to do. Also need to re-create index for history file Only needs exclusive access for long enough to read any new items and append them to the new history file. */ void copy_mid(char *dst, char *src); static int pused,remember,inpurge; static int nkill; static int s_nhist,s_nold,s_nhistdel; static int s_nart,s_nartdel,s_nrealdel,s_time; static double s_speed; typedef struct {int min,max,keep,normal,purge;} Rules; static Rules *rcache[MAX_GROUPS]; static int nrcache,estate; static int purge_upto; static char expire_started[50],expire_end[50]; void expire_cache_clear(void); static int used_start,used_end; void expire_do(void) { static int i,t,uptoi; static char upto[500]; /* Message id we are about to process */ char *h; if (inpurge) { expire_purgelost(); return;} pused = lib_pused(); if (estate==0) { used_start = pused; imsg("pused %d \n",pused); uptoi = 0; s_nhist=s_nold=s_nhistdel=s_nart=s_nartdel=s_nrealdel=0; s_time = lib_gmtime(); nntp_setsleep(0); /* Keep calling unless you get packets */ strcpy(expire_started,lib_now()); h = hist_line(0); h = hist_next(); estate=1; copy_mid(upto,h); return; /* SHOULD CLEAR RULE CACHE ETC. WHEN THAT EXISTS*/ expire_cache_clear(); wmsg("expire: Percent disk used %d \n",pused); } if (estate==1) { hist_line(uptoi); h = hist_next(); if (uptoi!=0) for (i=0; i<100; i++) { if (h==NULL) break; if (strstr(h,upto)!=NULL) break; h = hist_next(); } if (h!=NULL) dmsg("expire: Restarting at {%s} {%s} \n",upto,h); if (h!=NULL) h = hist_next(); if (h==NULL) { emsg("expire: Failed to find restart position {%s} \n",upto); goto fail; } for (i=0;h!=NULL;i++) { s_nhist++; expire_line(h); uptoi = hist_upto(); h = hist_next(); if (h==NULL) break; if ((nkill+1000)>kill_max()) { copy_mid(upto,h); estate = 2; return; } if (i>100) { copy_mid(upto,h); return; } } estate=3; } if (estate==2 || estate==3) { /* Doing a block of items's */ purge_upto = item_purge(); if (purge_upto>=0) { return; } nkill = 0; if (estate==2) {estate=1; return; } /* Do rest*/ estate = 4; return; } if (estate==4) { hist_switch(); fail: suck_expire_end(); /* Set suck loop to idle */ nntp_setsleep(3); /* Switch back to sleeping mode */ strcpy(expire_end,lib_now()); wmsg("%s",expire_status()); used_end = pused; dnews_manager_report("Daily expire report"); /* Send the manager a daily report */ estate = 0; return; } } void expire_cache_clear(void) { int i; for (i=0; iarrived~expires~postedgroup/num group/num ... */ static char curgrp[100]; void expire_line(char *h) { char *g; char fixed[10000]; char *s,*out; int arrived,expires,first; int kill_grp[900],kill_num[900],kill[900]; int ng,gi,i; arrived = hist_date_arrived(h); expires = hist_date_expires(h); g = hist_groupfirst(h); for (ng=0;g!=NULL;) { s_nart++; ncpy(curgrp,g,80); gi = group_find(g); expire_rules(gi); kill_grp[ng] = gi; kill_num[ng] = hist_groupnextnum(); kill[ng] = FALSE; if (expire_item(gi,kill_num[ng],arrived,expires)) { kill[ng] = TRUE; s_nartdel++; dmsg("expire: Expring item %s %d \n",g,kill_num[ng]); } ng++; g = hist_groupnext(); } if (ng==0) { s_nold++; /* SHOULD DELETE IF OLDER THAN REMEMBER VALUE*/ if (lib_gmtime()-(remember*60*60*24) >arrived) { s_nhistdel++; return; } } /* Don't kill first one if any of rest are still left */ for (i=1; i0) if (kill[0]) s_nrealdel++; for (i=0; i= maxitems) && (expires==0)) return TRUE; if (purge!=0) if (age>purge) return TRUE; if (age=expires) return TRUE; if (age>normal) return TRUE; return FALSE; /* Keep the item */ } #define DNEWS_EXPIRE "expire.conf" static Sary *expire; /* total 200 remember 14 upto 90% groups * keep 1 normal 2 purge 33 maxitems 100 minitems 0 Figure out the rules for this group Add caching if this is a bottle neck, it probably is */ void expire_rules(int g) { int i; static char bf[600]; char *s; static int last_time; Rules *r; if (expire==NULL) expire_load(); if ( (lib_gmtime()-last_time) > 560) { expire_cache_clear(); last_time = lib_gmtime(); } if (rcache[g]!=NULL) { r = rcache[g]; maxitems = r->max; minitems = r->min; keep = r->keep; normal = r->normal; purge = r->purge; return; } for (i=0; imax = maxitems ; r->min = minitems ; r->keep = keep; r->normal = normal; r->purge = purge; rcache[g] = r; if (g>=nrcache) nrcache = g+1; } void expire_load(void) { if (expire!=NULL) s_free(expire); expire = s_alloc(); s_read(expire,file_config(DNEWS_EXPIRE)); } /* upto 90% groups * keep 1 normal 2 purge 33 maxitems 100 minitems 0 */ void expire_upto(char *rec2) { char *s; char bf[500],wild[500]; char rec[1000]; ncpy(rec,rec2,999); if (remember==0 ) { emsg("expire: Must define remember and expire at top of file\n"); return; } strcpy(bf,rec); s = strtok(rec," \t\n"); if (s==NULL) return; s = strtok(NULL," \t\n"); if (s==NULL) return; if (pused=group_n()) { g = 0; nntp_setsleep(3); inpurge = FALSE; s_nhistdel = 0; s_nhist = 0; suck_expire_end(); /* Set suck loop to idle */ return; } s_wild(ls,sys_gdir(g),"*.idx"); /* Returns list without paths */ for (i=0; i