|
|
/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
nmsscv.c
Abstract: This module contains functions that implement the functionality associated with scavenging
Functions: NmsScvInit, ScvThdInitFn, DoScavenging ReconfigScv
Portability:
This module is portable
Author:
Pradeep Bahl (PradeepB) Apr-1993
Revision History:
Modification date Person Description of modification ----------------- ------- ---------------------------- --*/
/*
* Includes */ #include <time.h>
#include "wins.h"
#include "winsevt.h"
#include "nms.h"
#include "nmsnmh.h"
#include "winsmsc.h"
#include "winsdbg.h"
#include "winsthd.h"
#include "winscnf.h"
#include "nmsdb.h"
#include "winsque.h"
#include "nmsscv.h"
#include "rpl.h"
#include "rplpull.h"
#include "rplmsgf.h"
#include "comm.h"
#include "winsintf.h"
#include "winstmm.h"
#ifdef WINSDBG
#define SCV_EVT_NM TEXT("ScvEvtNm")
#else
#define SCV_EVT_NM NULL
#endif
//
// The no. of retries and the time interval (in secs) between each retry
// when trying to establish comm. with a WINS for the purpose of verifying
// old active replicas in the local db
//
#define VERIFY_NO_OF_RETRIES 0 //0 retries
#define VERIFY_RETRY_TIME_INTERVAL 30 //30 secs
//
// We get rid of extraneous log files every 3 hours.
//
FUTURES("Use symbols for times - defined in winscnf.h") #define ONE_HOUR 3600
#define THREE_HOURS 10800
#define TWENTY_FOUR_HOURS (3600 * 24)
#define THREE_DAYS (TWENTY_FOUR_HOURS * 3)
#define PERIOD_OF_LOG_DEL THREE_HOURS
#define PERIOD_OF_BACKUP TWENTY_FOUR_HOURS
#define LOG_SCV_MUL_OF_REF_INTVL 6
/*
* Local Macro Declarations */ //
// macro to set the state of a record in an in-memory data structure to
// that specified as an arg. if it has timed out. We check whether
// CurrTime is greater than pRec Timestamp before doing the other if test
// because these numbers otherwise the subtraction will produce a positive
// number even if current time is older than the timestamp (say the date
// on the pc was changed)
//
#define SET_STATE_IF_REQD_M(pRec, CurrentTime, TimeInterval, State, Cntr) \
{ \ pRec->fScv = FALSE; \ if (CurrentTime >= (time_t)(pRec)->TimeStamp) \ { \ NMSDB_SET_STATE_M( \ (pRec)->Flag, \ (State) \ ); \ (pRec)->NewTimeStamp = (pRec)->TimeStamp + \ TimeInterval; \ (pRec)->fScv = TRUE; \ NoOfRecsScv++; \ (Cntr)++; \ } \ }
#define DO_SCV_EVT_NM TEXT("WinsDoScvEvt")
/*
* Local Typedef Declarations */
/*
* Global Variable Definitions */
HANDLE NmsScvDoScvEvtHdl;//event signaled to initiate scavenging
//
// The min. version number to start scavenging from (for local records)
//
VERS_NO_T NmsScvMinScvVersNo; volatile BOOL fNmsScvThdOutOfReck; DWORD sMcastIntvl;
/*
* Local Variable Definitions */ FUTURES("Put all these in a structure and allocate it. Initialize sBootTime") FUTURES("in nms.c")
STATIC time_t sBootTime; //Boot Time
STATIC time_t sLastRefTime; //Last time we looked for active
// entries
STATIC time_t sLastVerifyTime; //Last time we looked for replicais
STATIC time_t sLastFullVerifyTime; //Last time we did full validation
STATIC time_t sLastAdminScvTime; //Last time admin. did scavenging
STATIC time_t sLastTombTime; //Last time we looked for replica
// tombstones
STATIC BOOL sfAdminForcedScv; //set to TRUE if the administrator
//forces scavenging
STATIC time_t sLastDbNullBackupTime;//Last time we deleted extraneous
//log files
STATIC time_t sLastDbBackupTime; //Last time we last did full backup
#if MCAST > 0
STATIC time_t sLastMcastTime; //Last time we last did full backup
#endif
/*
* Local Function Prototype Declarations */ STATIC STATUS DoScavenging( PNMSSCV_PARAM_T pScvParam, BOOL fSignaled, LPBOOL pfResetTimer, LPBOOL pfSpTimeOver ); STATIC DWORD ScvThdInitFn( IN LPVOID pThdParam );
STATIC VOID ReconfigScv( PNMSSCV_PARAM_T pScvParam );
STATIC VOID UpdDb( IN PNMSSCV_PARAM_T pScvParam, IN PRPL_REC_ENTRY_T pStartBuff, IN DWORD NoOfRecs, IN DWORD NoOfRecsToUpd );
STATIC STATUS VerifyDbData( PNMSSCV_PARAM_T pScvParam, time_t CurrentTime, DWORD Age, BOOL fForce, BOOL fPeriodicCC );
STATIC STATUS PickWinsToUse( IN PCOMM_ADD_T pVerifyWinsAdd, IN PCOMM_ADD_T pOwnerWinsAdd, IN BOOL fUseRplPnr, OUT LPBOOL pfNonOwnerPnr, OUT LPBOOL pRplType );
STATIC STATUS EstablishCommForVerify( PCOMM_ADD_T pWinsAdd, PCOMM_HDL_T pDlgHdl );
STATIC VOID PullAndUpdateDb( PCOMM_HDL_T pDlgHdl, PCOMM_ADD_T pWinsAdd, PRPL_REC_ENTRY_T pRspBuff, DWORD WinsIndex, VERS_NO_T MinVersNo, VERS_NO_T MaxVersNo, DWORD RplType, DWORD NoOfLocalRecs, time_t CurrentTime, PNMSSCV_PARAM_T pScvParam, BOOL fNonOwnerPnr, LPDWORD pTotNoOfPulledRecs );
STATIC __inline VOID FreeDbMemory( LPVOID pStartBuff, DWORD NoOfLocalDbRecs, PWINSTHD_TLS_T pTls );
STATIC VOID ChkConfNUpd( #if SUPPORT612WINS > 0
IN PCOMM_HDL_T pDlgHdl, #endif
IN PCOMM_ADD_T pOwnerWinsAdd, IN DWORD RplType, IN DWORD OwnerId, IN PRPL_REC_ENTRY_T *ppLocalDbRecs, IN LPBYTE pPulledRecs, IN DWORD *pNoOfLocalDbRecs, IN time_t CurrentTime, IN DWORD VerifyTimeIntvl, IN BOOL fNonOwnerPnr, OUT LPDWORD pNoOfPulledRecs, OUT PVERS_NO_T pMaxVersNo );
STATIC VOID CompareWithLocalRecs( IN VERS_NO_T VersNo, IN LPBYTE pName, IN NMSDB_ENTRY_STATE_E RecState_e, IN OUT PRPL_REC_ENTRY_T *ppLocalDbRecs, IN OUT DWORD *pNoOfLocalRecs, IN time_t CurrentTime, IN BOOL fNonOwnerPnr, IN OUT DWORD *pNoOfRecsDel, OUT PNMSSCV_REC_ACTION_E pRecAction_e ); STATIC VOID DoBackup( PNMSSCV_PARAM_T pScvParam, LPBOOL pfThdPrNormal );
#if MCAST > 0
VOID DoMcastSend( DWORD_PTR CurrentTime, DWORD Code, DWORD fNow ); #endif
//
// function definitions start here
//
VOID NmsScvInit( VOID )
/*++
Routine Description: This function is called to initialize the scavenger thread
Arguments: None
Externals Used: None
Return Value: None
Error Handling:
Called by:
Side Effects:
Comments: None --*/
{
//
// Create the event handle signaled when scavenging has to be
// initiated. This event is signaled by an RPC thread
// to start scavenging
//
WinsMscCreateEvt( DO_SCV_EVT_NM, FALSE, //auto-reset
&NmsScvDoScvEvtHdl );
//
// initialize sLastTombTime (used for determining if we need to look for
// tombstones of replicas) and sLastVerifyTime to current time.
// Don't forget RefreshTime
//
(void)time(&sBootTime); sLastVerifyTime = //fall through
sLastTombTime = //fall through
sLastFullVerifyTime = //fall through
sLastAdminScvTime = //fall through
sLastRefTime = sBootTime;
//
// Initialize the queue used by the scavenger thread
//
WinsQueInit(TEXT("NmsScvEvt"), &QueWinsScvQueHd);
//
// Create the Scavenger thread
//
WinsThdPool.ScvThds[0].ThdHdl = WinsMscCreateThd( ScvThdInitFn, NULL, &WinsThdPool.ScvThds[0].ThdId );
//
// Init WinsThdPool properly
//
WinsThdPool.ScvThds[0].fTaken = TRUE; WinsThdPool.ThdCount++;
return; }
VOID GetIntervalToDefSpTime( LPDWORD pTimeInt )
/*++
Routine Description: This function finds the time interval in seconds upto the Default Specific time.
Arguments: OUT pTimeInt - Time Interval in seconds
Externals Used: None
Return Value:
Success status codes -- Error status codes --
Error Handling:
Called by:
Side Effects:
Comments: None --*/
{
SYSTEMTIME CurrTime; GetSystemTime(&CurrTime);
//
// If default time hour is greater then current hour, add 3600
// for the number of hours it is ahead. Then subtract the the
// number of minutes and seconds in the current time
//
if (WINSCNF_DEF_CC_SP_HR > CurrTime.wHour) { *pTimeInt = (WINSCNF_DEF_CC_SP_HR - CurrTime.wHour) * 3600; *pTimeInt -= ((CurrTime.wMinute * 60) + (CurrTime.wSecond)); } else //default hour is same or less than current hour
{ *pTimeInt = (CurrTime.wHour - WINSCNF_DEF_CC_SP_HR) * 3600; *pTimeInt += (CurrTime.wMinute * 60) + (CurrTime.wSecond); } return;
}
DWORD ScvThdInitFn( IN LPVOID pThdParam )
/*++
Routine Description: This function is the initialization function for the scavenger thread
Arguments: pThdParam - Not used
Externals Used: None
Return Value:
Success status codes -- should never return Error status codes -- WINS_FAILURE
Error Handling:
Called by:
Side Effects:
Comments: None --*/
{
BOOL fSignaled = FALSE; HANDLE ThdEvtArr[3]; DWORD IndexOfHdlSignaled; NMSSCV_PARAM_T ScvParam; DWORD SleepTime; time_t CurrentTime; BOOL fThdPrNormal; DWORD TimeInt; QUE_SCV_REQ_WRK_ITM_T WrkItm; BOOL fResetTimer = TRUE; time_t AbsTime; time_t LastCC; BOOL fTimerRunning = FALSE; BOOL fSpTimeOver = FALSE;
UNREFERENCED_PARAMETER(pThdParam);
ThdEvtArr[0] = NmsTermEvt; ThdEvtArr[1] = WinsCnf.CnfChgEvtHdl; ThdEvtArr[2] = QueWinsScvQueHd.EvtHdl; try { /*
Initialize the thread with the database */ NmsDbThdInit(WINS_E_NMSSCV); DBGMYNAME("Scavenger Thread");
//
// get the scavenging parameters from the configuration structure.
// Note; There is no need for any synchronization here since
// we are executing in the main thread (process is initalizing
// at invocation).
//
ScvParam.ScvChunk = WinsCnf.ScvChunk; ScvParam.RefreshInterval = WinsCnf.RefreshInterval; ScvParam.TombstoneInterval = WinsCnf.TombstoneInterval; ScvParam.TombstoneTimeout = WinsCnf.TombstoneTimeout; ScvParam.VerifyInterval = WinsCnf.VerifyInterval; ScvParam.PrLvl = WinsCnf.ScvThdPriorityLvl;
//
// Load up the CC parameters
//
ScvParam.CC.TimeInt = WinsCnf.CC.TimeInt; ScvParam.CC.fSpTime = WinsCnf.CC.fSpTime; ScvParam.CC.SpTimeInt = WinsCnf.CC.SpTimeInt; ScvParam.CC.MaxRecsAAT = WinsCnf.CC.MaxRecsAAT; ScvParam.CC.fUseRplPnrs = WinsCnf.CC.fUseRplPnrs;
sMcastIntvl = WinsCnf.McastIntvl;
//
// if backup path is not NULL, copy it into ScvParam structure
//
if (WinsCnf.pBackupDirPath != NULL) { (VOID)strcpy(ScvParam.BackupDirPath, WinsCnf.pBackupDirPath); } else { ScvParam.BackupDirPath[0] = EOS; } //
// Use a stack variable WrkItm. Schedule it with the timer thread
// if required (will happen only if the CC key is present).
//
FUTURES("Set two work items - for two timer requests. One to fire off at a") FUTURES("specific time. The other one for the time interval") WrkItm.Opcode_e = WINSINTF_E_VERIFY_SCV; //verify replicas
WrkItm.Age = 0; //no matter how recent
WrkItm.fForce = TRUE; //force verification even if
//we did it recently
LOOP: try {
while (TRUE) { sfAdminForcedScv = FALSE;
SleepTime = min(min(sMcastIntvl, ScvParam.RefreshInterval), PERIOD_OF_LOG_DEL); if (fResetTimer) { if (fTimerRunning) { //
// Delete the old timer request. This should
// deallocate it
//
DBGPRINT0(SCV, "ScvThdInit: Deleting Timer requests\n"); WinsTmmDeleteReqs(WINS_E_NMSSCV); fTimerRunning = FALSE; } //
// If the time interval for CC is not MAXULONG, it means
// user wants CC to be done. TimeInt will be MAXULONG if
// there is no Wins\Paramaters\CC key in the registry
//
if (ScvParam.CC.TimeInt != MAXULONG) { //
// if no specific time was indicated, use default (2 am).
//
if (!fSpTimeOver) { if (!ScvParam.CC.fSpTime) { //
// Get the current hour. Schedule a wakeup at exact
// 2 am.
//
GetIntervalToDefSpTime(&TimeInt); } else { TimeInt = ScvParam.CC.SpTimeInt; } } else { TimeInt = ScvParam.CC.TimeInt; }
DBGPRINT1(SCV, "ScvThdInit: TimeInt is (%d)\n", TimeInt);
// Insert a timer request. Let the Timer thread create
// a work item for it.
//
(VOID)time(&AbsTime); if( !fSpTimeOver ) { AbsTime += (time_t)TimeInt; LastCC = AbsTime; } else { do { LastCC += (time_t)TimeInt; } while( LastCC <= (AbsTime + WINSCNF_MIN_VALID_INTER_CC_INTVL)); AbsTime = LastCC; } WinsTmmInsertEntry( NULL, WINS_E_NMSSCV, QUE_E_CMD_SET_TIMER, FALSE, //not used presently
AbsTime, TimeInt, &QueWinsScvQueHd, &WrkItm, 0, NULL ); fTimerRunning = TRUE; fResetTimer = FALSE; } }
//
// Do a timed wait until signaled for termination
//
// Multiply the sleep time by 1000 since WinsMscWaitTimed
// function expects the time interval in msecs.
//
#ifdef WINSDBG
{ time_t ltime; (VOID)time(<ime); DBGPRINT2(SCV, "ScvThdInitFn: Sleeping for (%d) secs. Last scavenging took = (%d secs)\n", SleepTime, ltime - CurrentTime); } #endif
WinsMscWaitTimedUntilSignaled( ThdEvtArr, sizeof(ThdEvtArr)/sizeof(HANDLE), &IndexOfHdlSignaled, SleepTime * 1000, &fSignaled );
//
// We can be signaled for termination, configuration change,
// by the admin to do general or specific scavenging or by
// the timer thread
//
if (fSignaled) { if (IndexOfHdlSignaled == 0) { WinsMscTermThd(WINS_SUCCESS, WINS_DB_SESSION_EXISTS); } else { if (IndexOfHdlSignaled == 1) { ReconfigScv(&ScvParam);
//
// Reset the timer
//
fResetTimer = TRUE; continue; }
//
// else, this must be the signal to initiate scavenging
// (by the admin. or the timer thread)
//
sfAdminForcedScv = TRUE; } }
//
// Get the current time and check if we need to do scavenging
//
(void)time(&CurrentTime);
if ( ( (CurrentTime > sLastRefTime) && ((CurrentTime - sLastRefTime) >= (time_t)ScvParam.RefreshInterval)) || sfAdminForcedScv ) {
//
// Do scavenging
//
NmsDbOpenTables(WINS_E_NMSSCV); //DBGPRINT0(ERR, "SCVTHDINITFN: OPENED tables\n");
(VOID)DoScavenging(&ScvParam, fSignaled, &fResetTimer, &fSpTimeOver); NmsDbCloseTables(); //DBGPRINT0(ERR, "SCVTHDINITFN: CLOSED tables\n");
fTimerRunning = !fResetTimer;
} //
// If enough time has expired to warrant a purging of old log
// files, do it (check done in DoBackup). We don't do this
// on an admin. trigger since it may take long.
//
if (!sfAdminForcedScv) { #if MCAST > 0
DoMcastSend(CurrentTime, COMM_MCAST_WINS_UP, FALSE); #endif
fThdPrNormal = TRUE; DoBackup(&ScvParam, &fThdPrNormal); }
} // end of while (TRUE)
} //end of inner try {..}
except(EXCEPTION_EXECUTE_HANDLER) { DBGPRINTEXC("ScvThdInit");
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_SCV_EXC); } goto LOOP; } //end of outer try {..}
except(EXCEPTION_EXECUTE_HANDLER) { DBGPRINTEXC("ScvThdInit"); WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_SCV_EXC);
//
// Let us terminate the thread gracefully
//
WinsMscTermThd(WINS_FAILURE, WINS_DB_SESSION_EXISTS);
}
//
// We should never get here
//
return(WINS_FAILURE); }
STATUS DoScavenging( PNMSSCV_PARAM_T pScvParam, BOOL fSignaled, LPBOOL pfResetTimer, LPBOOL pfSpTimeOver )
/*++
Routine Description: This function is responsible for doing all scavenging
Arguments: None
Externals Used: None
Return Value:
None Error Handling:
Called by: ScvThdInitFn()
Side Effects:
Comments: None --*/
{ PRPL_REC_ENTRY_T pStartBuff; PRPL_REC_ENTRY_T pRec; DWORD BuffLen; DWORD NoOfRecs = 0; time_t CurrentTime; DWORD NoOfRecsScv; //no of records whose state has
//been affected
DWORD TotNoOfRecsScv = 0; //Total no of records
//whose state has
//been affected
VERS_NO_T MyMaxVersNo; DWORD i; //for loop counter
DWORD RecCnt; LARGE_INTEGER n; //for loop counter
LARGE_INTEGER Tmp; DWORD State; //stores state of a record
VERS_NO_T VersNoLimit; DWORD NoOfRecChgToRelSt = 0; DWORD NoOfRecChgToTombSt = 0; DWORD NoOfRecToDel = 0; DWORD MaxNoOfRecsReqd = 0; BOOL fLastEntryDel = FALSE; PWINSTHD_TLS_T pTls; PRPL_REC_ENTRY_T pTmp; BOOL fRecsExistent = FALSE; VERS_NO_T MinScvVersNo; #ifdef WINSDBG
DWORD SectionCount = 0; #endif
PQUE_SCV_REQ_WRK_ITM_T pScvWrkItm; PQUE_SCV_REQ_WRK_ITM_T pClientWrkItm; PQUE_TMM_REQ_WRK_ITM_T pTmmWrkItm; QUE_SCV_OPC_E Opcode_e; DWORD Age; STATUS RetStat; BOOL fForce; BOOL fPeriodicCC = FALSE;
DBGENTER("DoScavenging\n"); *pfResetTimer = FALSE; while (TRUE) {
try { if (fSignaled) { RetStat = QueRemoveScvWrkItm((LPVOID *)&pScvWrkItm); if (RetStat == WINS_NO_REQ) { break; } else { //
// If we got signaled by the timer thread, get the pointer
// to the local WrkItm of ScvThdInitFn()
//
if (pScvWrkItm->CmdTyp_e == QUE_E_CMD_TIMER_EXPIRED) { DBGPRINT0(SCV, "DoScavenging: Timer Thd. triggered scavenging\n"); pClientWrkItm = ((PQUE_TMM_REQ_WRK_ITM_T)(pScvWrkItm))->pClientCtx; fPeriodicCC = TRUE;
if (!*pfResetTimer) { *pfResetTimer = TRUE; }
//
// If *pfSpTimeOver is false, it means that the timer
// thread wokr us up at SpTime specified in registry
// (or at 2am if SpTime) was not specifid in registry.
// Set *pfSpTimeOver to TRUE so that from hereon we
// use TimeInterval specified in the registry as
// the time interval
//
if (!*pfSpTimeOver) { *pfSpTimeOver = TRUE; } } else { pClientWrkItm = pScvWrkItm; }
Opcode_e = pClientWrkItm->Opcode_e; Age = pClientWrkItm->Age; fForce = (BOOL)pClientWrkItm->fForce; if (*pfResetTimer) { WinsTmmDeallocReq((PQUE_TMM_REQ_WRK_ITM_T)pScvWrkItm); } else { //
// Free the admin. initiated rpc work item
//
WinsMscHeapFree(NmsRpcHeapHdl, pScvWrkItm); } } } else { //
// timer expiry of the wait call
//
Opcode_e = WINSINTF_E_SCV_GENERAL; Age = pScvParam->VerifyInterval; fForce = FALSE; // no forceful scavenging
}
if (sfAdminForcedScv && !fPeriodicCC) { WinsIntfSetTime( NULL, WINSINTF_E_ADMIN_TRIG_SCV ); DBGPRINTTIME(SCV, "STARTING AN ADMIN. TRIGGERED SCAVENGING CYCLE ", LastATScvTime); DBGPRINTTIME(DET, "STARTING AN ADMIN. TRIGGERED SCAVENGING CYCLE ", LastATScvTime); } else { WinsIntfSetTime( NULL, WINSINTF_E_PLANNED_SCV); DBGPRINTTIME(SCV, "STARTING A SCAVENGING CYCLE ", LastPScvTime); DBGPRINTTIME(DET, "STARTING A SCAVENGING CYCLE ", LastPScvTime); }
//
// get the current time
//
(void)time(&CurrentTime);
if (Opcode_e == WINSINTF_E_SCV_GENERAL) {
WINSEVT_LOG_INFO_D_M(WINS_SUCCESS, WINS_EVT_SCVENGING_STARTED); //
// record current time in sLastRefTime
//
sLastRefTime = CurrentTime; EnterCriticalSection(&NmsNmhNamRegCrtSec); //
// Store the max. version number in a local since the max. version
// number is incremented by several threads
//
NMSNMH_DEC_VERS_NO_M( NmsNmhMyMaxVersNo, MyMaxVersNo ); //
// synchronize with RplPullPullSpecifiedRange
//
MinScvVersNo = NmsScvMinScvVersNo;
LeaveCriticalSection(&NmsNmhNamRegCrtSec);
//
// Set thread priority to the level indicated in the WinsCnf
// structure
//
WinsMscSetThreadPriority( WinsThdPool.ScvThds[0].ThdHdl, pScvParam->PrLvl );
// log a detailed event showing the range of version_numbers that
// are being scavenged. This helps finding out why some particuler
// record is stalled in the database. (If it doesn't fall in this
// range it means the scavenger is not even looking at it).
WinsEvtLogDetEvt( TRUE, // Informational event
WINS_EVT_SCV_RANGE, // event ID
NULL, // NULL filename
__LINE__, // line number where this event is logged
"dddd", // data section format
MinScvVersNo.LowPart, MinScvVersNo.HighPart, // data: 2nd, 3rd words
MyMaxVersNo.LowPart, MyMaxVersNo.HighPart); // data: 4th, 5th words
Tmp.QuadPart = pScvParam->ScvChunk; for ( n.QuadPart = MinScvVersNo.QuadPart; // min. version no. to
//start from
LiLeq(n, MyMaxVersNo); // until we reach the max. vers. no
// no third expression here
) { BOOL fGotSome = FALSE;
//
// The max. version number to ask for in one shot.
//
VersNoLimit.QuadPart = LiAdd(n, Tmp);
//
// If my max. version number is less than the version number
// computed above, we do not specify a number for the max.
// records. If however, my max. vers. no is more, we specify
// the number equal to the chunk specified in Tmp
//
if (LiLeq(MyMaxVersNo, VersNoLimit)) { MaxNoOfRecsReqd = 0; } else { MaxNoOfRecsReqd = Tmp.LowPart; }
// log a detailed event saying what are the exact records that are retrieved
// from the database for scavenging. This helps finding out whether the loop is
// not broken earlier that expected leaving records not scavenged.
WinsEvtLogDetEvt( TRUE, // Informational event
WINS_EVT_SCV_CHUNK, // event ID
NULL, // NULL filename
__LINE__, // line number where this event is logged
"ddddd", // data section format
MaxNoOfRecsReqd, // data: 2nd word
n.LowPart, n.HighPart, // data: 3rd, 4th words
MyMaxVersNo.LowPart, MyMaxVersNo.HighPart); // data: 5th, 6th words
/*
* Call database manager function to get all the records. owned * by us. No need to check the return status here */ NmsDbGetDataRecs( WINS_E_NMSSCV, pScvParam->PrLvl, n, MyMaxVersNo, //Max vers. no
MaxNoOfRecsReqd, FALSE, //we want data recs upto MaxVers
FALSE, //not interested in replica tombstones
NULL, //must be NULL since we are not
//doing scavenging of clutter
&NmsLocalAdd, FALSE, //both dynamic & static records should be considered
WINSCNF_RPL_DEFAULT_TYPE, //no use here
(LPVOID *)&pStartBuff, &BuffLen, &NoOfRecs );
//
// If no of records retrieved is 0, we should break out of
// the loop
//
if (NoOfRecs == 0) {
//
// deallocate the heap that was created
//
// NmsDbGetDataRecs always allocates a buffer (even if
// the number of records is 0). Let us deallocate it
//
GET_TLS_M(pTls); ASSERT(pTls->HeapHdl != NULL); WinsMscHeapFree(pTls->HeapHdl, pStartBuff); WinsMscHeapDestroy(pTls->HeapHdl); break; }
fGotSome = TRUE; if (!fRecsExistent) { fRecsExistent = TRUE; } NoOfRecsScv = 0; // init the counter to 0
(void)time(&CurrentTime);
for ( i = 0, pRec = pStartBuff; i < NoOfRecs; i++ ) {
State = NMSDB_ENTRY_STATE_M(pRec->Flag);
switch (State) {
case(NMSDB_E_ACTIVE): // don't touch active static records
if (!NMSDB_IS_ENTRY_STATIC_M(pRec->Flag)) { SET_STATE_IF_REQD_M( pRec, CurrentTime, pScvParam->TombstoneInterval, NMSDB_E_RELEASED, NoOfRecChgToRelSt ); } break;
case(NMSDB_E_RELEASED): // a static record can't become released, but who knows...
// just making sure we don't touch statics in this case
if (!NMSDB_IS_ENTRY_STATIC_M(pRec->Flag)) { SET_STATE_IF_REQD_M( pRec, CurrentTime, pScvParam->TombstoneTimeout, NMSDB_E_TOMBSTONE, NoOfRecChgToTombSt ); } break;
case(NMSDB_E_TOMBSTONE):
FUTURES("Redesign, so that the if condition is not executed multiple times"); //
//If there are records to delete and we have
//been up and running for at least 3 days, go
//ahead and delete them. The records should
//have replicated to atleast one partner by
//now.
if ((CurrentTime - sBootTime) >= THREE_DAYS || sfNoLimitChk) { SET_STATE_IF_REQD_M( pRec, CurrentTime, pScvParam->TombstoneTimeout, //no use
NMSDB_E_DELETED, NoOfRecToDel ); } break;
default: DBGPRINT1(EXC, "DoScavenging: Weird State of Record (%d)\n", State); WINSEVT_LOG_M(WINS_EXC_FAILURE, WINS_EVT_SFT_ERR); // Just change the state of the record to tombstone and continue
// with scavenging.
NMSDB_SET_STATE_M(pRec->Flag, NMSDB_E_TOMBSTONE); break; }
pRec = (PRPL_REC_ENTRY_T)( (LPBYTE)pRec + RPL_REC_ENTRY_SIZE ); }
//
// Make pTmp point to the last record in the
// buffer.
//
pTmp = (PRPL_REC_ENTRY_T)( (LPBYTE)pRec - RPL_REC_ENTRY_SIZE);
//
// If one or more records need to be scavenged
//
if (NoOfRecsScv > 0) { if (NoOfRecToDel > 0) {
//
// If the most recent record in this chunk has
// to be deleted, let us record that fact in a
// boolean.
// If in the scavenging of the next chunk, the
// most recent record is not deleted, the boolean
// will be reset. At this point we don't know
// whether or not there is even another record
// more recent than this one (the next time, we
// retrieve records, we may not get any)
//
CHECK("This if test is most probably not required. Get rid of it") if (LiLeq(pTmp->VersNo, MyMaxVersNo)) { //
// If entry is marked for deletion
//
if (NMSDB_ENTRY_DEL_M(pTmp->Flag)) { fLastEntryDel = TRUE; } else { fLastEntryDel = FALSE; } }
} else { fLastEntryDel = FALSE; }
UpdDb( pScvParam, pStartBuff, NoOfRecs, NoOfRecsScv ); TotNoOfRecsScv += NoOfRecsScv; } #ifdef WINSDBG
else { DBGPRINT0(DET,"DoScavenging: NO RECORDS NEED TO BE SCAVENGED AT THIS TIME\n"); } #endif
//
// get pointer to TLS for accessing the heap hdl later on
//
GET_TLS_M(pTls);
//
// if we specified a max. no. and the no. of recs retrieved
// is less than that, clearly there are no more records to
// retrieve. Get rid of the buffer and break out of the loop
//
if ((MaxNoOfRecsReqd > 0) && (NoOfRecs < MaxNoOfRecsReqd)) { //
// Since the number of records we retrieved were
// less than the max. we had specified, it means that
// there are no more records to retrieve. Break out of
// the for loop
//
//
// destroy the heap that was allocated
//
for (RecCnt=0, pRec = pStartBuff; RecCnt<NoOfRecs; RecCnt++) { WinsMscHeapFree(pTls->HeapHdl, pRec->pName); pRec = (PRPL_REC_ENTRY_T)( (LPBYTE)pRec + RPL_REC_ENTRY_SIZE ); }
WinsMscHeapFree(pTls->HeapHdl, pStartBuff); WinsMscHeapDestroy(pTls->HeapHdl); break; } //
// Set n to the highest version number retrieved if it is
// more than what n would be set to prior to the next
// iteration.
//
// At the next iteration, n will be compared with the highest
// version number we have. If equal, then we don't have to
// iterate anymore (useful when the highest version number
// is very high but there are one or more records with low
// version numbers
//
if (LiGtr(pTmp->VersNo, VersNoLimit)) { n = pTmp->VersNo; } else { n = VersNoLimit; }
//
// destroy the heap that was allocated
//
for (RecCnt=0, pRec = pStartBuff; RecCnt<NoOfRecs; RecCnt++) { WinsMscHeapFree(pTls->HeapHdl, pRec->pName); pRec = (PRPL_REC_ENTRY_T)( (LPBYTE)pRec + RPL_REC_ENTRY_SIZE ); }
WinsMscHeapFree(pTls->HeapHdl, pStartBuff); WinsMscHeapDestroy(pTls->HeapHdl);
} // end of for loop for looping over records
WINSEVT_LOG_INFO_D_M(TotNoOfRecsScv, WINS_EVT_SCV_RECS); WINSDBG_INC_SEC_COUNT_M(SectionCount);
//
// If the last scavenging action was a deletion, it means that
// we deleted the highest version numbered record owned by
// us. Let us therefore update the Special record that records
// this version number.
//
if (fLastEntryDel) { WinsMscSetThreadPriority( WinsThdPool.ScvThds[0].ThdHdl, THREAD_PRIORITY_NORMAL );
(VOID)NmsDbUpdHighestVersNoRec( NULL, //no pTls
MyMaxVersNo, TRUE //enter critical section
); WinsMscSetThreadPriority( WinsThdPool.ScvThds[0].ThdHdl, pScvParam->PrLvl ); } (void)time(&CurrentTime); //
// Let us get rid of the replica tombstones if sufficient time has
// elapsed since the last time we did this. Exception: If the
// administrator has requested scavenging, let us do it now.
// Even if admin. requests it we don't do it unless we have been
// up and running for atleast 3 days. This is in line with our
// philosophy of being absolutely robust even when admin. makes
// mistakes.
// sfNoLimitChk allows testers to override this 3 day limitations.
if ( ( ((CurrentTime > sLastTombTime) && (CurrentTime - sLastTombTime) > (time_t)min( pScvParam->TombstoneTimeout, pScvParam->TombstoneInterval ) ) || sfAdminForcedScv ) && ((CurrentTime - sBootTime >= THREE_DAYS) || fForce || sfNoLimitChk) ) { NMSSCV_CLUT_T ClutterInfo; WinsIntfSetTime( NULL, WINSINTF_E_TOMBSTONES_SCV );
NoOfRecsScv = 0; NoOfRecToDel = 0;
ClutterInfo.Interval = pScvParam->TombstoneTimeout; ClutterInfo.CurrentTime = CurrentTime; ClutterInfo.fAll = FALSE; //not used but
//let us set it
/*
* Call database manager function to get all the * replicas that are tombstones */ DBGPRINT0(DET, "DoScavenging: GETTING REPLICA TOMBSTONES\n"); NmsDbGetDataRecs( WINS_E_NMSSCV, pScvParam->PrLvl, n, //no use in this call
MyMaxVersNo, //no use in this call
0, //no use in this call
TRUE, //no use in this call
TRUE, //Get only replica tombstones
&ClutterInfo, &NmsLocalAdd, //no use in this call
FALSE, //both dyn & static should be taken
WINSCNF_RPL_DEFAULT_TYPE, //no use here
(LPVOID *)&pStartBuff, &BuffLen, &NoOfRecs );
if(NoOfRecs > 0) {
for ( i = 0, pRec = pStartBuff; i < NoOfRecs; i++ ) { NMSDB_SET_STATE_M(pRec->Flag, NMSDB_E_DELETED); pRec->fScv = TRUE; NoOfRecToDel = NoOfRecs; pRec = (PRPL_REC_ENTRY_T)( (LPBYTE)pRec + RPL_REC_ENTRY_SIZE );
}
//
// If one or more replicas needs to be deleted
// call UpdDb
//
DBGPRINT1(DET, "DoScavenging: %d REPLICAS WILL BE DELETED\n", NoOfRecs); UpdDb( pScvParam, pStartBuff, NoOfRecs, NoOfRecs //NoOfRecsScv
);
if (fForce) { DBGPRINT0(SCV, "DoScavenging: FORCEFUL SCAVENGING OF REPLICA TOMBSTONES\n"); WINSEVT_LOG_M(WINS_SUCCESS, WINS_EVT_FORCE_SCV_R_T); }
WINSEVT_LOG_INFO_D_M(NoOfRecsScv, WINS_EVT_SCV_RPLTOMB); } #ifdef WINSDBG
else { DBGPRINT0(DET, "DoScavenging: NO REPLICA TOMBSTONES DELETED\n"); } #endif
//
// destroy the heap that was allocated
//
GET_TLS_M(pTls); //
// destroy the heap that was allocated
//
for (RecCnt=0, pRec = pStartBuff; RecCnt<NoOfRecs; RecCnt++) { WinsMscHeapFree(pTls->HeapHdl, pRec->pName); pRec = (PRPL_REC_ENTRY_T)( (LPBYTE)pRec + RPL_REC_ENTRY_SIZE ); } WinsMscHeapFree(pTls->HeapHdl, pStartBuff); WinsMscHeapDestroy(pTls->HeapHdl);
//
// record current time in sLastTombTime
//
sLastTombTime = CurrentTime;
} // end of if (test if replica tombstones need to be processed)
WINSEVT_LOG_INFO_D_M(WINS_SUCCESS, WINS_EVT_SCVENGING_COMPLETED); }
WINSDBG_INC_SEC_COUNT_M(SectionCount);
if (Opcode_e != WINSINTF_E_SCV_GENERAL) { WinsMscSetThreadPriority( WinsThdPool.ScvThds[0].ThdHdl, pScvParam->PrLvl ); } //
// If we are due for a verification or if we are being forced to do
// it by the admin., do it. Note: Timer Thread initiated verification
// is always forced. An admin. initiated one may or may not be forced.
// We force the admin. to specify the kind of verification he wants.
// If he chooses to do a forceful one, then we give him a warning.
// about the overhead of this (specially if a number of admins. are
// doing forceful verification around the same time or one after
// another
//
if ( ((CurrentTime > sLastVerifyTime) && ((CurrentTime - sLastVerifyTime) > (time_t)pScvParam->VerifyInterval)) || fForce ||
(sfAdminForcedScv && (CurrentTime - sLastAdminScvTime) >= ONE_HOUR ) ) {
// we might want to always log normal events for consistency checking
// since this operation happens normally only when initiated by the
// administrator or at about 24hrs, if configured
// (or reg param ..Parameters\ConsistencyCheck:TimeInterval)
// --ft: #384489: if this is an administrator initiated action...
//if (sfAdminForcedScv)
//..log the event as a normal one
WINSEVT_LOG_INFO_M(WINS_SUCCESS, WINS_EVT_CCCHECK_STARTED); //else
//..log it as a detailed event only.
// WINSEVT_LOG_INFO_D_M(WINS_SUCCESS, WINS_EVT_CCCHECK_STARTED);
WinsIntfSetTime( NULL, WINSINTF_E_VERIFY_SCV ); //
// get all active replicas that are older than the
// verify interval. Contact the owner WINS to verify their
// validity
//
//DBGPRINT1(ERR, "DoScavenging: pScvParam is (%x)\n", pScvParam);
(VOID)VerifyDbData(pScvParam, CurrentTime, Age, fForce, fPeriodicCC); //WINSEVT_LOG_INFO_D_M(WINS_SUCCESS, WINS_EVT_SCV_CLUTTER);
// --ft: #384489: see comment above.
//if (sfAdminForcedScv)
//..log the event as a normal one
WINSEVT_LOG_INFO_M(WINS_SUCCESS, WINS_EVT_CCCHECK_COMPLETED); //else
//..log it as a detailed event only.
// WINSEVT_LOG_INFO_D_M(WINS_SUCCESS, WINS_EVT_CCCHECK_COMPLETED);
sLastVerifyTime = CurrentTime;
}
WINSDBG_INC_SEC_COUNT_M(SectionCount);
} // end of try ..
except (EXCEPTION_EXECUTE_HANDLER) { DBGPRINTEXC("DoScavenging"); DBGPRINT1(EXC, "DoScavenging: Section Count (%d)\n", SectionCount); DBGPRINT5(EXC, "DoScavenging: Variables - i (%d), NoOfRecs (%d), \
NoOfRecsScv (%d), pStartBuff (%p), pRec (%p)\n", i, NoOfRecs, NoOfRecsScv, pStartBuff, pRec );
if (GetExceptionCode() != WINS_EXC_COMM_FAIL) { //
// Set thd. priority back to normal
//
WinsMscSetThreadPriority( WinsThdPool.ScvThds[0].ThdHdl, THREAD_PRIORITY_NORMAL ); //
// This is serious. Let us reraise the exception so that
// WINS comes down
//
//WINS_RERAISE_EXC_M();
//
// just return so that we close tables in the caller function
//
return(WINS_FAILURE); } }
//
// Set thd. priority back to normal
//
WinsMscSetThreadPriority( WinsThdPool.ScvThds[0].ThdHdl, THREAD_PRIORITY_NORMAL ); if (Opcode_e == WINSINTF_E_SCV_GENERAL) { //
//If we were not able to retrieve any owned records in this scavenging
// cycle, adjust the min. scv vers. no. Synchronize with
// RplPullPullSpecifiedRange
//
if (!fRecsExistent) { //
// NmsScvMinScvVersNo may be greater than MyMaxVersNo
// (This may happen if we did not find any local records
// last time around and no registrations have taken
// place since then).
//
if (LiGtr(MyMaxVersNo, NmsScvMinScvVersNo)) {
//
//
// Change the Low end of the range that
// we will use it at the next Scavenging cycle
//
EnterCriticalSection(&NmsNmhNamRegCrtSec);
//
// Set the Min. Scv. Vers. no to 1 more than the max. vers.
// no. we used when searching for records to scavenge.
//
NMSNMH_INC_VERS_NO_M(MyMaxVersNo, MyMaxVersNo); NmsScvMinScvVersNo = MyMaxVersNo; LeaveCriticalSection(&NmsNmhNamRegCrtSec); } }
//
// If we are not executing a work item from the queue, break out
// of the while loop, else continue (to get the next work item)
// if there
//
if (!fSignaled) { break; } } } // end of while
DBGPRINT0(SCV, "SCAVENGING CYCLE ENDED\n"); DBGLEAVE("DoScavenging\n"); return(WINS_SUCCESS); }
VOID ReconfigScv( PNMSSCV_PARAM_T pScvParam )
/*++
Routine Description: This function is called to reinit the scavenging params
Arguments: pScvParam - Structure storing the scavenging params
Externals Used: None
Return Value: None
Error Handling:
Called by: ScvThdInitFn Side Effects:
Comments: None --*/
{ DBGENTER("ReconfigScv\n"); //
// Extract the parameters that are related
// to scavenging and go back to doing the timed
// wait. Since WinsCnf can change any time, we
// operate with copies. Also, the priority of this
// thread is changed outside of this critical section
// See DoScavenging().
//
EnterCriticalSection(&WinsCnfCnfCrtSec); try { pScvParam->ScvChunk = WinsCnf.ScvChunk; pScvParam->RefreshInterval = WinsCnf.RefreshInterval; pScvParam->TombstoneInterval = WinsCnf.TombstoneInterval; pScvParam->TombstoneTimeout = WinsCnf.TombstoneTimeout; pScvParam->PrLvl = WinsCnf.ScvThdPriorityLvl;
//
// Load up the CC parameters
//
pScvParam->CC.TimeInt = WinsCnf.CC.TimeInt; pScvParam->CC.fSpTime = WinsCnf.CC.fSpTime; pScvParam->CC.SpTimeInt = WinsCnf.CC.SpTimeInt; pScvParam->CC.MaxRecsAAT = WinsCnf.CC.MaxRecsAAT; pScvParam->CC.fUseRplPnrs = WinsCnf.CC.fUseRplPnrs;
//
// If the backup path has changed, start using it.
//
if (WinsCnf.pBackupDirPath != NULL) { if (strcmp(WinsCnf.pBackupDirPath, pScvParam->BackupDirPath)) { strcpy(pScvParam->BackupDirPath, WinsCnf.pBackupDirPath); } } else { pScvParam->BackupDirPath[0] = EOS; } } finally { LeaveCriticalSection(&WinsCnfCnfCrtSec); }
DBGLEAVE("ReconfigScv\n"); return; }
#ifdef WINSDBG
#pragma optimize ("", off)
#endif
VOID UpdDb( IN PNMSSCV_PARAM_T pScvParam, IN PRPL_REC_ENTRY_T pStartBuff, IN DWORD NoOfRecs, IN DWORD NoOfRecsToUpd )
/*++
Routine Description:
This function is called to update the DB
Arguments: pScvParam - Scavenging params pStartBuff - Buffer containing records processed by DoScavenging() NoOfRecs - No of records in the above buffer NoofRecsToUpd - No of records that need to be modified in the db
Externals Used: None
Return Value: None
Error Handling:
Called by: DoScavenging
Side Effects:
Comments: None --*/
{ DWORD i; DWORD NoUpdated = 0; //No of records that have been
//updated
PRPL_REC_ENTRY_T pRec = pStartBuff;
DBGENTER("UpdDb\n");
//
// Set the current index to be the clustered index
//
NmsDbSetCurrentIndex( NMSDB_E_NAM_ADD_TBL_NM, NMSDB_NAM_ADD_CLUST_INDEX_NAME ); //
// Update the database now
//
for ( i = 0; i < NoOfRecs; i++ ) {
//
// if the record was updated, update the db
//
if (pRec->fScv) { if (NmsDbQueryNUpdIfMatch( pRec, pScvParam->PrLvl, TRUE, //chg pr. lvl
WINS_E_NMSSCV ) == WINS_SUCCESS ) { NoUpdated++; // no of records that we
//have updated in the db
} else { DBGPRINT0(ERR, "DoScavenging: Could not scavenge a record\n"); WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_SCV_ERR); } }
//
// see if we are done
//
if (NoUpdated == NoOfRecsToUpd) { break; }
pRec = (PRPL_REC_ENTRY_T)( (LPBYTE)pRec + RPL_REC_ENTRY_SIZE ); } // end of for loop
DBGPRINT1(FLOW, "LEAVE: SCAVENGING: UpdDb. Records Updated = (%d)\n", NoUpdated); return; } // UpdDb()
#ifdef WINSDBG
#pragma optimize ("", on)
#endif
STATUS VerifyDbData( PNMSSCV_PARAM_T pScvParam, time_t CurrentTime, DWORD Age, BOOL fForce, BOOL fPeriodicCC )
/*++
Routine Description: This function is called to remove any clutter that might have accumulated in the db. For each owner, excepting self, in the db, it gets the version numbers of the active records that are older than the verify time interval. It then contacts the owner WINS to verify their validity
Arguments: pScvParam - pointer to the scavenging parameters
Externals Used: None
Return Value: None
Error Handling:
Called by:
DoScavenging
Side Effects:
Comments: None --*/
{
DWORD MaxOwnerIdFound; volatile DWORD i; NMSSCV_CLUT_T ClutterInfo; PRPL_REC_ENTRY_T pStartBuff; DWORD BuffLen; DWORD NoOfLocalDbRecs; COMM_ADD_T OwnerWinsAdd; COMM_ADD_T VerifyWinsAdd; PCOMM_ADD_T pWinsAdd; VERS_NO_T MinVersNo, MaxVersNo; PNMSDB_WINS_STATE_E pWinsState_e; PVERS_NO_T pStartVersNo; NMSDB_WINS_STATE_E WinsState_e; COMM_HDL_T DlgHdl; PWINSTHD_TLS_T pTls; static DWORD sFirstOwnerId = 1; DWORD FirstOwnerId; DWORD NoOfPulledRecs; DWORD TotNoOfPulledRecs = 0; DWORD LastOwnerId; BOOL fNonOwnerPnr; DWORD TotPulledRecsFromOneWins; BOOL fDlgStarted = FALSE; BOOL fFirstTime; PRPL_REC_ENTRY_T pLastEntry; STATUS RetStat; DWORD RplType; BOOL fPulledAtLeastOnce; VERS_NO_T MaxVersNoSave;
DBGENTER("VerifyDbData\n");
//
// Init the structure used by NmsDbGetDataRecs()
//
ClutterInfo.Interval = pScvParam->VerifyInterval; ClutterInfo.CurrentTime = CurrentTime; ClutterInfo.Age = Age; ClutterInfo.fAll = TRUE;
//
// Set thread priority to NORMAL
//
WinsMscSetThreadPriority( WinsThdPool.ScvThds[0].ThdHdl, THREAD_PRIORITY_NORMAL );
//
// Cleanup the owner-address table if it requires cleaning
//
NmsDbCleanupOwnAddTbl(&MaxOwnerIdFound);
try {
//
// If it is an admin. forced verification or the one that happens
// due to the verify interval being over, do a full validation
//
if (!fPeriodicCC) { FirstOwnerId = 1; sLastFullVerifyTime = CurrentTime; } else { //
// Periodic verification. Skip the owners we verified earlier
//
if (sFirstOwnerId >= MaxOwnerIdFound) { sFirstOwnerId = 1; } FirstOwnerId = sFirstOwnerId; } LastOwnerId = MaxOwnerIdFound;
//
// for each owner in the db, excluding self, do the following.
//
for (i = FirstOwnerId; i <= LastOwnerId; i++) {
//
// If it is periodic verification and we have pulled more than
// the max. threshold specified for one particular cycle,
// break out of the loop
//
if (fPeriodicCC && (TotNoOfPulledRecs >= pScvParam->CC.MaxRecsAAT)) { break;
}
//
// Get all ACTIVE replicas that are older than verify interval.
//
ClutterInfo.OwnerId = i;
//
// We need to synchronize with the Pull thread which can
// change the NmsDbOwnAddTbl table. The entry may have
// been deleted by the Pull thread (DeleteWins), so we
// should be ready for access violation
//
EnterCriticalSection(&NmsDbOwnAddTblCrtSec); RPL_FIND_ADD_BY_OWNER_ID_M( i, pWinsAdd, pWinsState_e, pStartVersNo);
//
// The Wins entry should be there.
//
ASSERT(pWinsAdd); OwnerWinsAdd = *pWinsAdd; WinsState_e = *pWinsState_e; LeaveCriticalSection(&NmsDbOwnAddTblCrtSec);
//
// If WINS is not active, log a record and continue to
// the next WINS. It is possible for WINS to get deleted
// to between the time we get its records and the time
// we check the own-add table for its entry.
//
if ( (WinsState_e == NMSDB_E_WINS_DOWN) || (WinsState_e == NMSDB_E_WINS_DELETED) ) {
//
// if there are records in the db, then the
// state of WINS in the in-memory table can not
// be deleted
//
DBGPRINT2(SCV, "VerifyDbData: WINS with index = (%d) and IP Address = (%x) is either down or deleted \n", i, OwnerWinsAdd.Add.IPAdd); continue; }
WINS_ASSIGN_INT_TO_LI_M(MinVersNo, 0); fFirstTime = TRUE; TotPulledRecsFromOneWins = 0; fPulledAtLeastOnce = FALSE;
//
// Save the max. vers. no. that we have in the
// pRplPullOwnerVersNo table in a local.
//
EnterCriticalSection(&RplVersNoStoreCrtSec); #ifdef WINSDBG
try { #endif
MaxVersNoSave = (pRplPullOwnerVersNo + i)->VersNo; #ifdef WINSDBG
} //end of try { .. }
finally { #endif
LeaveCriticalSection(&RplVersNoStoreCrtSec); #ifdef WINSDBG
} #endif
do { NoOfLocalDbRecs = 0; // DBGPRINT1(ERR, "VerifyDbData:1 pScvParam is (%x)\n", pScvParam);
MaxVersNo.QuadPart = 0; NmsDbGetDataRecs( WINS_E_NMSSCV, pScvParam->PrLvl, MinVersNo, MaxVersNo, //not used in this call
0, TRUE, //fUpToLimit set to TRUE
FALSE, //not interested in replica tombstones
&ClutterInfo, &OwnerWinsAdd, //Wins Address - not used
FALSE, //dyn + static recs required
WINSCNF_RPL_DEFAULT_TYPE, //no use here
(LPVOID *)&pStartBuff, &BuffLen, &NoOfLocalDbRecs );
GET_TLS_M(pTls); ASSERT(pTls->HeapHdl != NULL);
WinsMscChkTermEvt( #ifdef WINSDBG
WINS_E_NMSSCV, #endif
FALSE );
PERF("Optimize so that we reuse a dlg session if we need to go to the same") PERF("pnr in a subsequent iteration") //
// If this is the first time, we pick a WINS and establish
// communications with it. Note: If the max. vers. no
// in pRplOwnerVersNo for this WINS is 0, we continue on
// to the next WINS in our list.
//
// We don't care whether or not we were able to retrieve
// any records from the db. If we retrieved 0 but the Wins's
// pRplPullOwnerVersNo entry has a positive entry, it means
// we are out of synch
//
if (fFirstTime) { if (MaxVersNoSave.QuadPart == 0) { ASSERT(NoOfLocalDbRecs == 0); DBGPRINT2(SCV, "VerifyDbData: WINS with index = (%d) and address = (%x) has pRplPullOwnerVersNo value of 0. SKIPPING IT\n", i, OwnerWinsAdd.Add.IPAdd);
FreeDbMemory(pStartBuff, NoOfLocalDbRecs, pTls); break; }
//
// Pick the pnr to use for verification
//
if (PickWinsToUse( &VerifyWinsAdd, &OwnerWinsAdd, pScvParam->CC.fUseRplPnrs, &fNonOwnerPnr, &RplType) != WINS_SUCCESS) { //
// Any error that needed to be logged has already
// been logged. Just return success.
//
FreeDbMemory(pStartBuff, NoOfLocalDbRecs, pTls); return (WINS_SUCCESS); }
//
// Establish communication with it. If we can not
// establish comm. with it, break out of the loop
//
RetStat = EstablishCommForVerify(&VerifyWinsAdd, &DlgHdl);
if (RetStat == WINS_FAILURE) { FreeDbMemory(pStartBuff, NoOfLocalDbRecs, pTls); break; //go on to the next WINS in the list of owners
} fDlgStarted = TRUE;
//
// get the min and max version numbers of the active
// replicas
//
MinVersNo.QuadPart = 1; //pStartBuff->VersNo;
fFirstTime = FALSE; } // if first time
{
//
//Must not pull a version number that is > what we
//have in our table to avoid conflicting with the
//pull thread.
//
MaxVersNo = MaxVersNoSave; } ASSERT(MaxVersNo.QuadPart <= MaxVersNoSave.QuadPart);
DBGPRINT5(DET, "VerifyDbData: Going to pull records in the range (%d %d) to (%d %d) from Wins with owner id = (%d)\n", MinVersNo.HighPart, MinVersNo.LowPart, MaxVersNo.HighPart, MaxVersNo.LowPart, i );
try { //
// Pull the records in the range from the WINS
//
PullAndUpdateDb( &DlgHdl, &OwnerWinsAdd, pStartBuff, i, MinVersNo, MaxVersNo, RplType, NoOfLocalDbRecs, CurrentTime, pScvParam, fNonOwnerPnr, &TotPulledRecsFromOneWins ); } except (EXCEPTION_EXECUTE_HANDLER) { // just in case some exception is raised while pulling the records,
// bail this owner only, not the entire scavenge process
FreeDbMemory(pStartBuff, NoOfLocalDbRecs, pTls); break; }
if (!fPulledAtLeastOnce) { fPulledAtLeastOnce = TRUE; } //
// deallocate the memory block that was allocated
//
// NmsDbGetDataRecs always allocates a buffer (even if
// the number of records is 0). Let us deallocate it
//
FreeDbMemory(pStartBuff, NoOfLocalDbRecs, pTls);
//
// Make the min. version number 1 more than the the
// max. vers. no. we used last time
//
NMSNMH_INC_VERS_NO_M(MaxVersNo, MinVersNo);
} while (LiLtr(MaxVersNo,MaxVersNoSave));
if (fDlgStarted) { ECommEndDlg(&DlgHdl); fDlgStarted = FALSE; } if ((WinsCnf.LogDetailedEvts > 0) && fPulledAtLeastOnce) { WinsEvtLogDetEvt(TRUE, WINS_EVT_CC_NO_RECS, NULL, __LINE__, "ddd", TotPulledRecsFromOneWins, OwnerWinsAdd.Add.IPAdd, VerifyWinsAdd.Add.IPAdd);
DBGPRINT3(SCV, "VerifyDbData: WINS pulled (%d) records owned by WINS= (%x) from WINS = (%x) for doing CC\n", TotPulledRecsFromOneWins, OwnerWinsAdd.Add.IPAdd, VerifyWinsAdd.Add.IPAdd); }
//
// Total no. of records pulled so far
//
TotNoOfPulledRecs += TotPulledRecsFromOneWins; } //end of for loop for looping over owners
//
// We are done for this cycle. If this was a CC verify, set
// sFirstOwnerId to the index of the WINS to start from in the next
// periodic CC cycle
//
if (fPeriodicCC) { sFirstOwnerId = i; }
} // end of try
except(EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("VerifyDbData"); DBGPRINT2(EXC, "VerifyDbData: i is (%d), MaxOwnerIdFound is (%d)\n",i, MaxOwnerIdFound);
//--ft: bug #422659--
// if an exception happens between EstablishCommForVerify and ECommEndDlg
// we need to make sure we close the connection - otherwise the connection
// remains active and the sender WINS eventually get stucked in send().
if (fDlgStarted) ECommEndDlg(&DlgHdl);
WINS_RERAISE_EXC_M(); }
//
// Set the priority back the old level
//
WinsMscSetThreadPriority( WinsThdPool.ScvThds[0].ThdHdl, pScvParam->PrLvl );
DBGLEAVE("VerifyDbData\n"); return(WINS_SUCCESS); } // VerifyDbData()
STATUS PickWinsToUse( IN PCOMM_ADD_T pVerifyWinsAdd, IN PCOMM_ADD_T pOwnerWinsAdd, IN BOOL fUseRplPnrs, OUT LPBOOL pfNonOwnerPnr, OUT LPBOOL pfRplType )
/*++
Routine Description: This function picks a WINS to verify the active replicas with
Arguments:
Externals Used: None
Return Value:
Success status codes -- Error status codes --
Error Handling:
Called by:
Side Effects:
Comments: None --*/
{ PRPL_CONFIG_REC_T pRplPnr; DWORD IndexOfPnrToUse; STATUS RetStat = WINS_SUCCESS;
*pfNonOwnerPnr = FALSE;
DBGENTER("PickWinsToUse\n"); //
// If the admin. specified that we should just use
// our replication partners for consistency checking,
// pick a replication partner for this.
//
*pfNonOwnerPnr = FALSE; EnterCriticalSection(&WinsCnfCnfCrtSec); try { pRplPnr = RplGetConfigRec(RPL_E_PULL, NULL, pOwnerWinsAdd); if (fUseRplPnrs) { //
// If this guy is not a partner but there are other partners that
// we can pick from, pick one
//
if (pRplPnr == NULL) { if (WinsCnf.PullInfo.NoOfPushPnrs > 0) { //
// Just use one of the pnrs. Pick one at
// random
//
*pfRplType = WinsCnf.PullInfo.RplType;
srand((unsigned)time(NULL)); IndexOfPnrToUse = rand() % WinsCnf.PullInfo.NoOfPushPnrs;
*pVerifyWinsAdd = ((PRPL_CONFIG_REC_T)((LPBYTE)WinsCnf.PullInfo.pPullCnfRecs + (IndexOfPnrToUse * RPL_CONFIG_REC_SIZE)))->WinsAdd;
*pfNonOwnerPnr = TRUE; } else { DBGPRINT0(ERR, "PickWinsToUse: CC checking NOT DONE since no partners are there\n"); WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_CC_FAILED); RetStat = WINS_FAILURE; } } else { *pfRplType = pRplPnr->RplType;
} } // if (fUseRplPnr)
else { *pfRplType = (pRplPnr != NULL) ? pRplPnr->RplType : WinsCnf.PullInfo.RplType; } } // end if try {..}
finally { LeaveCriticalSection(&WinsCnfCnfCrtSec);
if (RetStat == WINS_SUCCESS) { //
// If we are to communicate with the owner WINS, set *pVerifyWinsAdd
// since it was not set above.
//
if (!*pfNonOwnerPnr) { *pVerifyWinsAdd = *pOwnerWinsAdd; } DBGPRINT3(DET, "VerifyDbData: Using pnr no = (%d) with address = (%x) for verification of records owned by WINS (%x)\n", IndexOfPnrToUse, pVerifyWinsAdd->Add.IPAdd, pOwnerWinsAdd->Add.IPAdd) } } DBGLEAVE("PickWinsToUse\n"); return (RetStat); } //PickWinsToUse()
STATUS EstablishCommForVerify( PCOMM_ADD_T pWinsAdd, PCOMM_HDL_T pDlgHdl )
/*++
Routine Description: This function is called to setup communication with a WINS
Arguments:
Externals Used: None
Return Value:
Success status codes -- Error status codes --
Error Handling:
Called by:
Side Effects:
Comments: None --*/
{ //DWORD NoOfRetries = 0;
BOOL fAbort = FALSE; STATUS RetStat = WINS_SUCCESS;
DBGENTER("EstablishCommForVerify\n"); //
// We try a certain number of times to establish a
// a dialogue. Currently, it is 1.
//
do { try { ECommStartDlg( pWinsAdd, WINS_E_NMSSCV, pDlgHdl ); } except(EXCEPTION_EXECUTE_HANDLER) { DBGPRINTEXC("VerifyDbData"); if (GetExceptionCode() == WINS_EXC_COMM_FAIL) { DBGPRINT1(EXC, "VerifyDbData: Could not start a dlg with WINS at address (%x)\n", pWinsAdd->Add.IPAdd);
//--ft: 07/10/00 commented out since VERIFY_NO_OF_RETRIES is 0 anyhow so the test is always false.
//if (NoOfRetries++ < VERIFY_NO_OF_RETRIES)
//{
// Sleep(VERIFY_RETRY_TIME_INTERVAL);
// continue;
//}
RetStat = WINS_FAILURE; } else { //
// This is a serious error. Log and abort the verify cycle
//
WINSEVT_LOG_M(WINS_FATAL_ERR, WINS_EVT_SFT_ERR); RetStat = WINS_FAILURE; } } // end of exception handler
break; } while (TRUE); if (RetStat == WINS_FAILURE) { DBGPRINT1(ERR, "EstablishCommForVerify: Could not start dlg with WINS at address (%x)\n", pWinsAdd->Add.IPAdd); } DBGLEAVE("EstablishCommForVerify\n"); return(RetStat); } // EstablishCommForVerify()
VOID PullAndUpdateDb( PCOMM_HDL_T pDlgHdl, PCOMM_ADD_T pOwnerWinsAdd, PRPL_REC_ENTRY_T pRspBuff, DWORD WinsIndex, VERS_NO_T MinVersNo, VERS_NO_T MaxVersNo, DWORD RplType, DWORD NoOfLocalDbRecs, time_t CurrentTime, PNMSSCV_PARAM_T pScvParam, BOOL fNonOwnerPnr, LPDWORD pTotNoPulledFromOneWins )
/*++
Routine Description: This pulls the records in the range specified and then updates the db accordingly
Arguments:
Externals Used: None
Return Value:
NONE
Error Handling:
Called by: VerifyDbData() Side Effects:
Comments: None --*/
{
LPBYTE pBuffOfPulledRecs; VERS_NO_T VersNo; DWORD NoOfPulledRecs;
DBGENTER("PullAndUpdateDb\n"); while (TRUE) { //
//Pull the records in the range min-max determined
//above
//
RplPullPullEntries( pDlgHdl, WinsIndex, MaxVersNo, MinVersNo, WINS_E_NMSSCV, &pBuffOfPulledRecs, FALSE, //do not want to update counters
RplType );
//
// Update the DB. All valid records are updated.
// The invalid records are deleted from the db
//
ChkConfNUpd( #if SUPPORT612WINS > 0
pDlgHdl, #endif
pOwnerWinsAdd, RplType, WinsIndex, &pRspBuff, pBuffOfPulledRecs, &NoOfLocalDbRecs, CurrentTime, pScvParam->VerifyInterval, fNonOwnerPnr, &NoOfPulledRecs, &VersNo );
*pTotNoPulledFromOneWins += NoOfPulledRecs;
//
// Free the response buffer
//
ECommFreeBuff(pBuffOfPulledRecs - COMM_HEADER_SIZE);
//
//If vers. no. pulled is smaller than the Max. Vers
//no, specified, check if it is because of the limit
//we have set for the max. number or records that
//can be replicated at a time. If yes, pull again.
//
if ( LiLtr(VersNo, MaxVersNo) && (NoOfPulledRecs == RPL_MAX_LIMIT_FOR_RPL) ) { MinVersNo = VersNo; NMSNMH_INC_VERS_NO_M(MinVersNo, MinVersNo); continue; } break; //break out of the loop
} //end of while (pulled all records in the range from pnr)_
DBGLEAVE("PullAndUpdateDb\n"); return; } // PullAndUpdateDb()
__inline VOID FreeDbMemory( LPVOID pStartBuff, DWORD NoOfLocalDbRecs, PWINSTHD_TLS_T pTls )
/*++
Routine Description: Frees the memory allocated by NmsDbGetDataRecs()
Arguments:
Externals Used: None
Return Value:
NONE
Error Handling:
Called by: VerifyDbData() Side Effects:
Comments: None --*/
{ PRPL_REC_ENTRY_T pRec; DWORD RecCnt;
for ( RecCnt=0, pRec = pStartBuff; RecCnt < NoOfLocalDbRecs; RecCnt++ ) { WinsMscHeapFree(pTls->HeapHdl, pRec->pName); pRec = (PRPL_REC_ENTRY_T)( (LPBYTE)pRec + RPL_REC_ENTRY_SIZE ); } WinsMscHeapFree(pTls->HeapHdl, pStartBuff); WinsMscHeapDestroy(pTls->HeapHdl); return; } // FreeDbMemory ()
VOID ChkConfNUpd( #if SUPPORT612WINS > 0
IN PCOMM_HDL_T pDlgHdl, #endif
IN PCOMM_ADD_T pOwnerWinsAdd, IN DWORD RplType, IN DWORD OwnerId, IN PRPL_REC_ENTRY_T *ppLocalDbRecs, IN LPBYTE pRspBuff, IN DWORD *pNoOfLocalDbRecs, IN time_t CurrentTime, IN DWORD VerifyTimeIntvl, IN BOOL fNonOwnerPnr, OUT LPDWORD pNoOfPulledRecs, OUT PVERS_NO_T pMaxVersNo ) /*++
Routine Description: This function compares the records that have been pulled from a WINS with those in its local db. If the comparison is successful, the record's timestamp in the local db is updated. If the comparison is unsuccessful (i.e. the record in the local db has no match in the list of records pulled from the remote WINS, the record is deleted in the local db
Arguments: pLocalDbRecs - Address of buffer holding the local active replicas pRspBuff - Buffer containing records pulled from the remote WINS NoOfLocalDbRecs - No of local replicas in the above buffer
Externals Used: None
Return Value: NONE
Error Handling:
Called by: VerifyDbData()
Side Effects:
Comments: None --*/ { DWORD NoOfPulledRecs; BYTE Name[NMSDB_MAX_NAM_LEN]; DWORD NameLen; BOOL fGrp; DWORD NoOfAdds; COMM_ADD_T NodeAdd[NMSDB_MAX_MEMS_IN_GRP * 2]; //twice the # of
VERS_NO_T VersNo; LPBYTE pTmp = pRspBuff + 4; //past the opcode
DWORD i, j; PRPL_REC_ENTRY_T pRecLcl; DWORD NoOfRecsDel = 0; PRPL_REC_ENTRY_T pStartOfLocalRecs = *ppLocalDbRecs; DWORD MvNoOfLocalDbRecs = *pNoOfLocalDbRecs; DWORD Flag; DWORD NoOfRecsUpd = 0; DWORD NoOfRecsIns = 0; struct in_addr InAddr; #if SUPPORT612WINS > 0
BOOL fIsPnrBeta1Wins; #endif
DBGENTER("ChkConfNUpd\n");
//
// Set the current index to be the clustered index
//
NmsDbSetCurrentIndex( NMSDB_E_NAM_ADD_TBL_NM, NMSDB_NAM_ADD_CLUST_INDEX_NAME ); #if SUPPORT612WINS > 0
COMM_IS_PNR_BETA1_WINS_M(pDlgHdl, fIsPnrBeta1Wins); #endif
/*
* Get the no of records from the response and also the first record * if there is at least one record in the buffer */ RplMsgfUfmSndEntriesRsp( #if SUPPORT612WINS > 0
fIsPnrBeta1Wins, #endif
&pTmp, &NoOfPulledRecs, Name, &NameLen, &fGrp, &NoOfAdds, NodeAdd, &Flag, &VersNo, TRUE /*Is it first time*/ );
if (WinsCnf.LogDetailedEvts > 0) { PCOMMASSOC_DLG_CTX_T pDlgCtx = pDlgHdl->pEnt; PCOMMASSOC_ASSOC_CTX_T pAssocCtx = pDlgCtx->AssocHdl.pEnt; DWORD IpPartner = pAssocCtx->RemoteAdd.sin_addr.s_addr;
WinsEvtLogDetEvt(TRUE, WINS_EVT_REC_PULLED, TEXT("Verification"), __LINE__, "ddd", IpPartner, pOwnerWinsAdd->Add.IPAdd, NoOfPulledRecs); }
DBGPRINT3(SCV, "ChkConfNUpd: pulled Records - (%d), local records - (%d), local records Buf (%p)\n", NoOfPulledRecs, *pNoOfLocalDbRecs, pStartOfLocalRecs);
*pNoOfPulledRecs = NoOfPulledRecs; if (NoOfPulledRecs > 0) {
NMSSCV_REC_ACTION_E RecAction_e;
//
// After this function returns, all local records that have
// a version number < the version record of the pulled record
// will be marked deleted. Also, if there is a local record
// with the same version number as the pulled record but a
// different name it will be marked for deletion and fAddDiff
// will be set to TRUE so that we register the pulled record
// A local record with the same name and version number as
// the pulled one will be updated (timestamp only) in the db.
//
CompareWithLocalRecs( VersNo, Name, NMSDB_ENTRY_STATE_M(Flag), &pStartOfLocalRecs, &MvNoOfLocalDbRecs, CurrentTime, fNonOwnerPnr, &NoOfRecsDel, &RecAction_e ); //
// If RecAction_e is NMSSCV_E_INSERT and the record is
// marked as DELETED, it means that the pulled record
// has the same version number but a different name.
// This should never happen in a consistent system of
// WINS servers. The fact that it happened means that
// the administrator has goofed up. The remote WINS server
// has started afresh (new database) or its database got
// corrupted. If any of the above did happen, the
// administrator should have made sure that at startup,
// the WINS server was starting from a version counter
// value that was not less than what any of the other WINS
// servers thought it to be in.
//
// To bring the database upto snuff, this WINS server will
// register this replica. If there is a clash, it will
// be handled appropriately. One can think of this as
// a pulling in of replicas at replication time.
//
for ( i = 0, pRecLcl = *ppLocalDbRecs; pRecLcl < pStartOfLocalRecs; i++ ) { //
//
// We update/delete the record depending upon the
// Flag value set by Compare
// not interested in the return code
//
pRecLcl->NewTimeStamp = (DWORD)CurrentTime + VerifyTimeIntvl; NmsDbQueryNUpdIfMatch( pRecLcl, THREAD_PRIORITY_NORMAL, FALSE, //don't change pr. lvl
WINS_E_NMSSCV ); NoOfRecsUpd++; pRecLcl = (PRPL_REC_ENTRY_T)((LPBYTE)pRecLcl + RPL_REC_ENTRY_SIZE);
}
//
// register the replica if it needs to be inserted
//
if (RecAction_e == NMSSCV_E_INSERT) { RplPullRegRepl( Name, NameLen, Flag, OwnerId, VersNo, NoOfAdds, NodeAdd, pOwnerWinsAdd, RplType ); NoOfRecsIns++; }
//
// Do until we have covered all the local records.
//
for (i=1; MvNoOfLocalDbRecs > 0; i++) { //
// if we have retrieved all the pull records, use a
// version number that is > the highest in the local
// db recs cache so that all the records more than
// the highest version # pulled get deleted -
// Check out CompareWithLocalRecs()
//
if (i < NoOfPulledRecs) { RplMsgfUfmSndEntriesRsp( #if SUPPORT612WINS > 0
fIsPnrBeta1Wins, #endif
&pTmp, &NoOfPulledRecs, Name, &NameLen, &fGrp, &NoOfAdds, NodeAdd, &Flag, &VersNo, FALSE /*Is it first time*/ );
} else { //
// Find out if this is the end of replica records.
// if we pulled exactly RPL_MAX_LIMIT_FOR_RPL, then that
// may mean that there is more to come. In that case we just
// get out of the loop and pull next lot.
//
// otherwise, this is the last record from the replica.
// we set VerNo to highest value so that all the local records
// more than the highest vers no of the pulled records get
// deleted.
//
if ( RPL_MAX_LIMIT_FOR_RPL == NoOfPulledRecs ) { break; } else { if (VersNo.HighPart != MAXLONG) { VersNo.LowPart = MAXULONG; VersNo.HighPart = MAXLONG; } } } //
//See if there is a hit with a local record. If there
//is a hit, we update the time stamp of the hit
//record, else we delete it
//
// First set, pRecLcl to the address of the first
// local record since pStartOfLocalRecs can be changed
// by this function. Actually, there is no need to
// do this. pRecLcl will be set already
//
pRecLcl = pStartOfLocalRecs; CompareWithLocalRecs( VersNo, Name, NMSDB_ENTRY_STATE_M(Flag), &pStartOfLocalRecs, &MvNoOfLocalDbRecs, CurrentTime, fNonOwnerPnr, &NoOfRecsDel, &RecAction_e );
//
// All records upto the new first local record should
// be updated/deleted
//
for ( j = 0; pRecLcl < pStartOfLocalRecs; j++ ) { //
//We update/delete the record depending
//upon the Flag value set by Compare
// not interested in the return code
//
pRecLcl->NewTimeStamp = (DWORD)CurrentTime + VerifyTimeIntvl; NmsDbQueryNUpdIfMatch( pRecLcl, THREAD_PRIORITY_NORMAL, FALSE, //don't change pr. lvl
WINS_E_NMSSCV ); NoOfRecsUpd++; pRecLcl = (PRPL_REC_ENTRY_T)((LPBYTE)pRecLcl + RPL_REC_ENTRY_SIZE);
}
//
// register the replica if it needs to be inserted
//
if (RecAction_e == NMSSCV_E_INSERT) { RplPullRegRepl( Name, NameLen, Flag, OwnerId, VersNo, NoOfAdds, NodeAdd, pOwnerWinsAdd, RplType ); NoOfRecsIns++; } }
//
// Whatever records were not retrieved must be retrieved
// now and then inserted
//
for (j=i; j < NoOfPulledRecs; j++) {
RplMsgfUfmSndEntriesRsp( #if SUPPORT612WINS > 0
fIsPnrBeta1Wins, #endif
&pTmp, &NoOfPulledRecs, Name, &NameLen, &fGrp, &NoOfAdds, NodeAdd, &Flag, &VersNo, FALSE /*Is it first time*/ );
RplPullRegRepl( Name, NameLen, Flag, OwnerId, VersNo, NoOfAdds, NodeAdd, pOwnerWinsAdd, RplType ); NoOfRecsIns++;
} } else // we got 0 records from the remote WINS server. It means that
// all the active replicas for this WINS need to be deleted
{ //
// We delete records only if the pnr with which we are doing
// verification is the owner of the records
//
VersNo.QuadPart = 0; if (!fNonOwnerPnr) { pRecLcl = *ppLocalDbRecs;
//
// Change state of all replicas that we retrieved to deleted
//
for (i = 0; i < *pNoOfLocalDbRecs; i++) { NMSDB_SET_STATE_M(pRecLcl->Flag, NMSDB_E_DELETED);
//
//
// We update/delete the record depending upon the
// Flag value set by Compare
// not interested in the return code
//
NmsDbQueryNUpdIfMatch( pRecLcl, THREAD_PRIORITY_NORMAL, FALSE, //don't change pr. lvl
WINS_E_NMSSCV ); pRecLcl = (PRPL_REC_ENTRY_T)((LPBYTE)pRecLcl + RPL_REC_ENTRY_SIZE); NoOfRecsDel++; } }
}
//
// Update our couters/pointers for the next iterations.
// see PullAndUpdateDb routine.
//
*pMaxVersNo = VersNo; *ppLocalDbRecs = pStartOfLocalRecs; *pNoOfLocalDbRecs = MvNoOfLocalDbRecs;
if (WinsCnf.LogDetailedEvts > 0) { InAddr.s_addr = htonl(pOwnerWinsAdd->Add.IPAdd); WinsEvtLogDetEvt(TRUE, WINS_EVT_CC_STATS, NULL, __LINE__, "sddd", inet_ntoa(InAddr), NoOfRecsIns, NoOfRecsUpd, NoOfRecsDel);
} DBGPRINT4(DET, "ChkConfNUpd: Wins = (%s). NO OF RECS INSERTED = (%d); NO OF RECORDS UPDATED = (%d); NO OF RECS DELETED = (%d)\n", inet_ntoa(InAddr), NoOfRecsIns, NoOfRecsUpd, NoOfRecsDel);
DBGLEAVE("ChkConfNUpd\n");
return; } // ChkConfNUpd()
VOID CompareWithLocalRecs( IN VERS_NO_T VersNo, IN LPBYTE pName, IN NMSDB_ENTRY_STATE_E RecState_e, IN OUT PRPL_REC_ENTRY_T *ppLocalDbRecs, IN OUT DWORD *pNoOfLocalRecs, IN time_t CurrentTime, IN BOOL fNonOwnerPnr, IN OUT DWORD *pNoOfRecsDel, OUT PNMSSCV_REC_ACTION_E pRecAction_e )
/*++
Routine Description: This function checks if the pulled record is in the buffer containing local active replicas. If it is, it is marked for update (timestamp) If it is not, then all replicas in the buffer that have a version stamp < the pulled record are marked for deletion
Arguments: VersNo - Version no. of the pulled record pName - Name in the pulled record ppLocalDbRecs - ptr to address of buffer containing one or more local active replicas pNoOfLocalRecs - count of records in the above buffer pNoOfRecsDel - count of records to be deleted
Externals Used: None
Return Value: None
Error Handling:
Called by: ChkConfNUpd()
Side Effects:
Comments: None --*/
{
DWORD i; PRPL_REC_ENTRY_T pRecLcl = *ppLocalDbRecs; #ifdef UNICODE
WCHAR NameLcl[WINS_MAX_FILENAME_SZ]; WCHAR NameRem[WINS_MAX_FILENAME_SZ]; #endif
//
// default is don't insert.
//
*pRecAction_e = NMSSCV_E_DONT_INSERT;
//
// Loop over all local replicas
//
for(i=0; i < *pNoOfLocalRecs; i++) { //
// if version number of pulled record is less, we should get the
// next pulled record from the response buffer. We should
// insert this one into our db
//
if (LiLtr(VersNo, pRecLcl->VersNo)) {
#if 0
//
// We don't insert tombstones
//
if (RecState_e == NMSDB_E_ACTIVE) #endif
//
// Even tombstones are inserted because we may
// have just got rid of the active record (lower
// version number than this tombstone). The above
// is TRUE only when pulling from an owner WINS
//
if ((RecState_e == NMSDB_E_ACTIVE) || !fNonOwnerPnr) { *pRecAction_e = NMSSCV_E_INSERT; } break; } else { //
// if version number is same, we need to update this record
// in our local db. We mark it for update. Caveat:
// if we are verifying with a non-owner, we don't mark
// record for deletion. We just keep it since we don't
// know who is more current (we or our replication partner)
//
if (LiEql(VersNo, pRecLcl->VersNo)) { if ( !(RtlCompareMemory(pRecLcl->pName, pName, pRecLcl->NameLen) == pRecLcl->NameLen) && !fNonOwnerPnr ) { DBGPRINT2(DET, "CompareWithLocalRecs: Names are DIFFERENT. Name to Verify (%s), Name pulled (%s).\nThis could mean that the remote WINS server restarted with a vers. counter value < the value in the previous invocation.\n", pRecLcl->pName/*pRecLcl->Name*/, pName); FUTURES("Replace the local record with the pulled record") NMSDB_SET_STATE_M(pRecLcl->Flag, NMSDB_E_DELETED); (*pNoOfRecsDel)++;
//
// Insert record regardless of its state
// (ACTIVE or TOMBSTONE)
//
*pRecAction_e = NMSSCV_E_INSERT;
} i++; //increment i so that we don't compare the
//the next pulled record with all local records
//upto the one we just compared this pulled
//record with
break; } else { //
// For the non-owner case, since we don't know whether
// our pnr is more/less current than us, we don't delete
// the local record
//
if (!fNonOwnerPnr) { //
// version number is greater than record in
// our local db. We delete our local db record
//
NMSDB_SET_STATE_M(pRecLcl->Flag, NMSDB_E_DELETED); (*pNoOfRecsDel)++; } } } pRecLcl = (PRPL_REC_ENTRY_T)((LPBYTE)pRecLcl + RPL_REC_ENTRY_SIZE); }
//
// Adjust the pointer in the buffer of local replicas so that next
// time we are called in this verify cycle, we don't look at
// the replicas we have already seen. Also, adjust the count.
//
*ppLocalDbRecs = (PRPL_REC_ENTRY_T)( (LPBYTE)(*ppLocalDbRecs) + (i * RPL_REC_ENTRY_SIZE) ); *pNoOfLocalRecs = *pNoOfLocalRecs - i; return;
} //CompareWithLocalRecs
VOID DoBackup( PNMSSCV_PARAM_T pScvParam, LPBOOL pfThdPrNormal ) /*++
Routine Description:
Arguments:
Externals Used: None
Return Value:
Success status codes -- Error status codes --
Error Handling:
Called by:
Side Effects:
Comments: None --*/
{
time_t CurrentTime;
(void)time(&CurrentTime);
//
// if logging is on and sufficient time has elapsed to warrant a
// another backup.
//
if (WinsCnf.fLoggingOn && (CurrentTime - sLastDbNullBackupTime) >= PERIOD_OF_LOG_DEL) {
#ifdef WINSDBG
IF_DBG(HEAP_CNTRS) { WinsSetFlags(WINSINTF_MEMORY_INFO_DUMP | WINSINTF_HEAP_INFO_DUMP | WINSINTF_QUE_ITEMS_DUMP); } #endif
DBGPRINT0(DET, "DoBackup: Will do backup now\n");
if (!*pfThdPrNormal) { //
// Set thread priority back to normal
//
WinsMscSetThreadPriority( WinsThdPool.ScvThds[0].ThdHdl, THREAD_PRIORITY_NORMAL ); *pfThdPrNormal = TRUE; }
if (pScvParam->BackupDirPath[0] != EOS) { if ( (CurrentTime - sLastDbBackupTime) > PERIOD_OF_BACKUP) { if (NmsDbBackup(pScvParam->BackupDirPath, NMSDB_FULL_BACKUP) != WINS_SUCCESS) { //
// Failed to do full backup, just get rid of the
// log files.
//
DBGPRINT0(ERR, "DOING BACKUP to NULL\n"); NmsDbBackup(NULL, 0);
} else {
sLastDbBackupTime = CurrentTime;
} } else { DBGPRINT0(ERR, "DOING BACKUP to NULL\n"); NmsDbBackup(NULL, 0); } } else { //
// Can not do full backup, just get rid of the
// log files.
//
DBGPRINT0(ERR, "DOING BACKUP to NULL\n"); NmsDbBackup(NULL, 0); } sLastDbNullBackupTime = CurrentTime; } return; }
#if MCAST > 0
VOID DoMcastSend( DWORD_PTR CurrentTime, DWORD Code, DWORD fNow ) { if (fNow || (CurrentTime - sLastMcastTime) >= sMcastIntvl) { CommSendMcastMsg(Code); if (!fNow) { sLastMcastTime = CurrentTime; } } return; } #endif
|