/*! * \brief Main interaction loop for the recovery manager * * The recovery light-weight process only runs when you're the * synchronization site. It performs the following tasks, if and only * if the prerequisite tasks have been performed successfully (it * keeps track of which ones have been performed in its bit map, * \p urecovery_state). * * First, it is responsible for probing that all servers are up. This * is the only operation that must be performed even if this is not * yet the sync site, since otherwise this site may not notice that * enough other machines are running to even elect this guy to be the * sync site. * * After that, the recovery process does nothing until the beacon and * voting modules manage to get this site elected sync site. * * After becoming sync site, recovery first attempts to find the best * database available in the network (it must do this in order to * ensure finding the latest committed data). After finding the right * database, it must fetch this dbase to the sync site. * * After fetching the dbase, it relabels it with a new version number, * to ensure that everyone recognizes this dbase as the most recent * dbase. * * One the dbase has been relabelled, this machine can start handling * requests. However, the recovery module still has one more task: * propagating the dbase out to everyone who is up in the network. */ void * urecovery_Interact(void *dummy) { afs_int32 code, tcode; struct ubik_server *bestServer = NULL; struct ubik_server *ts; int dbok, doingRPC, now; afs_int32 lastProbeTime; /* if we're the sync site, the best db version we've found yet */ static struct ubik_version bestDBVersion; struct ubik_version tversion; struct timeval tv; int length, tlen, offset, file, nbytes; struct rx_call *rxcall; char tbuffer[1024]; struct ubik_stat ubikstat; struct in_addr inAddr; char hoststr[16]; char pbuffer[1028]; int fd = -1; afs_int32 pass; afs_pthread_setname_self("recovery"); /* otherwise, begin interaction */ urecovery_state = 0; lastProbeTime = 0; while (1) { /* Run through this loop every 4 seconds */ tv.tv_sec = 4; tv.tv_usec = 0; #ifdef AFS_PTHREAD_ENV select(0, 0, 0, 0, &tv); #else IOMGR_Select(0, 0, 0, 0, &tv); #endif ubik_dprint("recovery running in state %x\n", urecovery_state); /* Every 30 seconds, check all the down servers and mark them * as up if they respond. When a server comes up or found to * not be current, then re-find the the best database and * propogate it. */ if ((now = FT_ApproxTime()) > 30 + lastProbeTime) { for (ts = ubik_servers, doingRPC = 0; ts; ts = ts->next) { UBIK_BEACON_LOCK; if (!ts->up) { UBIK_BEACON_UNLOCK; doingRPC = 1; code = DoProbe(ts); if (code == 0) { UBIK_BEACON_LOCK; ts->up = 1; UBIK_BEACON_UNLOCK; DBHOLD(ubik_dbase); urecovery_state &= ~UBIK_RECFOUNDDB; DBRELE(ubik_dbase); } } else { UBIK_BEACON_UNLOCK; DBHOLD(ubik_dbase); if (!ts->currentDB) urecovery_state &= ~UBIK_RECFOUNDDB; DBRELE(ubik_dbase); } } if (doingRPC) now = FT_ApproxTime(); lastProbeTime = now; } /* Mark whether we are the sync site */ DBHOLD(ubik_dbase); if (!ubeacon_AmSyncSite()) { urecovery_state &= ~UBIK_RECSYNCSITE; DBRELE(ubik_dbase); continue; /* nothing to do */ } urecovery_state |= UBIK_RECSYNCSITE; /* If a server has just come up or if we have not found the * most current database, then go find the most current db. */ if (!(urecovery_state & UBIK_RECFOUNDDB)) { DBRELE(ubik_dbase); bestServer = (struct ubik_server *)0; bestDBVersion.epoch = 0; bestDBVersion.counter = 0; for (ts = ubik_servers; ts; ts = ts->next) { UBIK_BEACON_LOCK; if (!ts->up) { UBIK_BEACON_UNLOCK; continue; /* don't bother with these guys */ } UBIK_BEACON_UNLOCK; if (ts->isClone) continue; UBIK_ADDR_LOCK; code = DISK_GetVersion(ts->disk_rxcid, &ts->version); UBIK_ADDR_UNLOCK; if (code == 0) { /* perhaps this is the best version */ if (vcmp(ts->version, bestDBVersion) > 0) { /* new best version */ bestDBVersion = ts->version; bestServer = ts; } } } /* take into consideration our version. Remember if we, * the sync site, have the best version. Also note that * we may need to send the best version out. */ DBHOLD(ubik_dbase); if (vcmp(ubik_dbase->version, bestDBVersion) >= 0) { bestDBVersion = ubik_dbase->version; bestServer = (struct ubik_server *)0; urecovery_state |= UBIK_RECHAVEDB; } else { /* Clear the flag only when we know we have to retrieve * the db. Because urecovery_AllBetter() looks at it. */ urecovery_state &= ~UBIK_RECHAVEDB; } urecovery_state |= UBIK_RECFOUNDDB; urecovery_state &= ~UBIK_RECSENTDB; } if (!(urecovery_state & UBIK_RECFOUNDDB)) { DBRELE(ubik_dbase); continue; /* not ready */ } /* If we, the sync site, do not have the best db version, then * go and get it from the server that does. */ if ((urecovery_state & UBIK_RECHAVEDB) || !bestServer) { urecovery_state |= UBIK_RECHAVEDB; } else { /* we don't have the best version; we should fetch it. */ urecovery_AbortAll(ubik_dbase); /* Rx code to do the Bulk fetch */ file = 0; offset = 0; UBIK_ADDR_LOCK; rxcall = rx_NewCall(bestServer->disk_rxcid); ubik_print("Ubik: Synchronize database with server %s\n", afs_inet_ntoa_r(bestServer->addr[0], hoststr)); UBIK_ADDR_UNLOCK; code = StartDISK_GetFile(rxcall, file); if (code) { ubik_dprint("StartDiskGetFile failed=%d\n", code); goto FetchEndCall; } nbytes = rx_Read(rxcall, (char *)&length, sizeof(afs_int32)); length = ntohl(length); if (nbytes != sizeof(afs_int32)) { ubik_dprint("Rx-read length error=%d\n", code = BULK_ERROR); code = EIO; goto FetchEndCall; } /* give invalid label during file transit */ UBIK_VERSION_LOCK; tversion.epoch = 0; code = (*ubik_dbase->setlabel) (ubik_dbase, file, &tversion); UBIK_VERSION_UNLOCK; if (code) { ubik_dprint("setlabel io error=%d\n", code); goto FetchEndCall; } snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d.TMP", ubik_dbase->pathName, (file<0)?"SYS":"", (file<0)?-file:file); fd = open(pbuffer, O_CREAT | O_RDWR | O_TRUNC, 0600); if (fd < 0) { code = errno; goto FetchEndCall; } code = lseek(fd, HDRSIZE, 0); if (code != HDRSIZE) { close(fd); goto FetchEndCall; } pass = 0; while (length > 0) { tlen = (length > sizeof(tbuffer) ? sizeof(tbuffer) : length); #ifndef AFS_PTHREAD_ENV if (pass % 4 == 0) IOMGR_Poll(); #endif nbytes = rx_Read(rxcall, tbuffer, tlen); if (nbytes != tlen) { ubik_dprint("Rx-read bulk error=%d\n", code = BULK_ERROR); code = EIO; close(fd); goto FetchEndCall; } nbytes = write(fd, tbuffer, tlen); pass++; if (nbytes != tlen) { code = UIOERROR; close(fd); goto FetchEndCall; } offset += tlen; length -= tlen; } code = close(fd); if (code) goto FetchEndCall; code = EndDISK_GetFile(rxcall, &tversion); FetchEndCall: tcode = rx_EndCall(rxcall, code); if (!code) code = tcode; if (!code) { /* we got a new file, set up its header */ urecovery_state |= UBIK_RECHAVEDB; UBIK_VERSION_LOCK; memcpy(&ubik_dbase->version, &tversion, sizeof(struct ubik_version)); snprintf(tbuffer, sizeof(tbuffer), "%s.DB%s%d", ubik_dbase->pathName, (file<0)?"SYS":"", (file<0)?-file:file); #ifdef AFS_NT40_ENV snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d.OLD", ubik_dbase->pathName, (file<0)?"SYS":"", (file<0)?-file:file); code = unlink(pbuffer); if (!code) code = rename(tbuffer, pbuffer); snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d.TMP", ubik_dbase->pathName, (file<0)?"SYS":"", (file<0)?-file:file); #endif if (!code) code = rename(pbuffer, tbuffer); if (!code) { (*ubik_dbase->open) (ubik_dbase, file); /* after data is good, sync disk with correct label */ code = (*ubik_dbase->setlabel) (ubik_dbase, 0, &ubik_dbase->version); } UBIK_VERSION_UNLOCK; #ifdef AFS_NT40_ENV snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d.OLD", ubik_dbase->pathName, (file<0)?"SYS":"", (file<0)?-file:file); unlink(pbuffer); #endif } if (code) { unlink(pbuffer); /* * We will effectively invalidate the old data forever now. * Unclear if we *should* but we do. */ UBIK_VERSION_LOCK; ubik_dbase->version.epoch = 0; ubik_dbase->version.counter = 0; UBIK_VERSION_UNLOCK; ubik_print("Ubik: Synchronize database failed (error = %d)\n", code); } else { ubik_print("Ubik: Synchronize database completed\n"); urecovery_state |= UBIK_RECHAVEDB; } udisk_Invalidate(ubik_dbase, 0); /* data has changed */ #ifdef AFS_PTHREAD_ENV CV_BROADCAST(&ubik_dbase->version_cond); #else LWP_NoYieldSignal(&ubik_dbase->version); #endif } if (!(urecovery_state & UBIK_RECHAVEDB)) { DBRELE(ubik_dbase); continue; /* not ready */ } /* If the database was newly initialized, then when we establish quorum, write * a new label. This allows urecovery_AllBetter() to allow access for reads. * Setting it to 2 also allows another site to come along with a newer * database and overwrite this one. */ if (ubik_dbase->version.epoch == 1) { urecovery_AbortAll(ubik_dbase); UBIK_VERSION_LOCK; version_globals.ubik_epochTime = 2; ubik_dbase->version.epoch = version_globals.ubik_epochTime; ubik_dbase->version.counter = 1; code = (*ubik_dbase->setlabel) (ubik_dbase, 0, &ubik_dbase->version); UBIK_VERSION_UNLOCK; udisk_Invalidate(ubik_dbase, 0); /* data may have changed */ #ifdef AFS_PTHREAD_ENV CV_BROADCAST(&ubik_dbase->version_cond); #else LWP_NoYieldSignal(&ubik_dbase->version); #endif } /* Check the other sites and send the database to them if they * do not have the current db. */ if (!(urecovery_state & UBIK_RECSENTDB)) { /* now propagate out new version to everyone else */ dbok = 1; /* start off assuming they all worked */ /* * Check if a write transaction is in progress. We can't send the * db when a write is in progress here because the db would be * obsolete as soon as it goes there. Also, ops after the begin * trans would reach the recepient and wouldn't find a transaction * pending there. Frankly, I don't think it's possible to get past * the write-lock above if there is a write transaction in progress, * but then, it won't hurt to check, will it? */ if (ubik_dbase->flags & DBWRITING) { struct timeval tv; int safety = 0; long cur_usec = 50000; while ((ubik_dbase->flags & DBWRITING) && (safety < 500)) { DBRELE(ubik_dbase); /* sleep for a little while */ tv.tv_sec = 0; tv.tv_usec = cur_usec; #ifdef AFS_PTHREAD_ENV select(0, 0, 0, 0, &tv); #else IOMGR_Select(0, 0, 0, 0, &tv); #endif cur_usec += 10000; safety++; DBHOLD(ubik_dbase); } } for (ts = ubik_servers; ts; ts = ts->next) { UBIK_ADDR_LOCK; inAddr.s_addr = ts->addr[0]; UBIK_ADDR_UNLOCK; UBIK_BEACON_LOCK; if (!ts->up) { UBIK_BEACON_UNLOCK; ubik_dprint("recovery cannot send version to %s\n", afs_inet_ntoa_r(inAddr.s_addr, hoststr)); dbok = 0; continue; } UBIK_BEACON_UNLOCK; ubik_dprint("recovery sending version to %s\n", afs_inet_ntoa_r(inAddr.s_addr, hoststr)); if (vcmp(ts->version, ubik_dbase->version) != 0) { ubik_dprint("recovery stating local database\n"); /* Rx code to do the Bulk Store */ code = (*ubik_dbase->stat) (ubik_dbase, 0, &ubikstat); if (!code) { length = ubikstat.size; file = offset = 0; UBIK_ADDR_LOCK; rxcall = rx_NewCall(ts->disk_rxcid); UBIK_ADDR_UNLOCK; code = StartDISK_SendFile(rxcall, file, length, &ubik_dbase->version); if (code) { ubik_dprint("StartDiskSendFile failed=%d\n", code); goto StoreEndCall; } while (length > 0) { tlen = (length > sizeof(tbuffer) ? sizeof(tbuffer) : length); nbytes = (*ubik_dbase->read) (ubik_dbase, file, tbuffer, offset, tlen); if (nbytes != tlen) { ubik_dprint("Local disk read error=%d\n", code = UIOERROR); goto StoreEndCall; } nbytes = rx_Write(rxcall, tbuffer, tlen); if (nbytes != tlen) { ubik_dprint("Rx-write bulk error=%d\n", code = BULK_ERROR); goto StoreEndCall; } offset += tlen; length -= tlen; } code = EndDISK_SendFile(rxcall); StoreEndCall: code = rx_EndCall(rxcall, code); } if (code == 0) { /* we set a new file, process its header */ ts->version = ubik_dbase->version; ts->currentDB = 1; } else dbok = 0; } else { /* mark file up to date */ ts->currentDB = 1; } } if (dbok) urecovery_state |= UBIK_RECSENTDB; } DBRELE(ubik_dbase); } return NULL; }
//----------------------------------------------------------------------------- // Purpose: // Input : flInterval - // &m_LastMoveTarget - // eMoveType - //----------------------------------------------------------------------------- void CNPC_Ichthyosaur::DoMovement( float flInterval, const Vector &MoveTarget, int eMoveType ) { // dvs: something is setting this bit, causing us to stop moving and get stuck that way Forget( bits_MEMORY_TURNING ); Vector Steer, SteerAvoid, SteerRel; Vector forward, right, up; //Get our orientation vectors. GetVectors( &forward, &right, &up); if ( ( GetActivity() == ACT_MELEE_ATTACK1 ) && ( GetEnemy() != NULL ) ) { SteerSeek( Steer, GetEnemy()->GetAbsOrigin() ); } else { //If we are approaching our goal, use an arrival steering mechanism. if ( eMoveType == ICH_MOVETYPE_ARRIVE ) { SteerArrive( Steer, MoveTarget ); } else { //Otherwise use a seek steering mechanism. SteerSeek( Steer, MoveTarget ); } } #if FEELER_COLLISION Vector f, u, l, r, d; float probeLength = GetAbsVelocity().Length(); if ( probeLength < 150 ) probeLength = 150; if ( probeLength > 500 ) probeLength = 500; f = DoProbe( GetLocalOrigin() + (probeLength * forward) ); r = DoProbe( GetLocalOrigin() + (probeLength/3 * (forward+right)) ); l = DoProbe( GetLocalOrigin() + (probeLength/3 * (forward-right)) ); u = DoProbe( GetLocalOrigin() + (probeLength/3 * (forward+up)) ); d = DoProbe( GetLocalOrigin() + (probeLength/3 * (forward-up)) ); SteerAvoid = f+r+l+u+d; //NDebugOverlay::Line( GetLocalOrigin(), GetLocalOrigin()+SteerAvoid, 255, 255, 0, false, 0.1f ); if ( SteerAvoid.LengthSqr() ) { Steer = (SteerAvoid*0.5f); } m_vecVelocity = m_vecVelocity + (Steer*0.5f); VectorNormalize( m_vecVelocity ); SteerRel.x = forward.Dot( m_vecVelocity ); SteerRel.y = right.Dot( m_vecVelocity ); SteerRel.z = up.Dot( m_vecVelocity ); m_vecVelocity *= m_flGroundSpeed; #else //See if we need to avoid any obstacles. if ( SteerAvoidObstacles( SteerAvoid, GetAbsVelocity(), forward, right, up ) ) { //Take the avoidance vector Steer = SteerAvoid; } //Clamp our ideal steering vector to within our physical limitations. ClampSteer( Steer, SteerRel, forward, right, up ); ApplyAbsVelocityImpulse( Steer * flInterval ); #endif Vector vecNewVelocity = GetAbsVelocity(); float flLength = vecNewVelocity.Length(); //Clamp our final speed if ( flLength > m_flGroundSpeed ) { vecNewVelocity *= ( m_flGroundSpeed / flLength ); flLength = m_flGroundSpeed; } Vector workVelocity = vecNewVelocity; AddSwimNoise( &workVelocity ); // Pose the fish properly SetPoses( SteerRel, flLength ); //Drag our victim before moving if ( m_pVictim != NULL ) { DragVictim( (workVelocity*flInterval).Length() ); } //Move along the current velocity vector if ( WalkMove( workVelocity * flInterval, MASK_NPCSOLID ) == false ) { //Attempt a half-step if ( WalkMove( (workVelocity*0.5f) * flInterval, MASK_NPCSOLID) == false ) { //Restart the velocity //VectorNormalize( m_vecVelocity ); vecNewVelocity *= 0.5f; } else { //Cut our velocity in half vecNewVelocity *= 0.5f; } } SetAbsVelocity( vecNewVelocity ); }
void CIchthyosaur::Swim( ) { int retValue = 0; Vector start = pev->origin; Vector Angles; Vector Forward, Right, Up; if (FBitSet( pev->flags, FL_ONGROUND)) { pev->angles.x = 0; pev->angles.y += RANDOM_FLOAT( -45, 45 ); ClearBits( pev->flags, FL_ONGROUND ); Angles = Vector( -pev->angles.x, pev->angles.y, pev->angles.z ); UTIL_MakeVectorsPrivate(Angles, Forward, Right, Up); pev->velocity = Forward * 200 + Up * 200; return; } if (m_bOnAttack && m_flightSpeed < m_flMaxSpeed) { m_flightSpeed += 40; } if (m_flightSpeed < 180) { if (m_IdealActivity == ACT_RUN) SetActivity( ACT_WALK ); if (m_IdealActivity == ACT_WALK) pev->framerate = m_flightSpeed / 150.0; // ALERT( at_console, "walk %.2f\n", pev->framerate ); } else { if (m_IdealActivity == ACT_WALK) SetActivity( ACT_RUN ); if (m_IdealActivity == ACT_RUN) pev->framerate = m_flightSpeed / 150.0; // ALERT( at_console, "run %.2f\n", pev->framerate ); } /* if (!m_pBeam) { m_pBeam = CBeam::BeamCreate( "sprites/laserbeam.spr", 80 ); m_pBeam->PointEntInit( pev->origin + m_SaveVelocity, entindex( ) ); m_pBeam->SetEndAttachment( 1 ); m_pBeam->SetColor( 255, 180, 96 ); m_pBeam->SetBrightness( 192 ); } */ #define PROBE_LENGTH 150 Angles = UTIL_VecToAngles( m_SaveVelocity ); Angles.x = -Angles.x; UTIL_MakeVectorsPrivate(Angles, Forward, Right, Up); Vector f, u, l, r, d; f = DoProbe(start + PROBE_LENGTH * Forward); r = DoProbe(start + PROBE_LENGTH/3 * Forward+Right); l = DoProbe(start + PROBE_LENGTH/3 * Forward-Right); u = DoProbe(start + PROBE_LENGTH/3 * Forward+Up); d = DoProbe(start + PROBE_LENGTH/3 * Forward-Up); Vector SteeringVector = f+r+l+u+d; m_SaveVelocity = (m_SaveVelocity + SteeringVector/2).Normalize(); Angles = Vector( -pev->angles.x, pev->angles.y, pev->angles.z ); UTIL_MakeVectorsPrivate(Angles, Forward, Right, Up); // ALERT( at_console, "%f : %f\n", Angles.x, Forward.z ); float flDot = DotProduct( Forward, m_SaveVelocity ); if (flDot > 0.5) pev->velocity = m_SaveVelocity = m_SaveVelocity * m_flightSpeed; else if (flDot > 0) pev->velocity = m_SaveVelocity = m_SaveVelocity * m_flightSpeed * (flDot + 0.5); else pev->velocity = m_SaveVelocity = m_SaveVelocity * 80; // ALERT( at_console, "%.0f %.0f\n", m_flightSpeed, pev->velocity.Length() ); // ALERT( at_console, "Steer %f %f %f\n", SteeringVector.x, SteeringVector.y, SteeringVector.z ); /* m_pBeam->SetStartPos( pev->origin + pev->velocity ); m_pBeam->RelinkBeam( ); */ // ALERT( at_console, "speed %f\n", m_flightSpeed ); Angles = UTIL_VecToAngles( m_SaveVelocity ); // Smooth Pitch // if (Angles.x > 180) Angles.x = Angles.x - 360; pev->angles.x = UTIL_Approach(Angles.x, pev->angles.x, 50 * 0.1 ); if (pev->angles.x < -80) pev->angles.x = -80; if (pev->angles.x > 80) pev->angles.x = 80; // Smooth Yaw and generate Roll // float turn = 360; // ALERT( at_console, "Y %.0f %.0f\n", Angles.y, pev->angles.y ); if (fabs(Angles.y - pev->angles.y) < fabs(turn)) { turn = Angles.y - pev->angles.y; } if (fabs(Angles.y - pev->angles.y + 360) < fabs(turn)) { turn = Angles.y - pev->angles.y + 360; } if (fabs(Angles.y - pev->angles.y - 360) < fabs(turn)) { turn = Angles.y - pev->angles.y - 360; } float speed = m_flightSpeed * 0.1; // ALERT( at_console, "speed %.0f %f\n", turn, speed ); if (fabs(turn) > speed) { if (turn < 0.0) { turn = -speed; } else { turn = speed; } } pev->angles.y += turn; pev->angles.z -= turn; pev->angles.y = fmod((pev->angles.y + 360.0), 360.0); static float yaw_adj; yaw_adj = yaw_adj * 0.8 + turn; // ALERT( at_console, "yaw %f : %f\n", turn, yaw_adj ); SetBoneController( 0, -yaw_adj / 4.0 ); // Roll Smoothing // turn = 360; if (fabs(Angles.z - pev->angles.z) < fabs(turn)) { turn = Angles.z - pev->angles.z; } if (fabs(Angles.z - pev->angles.z + 360) < fabs(turn)) { turn = Angles.z - pev->angles.z + 360; } if (fabs(Angles.z - pev->angles.z - 360) < fabs(turn)) { turn = Angles.z - pev->angles.z - 360; } speed = m_flightSpeed/2 * 0.1; if (fabs(turn) < speed) { pev->angles.z += turn; } else { if (turn < 0.0) { pev->angles.z -= speed; } else { pev->angles.z += speed; } } if (pev->angles.z < -20) pev->angles.z = -20; if (pev->angles.z > 20) pev->angles.z = 20; UTIL_MakeVectorsPrivate( Vector( -Angles.x, Angles.y, Angles.z ), Forward, Right, Up); // UTIL_MoveToOrigin ( ENT(pev), pev->origin + Forward * speed, speed, MOVE_STRAFE ); }