func (sub *Sub) poll(srpcClient *srpc.Client, previousStatus subStatus) { // If the planned image has just become available, force a full poll. if previousStatus == statusSynced && !sub.havePlannedImage && sub.herd.getImage(sub.plannedImage) != nil { sub.havePlannedImage = true sub.generationCount = 0 // Force a full poll. } var request subproto.PollRequest request.HaveGeneration = sub.generationCount var reply subproto.PollResponse sub.lastPollStartTime = time.Now() logger := sub.herd.logger if err := client.CallPoll(srpcClient, request, &reply); err != nil { sub.status = statusFailedToPoll logger.Printf("Error calling %s.Poll()\t%s\n", sub.hostname, err) return } sub.lastPollSucceededTime = time.Now() if reply.GenerationCount == 0 { sub.reclaim() sub.generationCount = 0 } if fs := reply.FileSystem; fs == nil { sub.lastShortPollDuration = sub.lastPollSucceededTime.Sub(sub.lastPollStartTime) shortPollDistribution.Add(sub.lastShortPollDuration) } else { if err := fs.RebuildInodePointers(); err != nil { sub.status = statusFailedToPoll logger.Printf("Error building pointers for: %s %s\n", sub.hostname, err) return } fs.BuildInodeToFilenamesTable() fs.BuildEntryMap() sub.fileSystem = fs sub.objectCache = reply.ObjectCache sub.generationCount = reply.GenerationCount sub.lastFullPollDuration = sub.lastPollSucceededTime.Sub(sub.lastPollStartTime) fullPollDistribution.Add(sub.lastFullPollDuration) logger.Printf("Polled: %s, GenerationCount=%d\n", sub.hostname, reply.GenerationCount) } if reply.FetchInProgress { sub.status = statusFetching return } if reply.UpdateInProgress { sub.status = statusUpdating return } if sub.generationCount < 1 { sub.status = statusSubNotReady return } if sub.fileSystem == nil { sub.status = previousStatus if previousStatus != statusSynced { // Force a full poll next cycle so that we can see the state of the // sub and recompute/retry what needs to be done. sub.generationCount = 0 } return } if idle, status := sub.fetchMissingObjects(srpcClient, sub.requiredImage); !idle { sub.status = status sub.reclaim() return } sub.status = statusComputingUpdate if idle, status := sub.sendUpdate(srpcClient); !idle { sub.status = status sub.reclaim() return } if idle, status := sub.fetchMissingObjects(srpcClient, sub.plannedImage); !idle { if status != statusImageNotReady { sub.status = status sub.reclaim() return } } sub.status = statusSynced sub.cleanup(srpcClient, sub.plannedImage) sub.reclaim() }
func (sub *Sub) poll(connection *rpc.Client) { var request subproto.PollRequest request.HaveGeneration = sub.generationCount var reply subproto.PollResponse sub.lastPollStartTime = time.Now() err := connection.Call("Subd.Poll", request, &reply) logger := sub.herd.logger if err != nil { sub.status = statusFailedToPoll logger.Printf("Error calling %s.Poll()\t%s\n", sub.hostname, err) return } sub.lastPollSucceededTime = time.Now() if reply.GenerationCount == 0 { sub.fileSystem = nil sub.generationCount = 0 } if fs := reply.FileSystem; fs == nil { sub.lastShortPollDuration = sub.lastPollSucceededTime.Sub(sub.lastPollStartTime) } else { fs.RebuildInodePointers() fs.BuildEntryMap() sub.fileSystem = fs sub.generationCount = reply.GenerationCount sub.lastFullPollDuration = sub.lastPollSucceededTime.Sub(sub.lastPollStartTime) // TODO(rgooch): Remove debugging output. fmt.Printf("Polled: %s, GenerationCount=%d\n", sub.hostname, reply.GenerationCount) } if sub.fileSystem == nil { sub.status = statusSubNotReady return } if reply.FetchInProgress { sub.status = statusFetching return } if reply.UpdateInProgress { sub.status = statusUpdating return } if sub.generationCountAtChangeStart == sub.generationCount { sub.status = statusWaitingForNextPoll return } if idle, status := sub.fetchMissingObjects(connection, sub.requiredImage); !idle { sub.status = status return } if idle, status := sub.sendUpdate(connection); !idle { sub.status = status return } if idle, status := sub.fetchMissingObjects(connection, sub.plannedImage); !idle { sub.status = status return } sub.status = statusSynced }
func (sub *Sub) poll(srpcClient *srpc.Client, previousStatus subStatus) { // If the planned image has just become available, force a full poll. if previousStatus == statusSynced && !sub.havePlannedImage && sub.plannedImage != nil { sub.havePlannedImage = true sub.generationCount = 0 // Force a full poll. } // If the computed files have changed since the last sync, force a full poll if previousStatus == statusSynced && sub.computedFilesChangeTime.After(sub.lastSyncTime) { sub.generationCount = 0 // Force a full poll. } // If the last update was disabled and updates are enabled now, force a full // poll. if previousStatus == statusUpdatesDisabled && sub.herd.updatesDisabledReason == "" && !sub.mdb.DisableUpdates { sub.generationCount = 0 // Force a full poll. } // If the last update was disabled due to a safety check and there is a // pending SafetyClear, force a full poll to re-compute the update. if previousStatus == statusUnsafeUpdate && sub.pendingSafetyClear { sub.generationCount = 0 // Force a full poll. } var request subproto.PollRequest request.HaveGeneration = sub.generationCount var reply subproto.PollResponse haveImage := false if sub.requiredImage == nil { request.ShortPollOnly = true } else { haveImage = true } logger := sub.herd.logger sub.lastPollStartTime = time.Now() if err := client.CallPoll(srpcClient, request, &reply); err != nil { srpcClient.Close() if err == io.EOF { return } sub.pollTime = time.Time{} if err == srpc.ErrorAccessToMethodDenied { sub.status = statusPollDenied } else { sub.status = statusFailedToPoll } logger.Printf("Error calling %s.Poll(): %s\n", sub, err) return } sub.lastPollSucceededTime = time.Now() sub.lastSuccessfulImageName = reply.LastSuccessfulImageName if reply.GenerationCount == 0 { sub.reclaim() sub.generationCount = 0 } sub.lastScanDuration = reply.DurationOfLastScan if fs := reply.FileSystem; fs == nil { sub.lastPollWasFull = false sub.lastShortPollDuration = sub.lastPollSucceededTime.Sub(sub.lastPollStartTime) shortPollDistribution.Add(sub.lastShortPollDuration) if !sub.startTime.Equal(reply.StartTime) { sub.generationCount = 0 // Sub has restarted: force a full poll. } } else { sub.lastPollWasFull = true if err := fs.RebuildInodePointers(); err != nil { sub.status = statusFailedToPoll logger.Printf("Error building pointers for: %s %s\n", sub, err) return } fs.BuildEntryMap() sub.fileSystem = fs sub.objectCache = reply.ObjectCache sub.generationCount = reply.GenerationCount sub.lastFullPollDuration = sub.lastPollSucceededTime.Sub(sub.lastPollStartTime) fullPollDistribution.Add(sub.lastFullPollDuration) } sub.startTime = reply.StartTime sub.pollTime = reply.PollTime sub.updateConfiguration(srpcClient, reply) if reply.FetchInProgress { sub.status = statusFetching return } if reply.UpdateInProgress { sub.status = statusUpdating return } if reply.GenerationCount < 1 { sub.status = statusSubNotReady return } if previousStatus == statusFetching && reply.LastFetchError != "" { logger.Printf("Fetch failure for: %s: %s\n", sub, reply.LastFetchError) sub.status = statusFailedToFetch if sub.fileSystem == nil { sub.generationCount = 0 // Force a full poll next cycle. return } } if previousStatus == statusUpdating { // Transition from updating to update ended (may be partial/failed). if reply.LastUpdateError != "" { logger.Printf("Update failure for: %s: %s\n", sub, reply.LastUpdateError) sub.status = statusFailedToUpdate } else { sub.status = statusWaitingForNextFullPoll } sub.scanCountAtLastUpdateEnd = reply.ScanCount sub.reclaim() return } if sub.checkCancel() { // Configuration change pending: skip further processing. Do not reclaim // file-system and objectcache data: it will speed up the next Poll. return } if !haveImage { if sub.requiredImageName == "" { sub.status = statusImageUndefined } else { sub.status = statusImageNotReady } return } if previousStatus == statusFailedToUpdate || previousStatus == statusWaitingForNextFullPoll { if sub.scanCountAtLastUpdateEnd == reply.ScanCount { // Need to wait until sub has performed a new scan. if sub.fileSystem != nil { sub.reclaim() } sub.status = previousStatus return } if sub.fileSystem == nil { // Force a full poll next cycle so that we can see the state of the // sub. sub.generationCount = 0 sub.status = previousStatus return } } if sub.fileSystem == nil { sub.status = previousStatus return } if idle, status := sub.fetchMissingObjects(srpcClient, sub.requiredImage, true); !idle { sub.status = status sub.reclaim() return } sub.status = statusComputingUpdate if idle, status := sub.sendUpdate(srpcClient); !idle { sub.status = status sub.reclaim() return } if idle, status := sub.fetchMissingObjects(srpcClient, sub.plannedImage, false); !idle { if status != statusImageNotReady { sub.status = status sub.reclaim() return } } if previousStatus == statusWaitingForNextFullPoll && !sub.lastUpdateTime.IsZero() { sub.lastSyncTime = time.Now() } sub.status = statusSynced sub.cleanup(srpcClient) sub.reclaim() }
func (sub *Sub) poll(connection *rpc.Client) { var request subproto.PollRequest request.HaveGeneration = sub.generationCount var reply subproto.PollResponse sub.lastPollStartTime = time.Now() logger := sub.herd.logger if err := connection.Call("Subd.Poll", request, &reply); err != nil { sub.status = statusFailedToPoll logger.Printf("Error calling %s.Poll()\t%s\n", sub.hostname, err) return } sub.lastPollSucceededTime = time.Now() if reply.GenerationCount == 0 { sub.fileSystem = nil sub.generationCount = 0 } if fs := reply.FileSystem; fs == nil { sub.lastShortPollDuration = sub.lastPollSucceededTime.Sub(sub.lastPollStartTime) shortPollDistribution.Add(sub.lastShortPollDuration) } else { if err := fs.RebuildInodePointers(); err != nil { sub.status = statusFailedToPoll logger.Printf("Error building pointers for: %s %s\n", sub.hostname, err) return } fs.BuildInodeToFilenamesTable() fs.BuildEntryMap() sub.fileSystem = fs sub.generationCount = reply.GenerationCount sub.lastFullPollDuration = sub.lastPollSucceededTime.Sub(sub.lastPollStartTime) fullPollDistribution.Add(sub.lastFullPollDuration) logger.Printf("Polled: %s, GenerationCount=%d\n", sub.hostname, reply.GenerationCount) } if sub.fileSystem == nil { sub.status = statusSubNotReady return } if reply.FetchInProgress { sub.status = statusFetching return } if reply.UpdateInProgress { sub.status = statusUpdating return } if sub.generationCountAtLastSync == sub.generationCount { sub.status = statusSynced return } if sub.generationCountAtChangeStart == sub.generationCount { sub.status = statusWaitingForNextPoll return } if idle, status := sub.fetchMissingObjects(connection, sub.requiredImage); !idle { sub.status = status return } sub.status = statusComputingUpdate if idle, status := sub.sendUpdate(connection); !idle { sub.status = status return } if idle, status := sub.fetchMissingObjects(connection, sub.plannedImage); !idle { if status != statusImageNotReady { sub.status = status return } } sub.status = statusSynced sub.cleanup(connection, sub.plannedImage) sub.generationCountAtLastSync = sub.generationCount }