private void StartForeignRequest( TrackerStateHolder trackerStateHolder ) { LocationRequest locationRequest = PrepareLocationRequest( trackerStateHolder ); if ( locationRequest == null ) return; try { if ( !HolderRwLock.TryEnterWriteLock( ) ) { Log.ErrorFormat( "Can't enter write mode in BeginRequest for {0}", trackerStateHolder.ForeignId ); return; } try { trackerStateHolder.CurrentRequest = locationRequest; trackerStateHolder.RequestStartTime = TimeService.Now; } finally { HolderRwLock.ExitWriteLock( ); } // Despite TrackerStateHolder having CurrentRequest field, locationRequest still need to // be passed as an implicit parameter because there is no guarantee that at the moment when // OnEndReadLocation is called there will be no other request started. E.g. this request // can be stuck, aborted by timeout, and then suddenly pop in again in OnEndReadLocation. // It's unlikely but still possible. So pass locationRequest to avoid any chance that // EndReadLocation is called on wrong locationRequest. Tuple<TrackerStateHolder, LocationRequest> paramTuple = new Tuple<TrackerStateHolder, LocationRequest>( trackerStateHolder, locationRequest ); DateTime requestStart = TimeService.Now; locationRequest.BeginReadLocation( OnEndReadLocation, paramTuple ); this.statistics.AddRequestStartEvent( trackerStateHolder.ForeignId, requestStart ); } catch { this.statistics.AddRequestErrorEvent(trackerStateHolder.ForeignId.Type); trackerStateHolder.CurrentRequest = null; // no-good => no CurrentRequest, no setting ScheduledTime to null. throw; } Thread.MemoryBarrier( ); // set ScheduledTime only _after_ successful BeginReadLocation. trackerStateHolder.ScheduledTime = null; }
private static int CompareHolders( TrackerStateHolder x, TrackerStateHolder y ) { bool areEqual; TrackerStateHolder moreStale = Scheduler.GetMoreStaleTracker( x, y, out areEqual ); if ( areEqual ) return string.Compare( x.ForeignId.Id, y.ForeignId.Id, StringComparison.InvariantCultureIgnoreCase ); if ( ReferenceEquals( moreStale, x ) ) return -1; return 1; }
private LocationRequest PrepareLocationRequest( TrackerStateHolder trackerStateHolder ) { LocationRequestFactory requestFactory = ForeignAccessCentral.LocationRequestFactories[trackerStateHolder.ForeignId.Type]; RequestParams requestParams; requestParams.Id = trackerStateHolder.ForeignId.Id; // Read lock needed to read trackerStateHolder.Snapshot.Position if ( !HolderRwLock.TryEnterReadLock( ) ) { Log.ErrorFormat( "Can't enter read mode in PrepareLocationRequest for {0}", trackerStateHolder.ForeignId ); return null; } try { // Potentially, the snapshot with the existing track might change while the new data is being requested. // But it's not a problem because the old track is valid anyway - to make sure that, the requesting // algorithm will check if the old track's starting section matches new data loaded from the foreign // system. So existing track (most probably its trailing points) would be in use anyway. if ( trackerStateHolder.Snapshot == null || trackerStateHolder.Snapshot.Position == null ) { requestParams.ExistingTrack = null; } else { requestParams.ExistingTrack = trackerStateHolder.Snapshot.Position.FullTrack; } } finally { HolderRwLock.ExitReadLock( ); } return requestFactory.CreateRequest( requestParams ); }