/* * precommit.c Copyright 1999 Christopher M Sedore. All Rights Reserved. * Please see the "COPYING" file for license details. * * Implements a simple precommit cache to prevent us from telling * more than one peer to send us an article. */ #include "main.h" struct precentry { u_quad_t hash; time_t etime; struct artent ae; int artAttached; struct article *art; TAILQ_ENTRY(precentry) next; TAILQ_ENTRY(precentry) all; }; TAILQ_HEAD(freeheadn,precentry) freehead; TAILQ_HEAD(allheadn,precentry) pceinuse; TAILQ_HEAD(waitheadn,precentry) waithead; struct pctable { TAILQ_HEAD(hprecentry,precentry) head; }; #define PRECOMMIT_SIZE 11111 #define PRECOMMIT_LIFE 300 #define MAX_FREEPCE 300 struct pctable precommit[PRECOMMIT_SIZE]; static int freepce=0; int pceactive=0; extern time_t curtime; inline struct precentry * FindEntry(u_quad_t hash) { int x; struct precentry *pce,*pcn; x=hash%PRECOMMIT_SIZE; for (pce=TAILQ_FIRST(&precommit[x].head);pce;pce=pcn) { pcn=TAILQ_NEXT(pce,next); if (pce->hash==hash) { return pce; } } return NULL; } int AddEntry(u_quad_t hash,struct pctable *pct) { struct precentry *pce; if (pce=TAILQ_FIRST(&freehead)) { TAILQ_REMOVE(&freehead,pce,next); freepce--; } else { pce=malloc(sizeof(struct precentry)); } pceactive++; pce->hash=hash; pce->art=NULL; pce->artAttached=0; time(&pce->etime); TAILQ_INSERT_TAIL(&pct->head,pce,next); TAILQ_INSERT_TAIL(&pceinuse,pce,all); } int GetPrecommitArt(u_quad_t hash, struct article **art) { struct precentry *pce; pce=FindEntry(hash); if (pce) if (pce->art) { pce->art->refcount++; *art=pce->art; return 1; } return 0; } int ReleasePrecommitArt(struct article *art) { assert(art->refcount>0); art->refcount--; if (art->refcount==0) { struct precentry *pce,*pcn; for (pce=TAILQ_FIRST(&waithead);pce;pce=pcn) { pcn=TAILQ_NEXT(pce,next); if (pce->art==art) { break; } } if (!pce) errx("article not found in precommit when ref=0"); if (freepceart); /* XXX need FreeArtStruct */ free(art->bufp); free(art); pceactive--; } } int AttachPrecommitArt(u_quad_t hash, struct article *art) { struct precentry *pce; pce=FindEntry(hash); if (!pce) return 0; pce->art=art; } int GetPrecommitArtEnt(u_quad_t hash,struct artent *ae) { struct precentry *pce; pce=FindEntry(hash); if (!pce) return 0; if (pce->artAttached) { memcpy(ae,&pce->ae,sizeof(struct artent)); return 1; } } int AddPrecommit(u_quad_t hash) { struct precentry *pce; pce=FindEntry(hash); if (!pce) { AddEntry(hash,&precommit[hash%PRECOMMIT_SIZE]); return 1; } return 0; } int UpdatePrecommit(u_quad_t hash, struct artent *ae) { struct precentry *pce; pce=FindEntry(hash); if (!pce) { AddEntry(hash,&precommit[hash%PRECOMMIT_SIZE]); pce=FindEntry(hash); } memcpy(&pce->ae,ae,sizeof(struct artent)); pce->artAttached=1; TAILQ_REMOVE(&pceinuse,pce,all); TAILQ_INSERT_TAIL(&pceinuse,pce,all); time(&pce->etime); return 1; } void FreePCE(struct precentry *pce) { int x; pce->artAttached=0; x=pce->hash%PRECOMMIT_SIZE; TAILQ_REMOVE(&precommit[x].head,pce,next); TAILQ_REMOVE(&pceinuse,pce,all); if (pce->art) { if (pce->art->refcount) { TAILQ_INSERT_TAIL(&waithead,pce,next); } FreeMatchData(pce->art); free(pce->art->bufp); free(pce->art); } if (freepceetime+PRECOMMIT_LIFE