blob: 4153d7f5c50814d4b3c995c56a750ec98fc9e174 [file] [log] [blame] [edit]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/uploader/upload_scheduler.h"
#include "src/public/lib/status.h"
#include "src/public/lib/statusor/statusor.h"
namespace cobalt::uploader {
// Definition of the static constant declared in shipping_manager.h.
// This must be less than 2^31. There appears to be a bug in
// std::condition_variable::wait_for() in which setting the wait time to
// std::chrono::seconds::max() effectively sets the wait time to zero.
constexpr std::chrono::seconds UploadScheduler::kMaxSeconds(999999999);
lib::statusor::StatusOr<UploadScheduler> UploadScheduler::Create(UploadScheduleConfig cfg) {
if (cfg.jitter < 0.0 || cfg.jitter >= 1.0) {
return Status(StatusCode::INVALID_ARGUMENT, "Jitter must be in the range [0.0, 1.0)");
}
if (cfg.min_interval.count() < 0) {
return Status(StatusCode::INVALID_ARGUMENT,
"min_interval must be greater than or equal to zero");
}
if (cfg.initial_interval.count() > cfg.target_interval.count()) {
return Status(StatusCode::INVALID_ARGUMENT,
"initial_interval must be less than or equal to target_interval");
}
if (cfg.min_interval.count() > cfg.target_interval.count()) {
return Status(StatusCode::INVALID_ARGUMENT,
"min_interval must be less than or equal to target_interval");
}
if (cfg.target_interval.count() > kMaxSeconds.count()) {
return Status(StatusCode::INVALID_ARGUMENT, "target_interval must be less than kMaxSeconds");
}
return UploadScheduler(cfg);
}
UploadScheduler::UploadScheduler(UploadScheduleConfig config)
: current_interval_(config.initial_interval),
target_interval_(config.target_interval),
min_interval_(config.min_interval),
jitter_(config.jitter) {}
std::chrono::seconds UploadScheduler::Interval() {
auto interval = current_interval_;
if (current_interval_ < target_interval_) {
current_interval_ *= 2;
if (current_interval_ >= target_interval_) {
current_interval_ = target_interval_;
}
}
int64_t interval_count = std::chrono::duration_cast<std::chrono::seconds>(interval).count();
if (interval_count == 0) {
return interval;
}
// Generate a random offset between [-n, n): n = jitter*current_interval.
auto unscaled_offset = static_cast<float>((rand() % (2 * interval_count)) - interval_count);
std::chrono::seconds offset = std::chrono::seconds(static_cast<int>(unscaled_offset * jitter_));
return interval + offset;
}
} // namespace cobalt::uploader