From: Art Cancro Date: Sat, 21 Nov 1998 23:25:00 +0000 (+0000) Subject: serv_expire.c: finished the code to purge stale visits X-Git-Tag: v7.86~8130 X-Git-Url: https://code.citadel.org/?a=commitdiff_plain;h=1a75078cc58fb932b6accf0699ba1366631e0b6b;p=citadel.git serv_expire.c: finished the code to purge stale visits --- diff --git a/citadel/ChangeLog b/citadel/ChangeLog index ac0c792a3..e299d218f 100644 --- a/citadel/ChangeLog +++ b/citadel/ChangeLog @@ -3,6 +3,7 @@ Sat Nov 21 16:53:30 EST 1998 Art Cancro on or off according to a per-user flag stored on the server. Added server-side support for this too, of course. * import.c: removed + * serv_expire.c: finished the code to purge stale visits Fri Nov 20 20:29:07 EST 1998 Art Cancro * setup.c: removed all prompts that can be configured from within the diff --git a/citadel/TODO b/citadel/TODO index 9ec7d2d55..3e83a1f5a 100644 --- a/citadel/TODO +++ b/citadel/TODO @@ -1,6 +1,5 @@ Citadel/UX v5.50 showstoppers list ---------------------------------- -* Write expire function for visits * Fix room expire time entry in client * Figure out a way to auto-launch expire functions (and other functions) * Fix the way netproc handles incoming file transfers. (marked) diff --git a/citadel/room_ops.h b/citadel/room_ops.h index 5cedacd83..775f64f10 100644 --- a/citadel/room_ops.h +++ b/citadel/room_ops.h @@ -48,3 +48,4 @@ void ForEachRoom(void (*CallBack)(struct quickroom *EachRoom)); void assoc_file_name(char *buf, struct quickroom *qrbuf, char *prefix); void delete_room(struct quickroom *qrbuf); void list_roomname(struct quickroom *qrbuf); +int is_noneditable(struct quickroom *qrbuf); diff --git a/citadel/serv_expire.c b/citadel/serv_expire.c index 1083e0e25..a2694a953 100644 --- a/citadel/serv_expire.c +++ b/citadel/serv_expire.c @@ -6,6 +6,23 @@ */ /* $Id$ */ + +/* + * A brief technical discussion: + * + * Several of the purge operations found in this module operate in two + * stages: the first stage generates a linked list of objects to be deleted, + * then the second stage deletes all listed objects from the database. + * + * At first glance this may seem cumbersome and unnecessary. The reason it is + * implemented in this way is because GDBM (and perhaps some other backends we + * may hook into in the future) explicitly do _not_ support the deletion of + * records from a file while the file is being traversed. The delete operation + * will succeed, but the traversal is not guaranteed to visit every object if + * this is done. Therefore we utilize the two-stage purge. + */ + + #include #include #include @@ -48,8 +65,29 @@ struct PurgeList { char name[ROOMNAMELEN]; /* use the larger of username or roomname */ }; +struct VPurgeList { + struct VPurgeList *next; + long vp_roomnum; + long vp_roomgen; + long vp_usernum; + }; + +struct ValidRoom { + struct ValidRoom *next; + long vr_roomnum; + long vr_roomgen; + }; + +struct ValidUser { + struct ValidUser *next; + long vu_usernum; + }; + struct PurgeList *UserPurgeList = NULL; struct PurgeList *RoomPurgeList = NULL; +struct ValidRoom *ValidRoomList = NULL; +struct ValidUser *ValidUserList = NULL; +int messages_purged; extern struct CitContext *ContextList; @@ -74,6 +112,7 @@ void DoPurgeMessages(struct quickroom *qrbuf) { char msgid[64]; int a; + messages_purged = 0; time(&now); GetExpirePolicy(&epbuf, qrbuf); @@ -104,6 +143,7 @@ void DoPurgeMessages(struct quickroom *qrbuf) { memcpy(&CC->msglist[0], &CC->msglist[1], (sizeof(long)*(CC->num_msgs - 1))); CC->num_msgs = CC->num_msgs - 1; + ++messages_purged; } } @@ -260,16 +300,57 @@ int PurgeUsers(void) { return(num_users_purged); } +void AddValidUser(struct usersupp *usbuf) { + struct ValidUser *vuptr; + + vuptr = (struct ValidUser *)malloc(sizeof(struct ValidUser)); + vuptr->next = ValidUserList; + vuptr->vu_usernum = usbuf->usernum; + ValidUserList = vuptr; + } + +void AddValidRoom(struct quickroom *qrbuf) { + struct ValidRoom *vrptr; + + vrptr = (struct ValidRoom *)malloc(sizeof(struct ValidRoom)); + vrptr->next = ValidRoomList; + vrptr->vr_roomnum = qrbuf->QRnumber; + vrptr->vr_roomgen = qrbuf->QRgen; + ValidRoomList = vrptr; + } +/* + * Purge visits + * + * This is a really cumbersome "garbage collection" function. We have to + * delete visits which refer to rooms and/or users which no longer exist. In + * order to prevent endless traversals of the room and user files, we first + * build linked lists of rooms and users which _do_ exist on the system, then + * traverse the visit file, checking each record against those two lists and + * purging the ones that do not have a match on _both_ lists. (Remember, if + * either the room or user being referred to is no longer on the system, the + * record is completely useless.) + */ int PurgeVisits(void) { struct cdbdata *cdbvisit; struct visit vbuf; + struct VPurgeList *VisitPurgeList = NULL; + struct VPurgeList *vptr; int purged = 0; + char IndexBuf[32]; + int IndexLen; + struct ValidRoom *vrptr; + struct ValidUser *vuptr; + int RoomIsValid, UserIsValid; - struct quickroom qr; - struct usersupp us; + /* First, load up a table full of valid room/gen combinations */ + ForEachRoom(AddValidRoom); + /* Then load up a table full of valid user numbers */ + ForEachUser(AddValidUser); + + /* Now traverse through the visits, purging irrelevant records... */ cdb_rewind(CDB_VISIT); while(cdbvisit = cdb_next_item(CDB_VISIT), cdbvisit != NULL) { memset(&vbuf, 0, sizeof(struct visit)); @@ -278,8 +359,62 @@ int PurgeVisits(void) { sizeof(struct visit) : cdbvisit->len) ); cdb_free(cdbvisit); + RoomIsValid = 0; + UserIsValid = 0; + + /* Check to see if the room exists */ + for (vrptr=ValidRoomList; vrptr!=NULL; vrptr=vrptr->next) { + if ( (vrptr->vr_roomnum==vbuf.v_roomnum) + && (vrptr->vr_roomgen==vbuf.v_roomgen)) + RoomIsValid = 1; + } + + /* Check to see if the user exists */ + for (vuptr=ValidUserList; vuptr!=NULL; vuptr=vuptr->next) { + if (vuptr->vu_usernum == vbuf.v_usernum) + UserIsValid = 1; + } + + /* Put the record on the purge list if it's dead */ + if ((RoomIsValid==0) || (UserIsValid==0)) { + vptr = (struct VPurgeList *) + malloc(sizeof(struct VPurgeList)); + vptr->next = VisitPurgeList; + vptr->vp_roomnum = vbuf.v_roomnum; + vptr->vp_roomgen = vbuf.v_roomgen; + vptr->vp_usernum = vbuf.v_usernum; + VisitPurgeList = vptr; + } + + } + + /* Free the valid room/gen combination list */ + while (ValidRoomList != NULL) { + vrptr = ValidRoomList->next; + free(ValidRoomList); + ValidRoomList = vrptr; + } + + /* Free the valid user list */ + while (ValidUserList != NULL) { + vuptr = ValidUserList->next; + free(ValidUserList); + ValidUserList = vuptr; + } + + /* Now delete every visit on the purged list */ + while (VisitPurgeList != NULL) { + IndexLen = GenerateRelationshipIndex(IndexBuf, + VisitPurgeList->vp_roomnum, + VisitPurgeList->vp_roomgen, + VisitPurgeList->vp_usernum); + cdb_delete(CDB_VISIT, IndexBuf, IndexLen); + vptr = VisitPurgeList->next; + free(VisitPurgeList); + VisitPurgeList = vptr; ++purged; } + return(purged); } @@ -308,17 +443,17 @@ void cmd_expi(char *argbuf) { } else if (!strcasecmp(cmd, "messages")) { PurgeMessages(); - cprintf("%d Finished purging messages.\n", OK); + cprintf("%d Expired %d messages.\n", OK, messages_purged); return; } else if (!strcasecmp(cmd, "rooms")) { retval = PurgeRooms(); - cprintf("%d Purged %d rooms.\n", OK, retval); + cprintf("%d Expired %d rooms.\n", OK, retval); return; } else if (!strcasecmp(cmd, "visits")) { retval = PurgeVisits(); - cprintf("%d There are %d visits...\n", OK, retval); + cprintf("%d Purged %d visits.\n", OK, retval); } else if (!strcasecmp(cmd, "defrag")) { defrag_databases(); diff --git a/citadel/user_ops.h b/citadel/user_ops.h index 996e84c40..c765ab52e 100644 --- a/citadel/user_ops.h +++ b/citadel/user_ops.h @@ -42,3 +42,7 @@ void CtdlSetRelationship(struct visit *newvisit, struct usersupp *rel_user, struct quickroom *rel_room); void MailboxName(char *buf, struct usersupp *who, char *prefix); +int GenerateRelationshipIndex( char *IndexBuf, + long RoomID, + long RoomGen, + long UserID);