/* * Copyright (c) 1987,1988 Massachusetts Institute of Technology. * * Note that there is absolutely NO WARRANTY on this software. * See the file COPYRIGHT.NOTICE for details and restrictions. * * Garbage collector. Not particularly clever, not ephemeral. * I suppose lookup() could be haired up to do ephemeral if * it becomes an issue, which I doubt. */ #include "domsym.h" #define punt(arg) return(bugchk arg, 0) int gc(zones,cache,ncache) struct btnode **zones, **cache, **ncache; { struct btnode *old, *new; int gc_zones(), gc_cache(), gc_ncache(); char *vector[MAX_DOMAIN_TAG_COUNT+1]; int now = zulu(); old = *zones; new = NULL; if(!gctree(old,&new,gc_zones,vector+MAX_DOMAIN_TAG_COUNT+1,0,now)) bughlt("gc","gc of zones failed"); *zones = new; kil_btnode(old,NULL); old = *cache; new = NULL; if(!gctree(old,&new,gc_cache,vector+MAX_DOMAIN_TAG_COUNT+1,0,now)) bughlt("gc","gc of cache failed"); *cache = new; kil_btnode(old,NULL); old = *ncache; new = NULL; if(!gctree(old,&new,gc_ncache,vector+MAX_DOMAIN_TAG_COUNT+1,0,now)) bughlt("gc","gc of ncache failed"); *ncache = new; kil_btnode(old,NULL); return(1); } static int gctree(old_tree,new_tree,func,vector,ntags,now) struct btnode *old_tree, **new_tree; int (*func)(), ntags, now; char **vector; { if(old_tree == NULL) return(1); if(new_tree == NULL || func == NULL || vector == NULL) punt(("gctree","new_tree=%o, func=%o, vector=%o", new_tree, func, vector)); if(DBGFLG(DBG_GC)) { char *name = namimp(vector,ntags), rrtext[STRSIZ]; if(namtoa(rrtext,name) == NULL) rrtext[0] = '\0'; buginf("gctree","old_tree=%o, *new_tree=%o, ntags=%d, name=\"%s\"", old_tree,*new_tree,ntags,rrtext); if(name != NULL) kil(name); } if(!gcnode(old_tree,new_tree,func,--vector,++ntags,now)) punt(("gctree","gcnode() failed")); return(1); } static int gcnode(old_node,new_tree,func,vector,ntags,now) struct btnode *old_node, **new_tree; char **vector; int ntags, now, (*func)(); { if(old_node == NULL) return(1); if(new_tree == NULL || vector == NULL || func == NULL) punt(("gcnode","new_tree=%o, vector=%o, func=%o", new_tree, vector, func)); if((*vector = old_node->data.name) == NULL) punt(("gcnode","null name")); if(DBGFLG(DBG_GC)) { char *name = namimp(vector,ntags), rrtext[STRSIZ]; buginf("gcnode","old_node=%o, old_node->tpoint=%o, old_node->left=%o, old_node->right=%o",old_node, old_node->data.link.tpoint, old_node->left, old_node->right); buginf("gcnode","new_tree=%o, *new_tree=%o, ntags=%d, name=\"%s\"", new_tree, *new_tree, ntags, namtoa(rrtext,name)); if(name != NULL) kil(name); } if(!(*func)(old_node,new_tree,vector,ntags,now)) punt(("gcnode","func failed")); if(!gctree(old_node->data.link.tpoint,new_tree,func,vector,ntags,now)) punt(("gcnode","nested gctree() failed")); if(!gcnode(old_node->left,new_tree,func,vector,ntags,now)) punt(("gcnode","nested gcnode(left) failed")); if(!gcnode(old_node->right,new_tree,func,vector,ntags,now)) punt(("gcnode","nested gcnode(right) failed")); return(1); } /* Macro to snip an entry out of a list and append it to another list. */ #define FIFO_append(list_tail,node_var,link_tag) { \ node_var = (*list_tail = node_var)->link_tag; \ *(list_tail = &((*list_tail)->link_tag)) = NULL;\ } static int gc_zones(node,tree,vector,ntags,now) struct btnode *node, **tree; char **vector; int ntags, now; { struct zone *z; struct zone *keep_head = NULL, **keep_tail = &keep_head; struct zone *kill_head = NULL, **kill_tail = &kill_head; if(node == NULL) return(1); if(tree == NULL || vector == NULL) punt(("gc_zones","tree=%o, vector=%o",tree,vector)); z = node->data.data.zoa; while(z != NULL) { if(DBGFLG(DBG_GC)) buginf("gc_zones", "z=%o, gotten=%d, soa_expire=%d, gotten+soa_expire=%d, now=%d", z, z->gotten, z->base.data.rrs->rdata[SOA_EXPIRE].word, z->gotten + z->base.data.rrs->rdata[SOA_EXPIRE].word, now); if( z->gotten == 0 /* zero means never GC */ || z->gotten + z->base.data.rrs->rdata[SOA_EXPIRE].word > now) { if(DBGFLG(DBG_GC)) buginf("gc_zones","keeping z=%o",z); FIFO_append(keep_tail,z,next) /* ; */ } else { if(DBGFLG(DBG_GC)) buginf("gc_zones","killing z=%o",z); FIFO_append(kill_tail,z,next) /* ; */ } } if(keep_head != NULL) { char *name = namimp(vector,ntags); if(!insert(tree,name,keep_head,0,0)) punt(("gc_zones","failed to re-insert zone")); kil(name); } kil_zone(kill_head); node->data.data.zoa = NULL; return(1); } static int gc_cache(node,tree,vector,ntags,now) struct btnode *node, **tree; char **vector; int ntags, now; { struct rr *r; struct rr *keep_head = NULL, **keep_tail = &keep_head; struct rr *kill_head = NULL, **kill_tail = &kill_head; if(node == NULL) return(1); if(tree == NULL || vector == NULL) punt(("gc_cache","tree=%o, vector=%o",tree,vector)); r = node->data.data.rrs; while(r != NULL) if(r->ttl > now) { if(DBGFLG(DBG_GC)) buginf("gc_cache","keeping r=%o",r); FIFO_append(keep_tail,r,chain) /* ; */ } else { if(DBGFLG(DBG_GC)) buginf("gc_cache","killing r=%o",r); FIFO_append(kill_tail,r,chain) /* ; */ } if(keep_head != NULL) { char *name = namimp(vector,ntags); if(!insert(tree,name,keep_head,0,1)) punt(("gc_cache","failed to re-insert RRs")); kil(name); } kil_rr(kill_head); node->data.data.rrs = NULL; return(1); } static int gc_ncache(node,tree,vector,ntags,now) struct btnode *node, **tree; char **vector; int ntags, now; { struct rr *r, *t; struct rr *keep_head = NULL, **keep_tail = &keep_head; struct rr *kill_head = NULL, **kill_tail = &kill_head; if(node == NULL) return(1); if(tree == NULL || vector == NULL) punt(("gc_ncache","tree=%o, vector=%o",tree,vector)); r = node->data.data.rrs; while(r != NULL) if(r->ttl > now) { if(DBGFLG(DBG_GC)) buginf("gc_ncache","keeping r=%o",r); FIFO_append(keep_tail,r,chain) /* ; */ } else { if(DBGFLG(DBG_GC)) buginf("gc_ncache","killing r=%o",r); FIFO_append(kill_tail,r,chain) /* ; */ } if(keep_head != NULL) { char *name = namimp(vector,ntags); if(!insert(tree,name,keep_head,0,0)) punt(("gc_ncache","failed to re-insert RRs")); kil(name); } r = kill_head; /* not exactly RRs, kill by hand */ while(r != NULL) { r = (t = r)->chain; kil_(t->rdata); kil_(t); } node->data.data.rrs = NULL; return(1); }