Chromium Code Reviews| Index: google_apis/gcm/engine/gcm_store_impl.cc |
| diff --git a/google_apis/gcm/engine/gcm_store_impl.cc b/google_apis/gcm/engine/gcm_store_impl.cc |
| index 602106ba298865f8dabc45d0542193dc842cc28a..4105e68518b6cd89dbce19c1c122554d82e9b367 100644 |
| --- a/google_apis/gcm/engine/gcm_store_impl.cc |
| +++ b/google_apis/gcm/engine/gcm_store_impl.cc |
| @@ -47,6 +47,7 @@ enum LoadStatus { |
| LOADING_GSERVICE_SETTINGS_FAILED, |
| LOADING_ACCOUNT_MAPPING_FAILED, |
| LOADING_LAST_TOKEN_TIME_FAILED, |
| + LOADING_HEARTBEAT_INTERVALS_FAILED, |
| // NOTE: always keep this entry at the end. Add new status types only |
| // immediately above this line. Make sure to update the corresponding |
| @@ -98,6 +99,12 @@ const char kAccountKeyStart[] = "account1-"; |
| // Key guaranteed to be higher than all account keys. |
| // Used for limiting iteration. |
| const char kAccountKeyEnd[] = "account2-"; |
| +// Lowest lexicographically ordered heartbeat key. |
| +// Used for prefixing account information. |
| +const char kHeartbeatKeyStart[] = "heartbeat1-"; |
| +// Key guaranteed to be higher than all heartbeat keys. |
| +// Used for limiting iteration. |
| +const char kHeartbeatKeyEnd[] = "heartbeat2-"; |
| // Key used for last token fetch time. |
| const char kLastTokenFetchTimeKey[] = "last_token_fetch_time"; |
| @@ -137,6 +144,14 @@ std::string ParseAccountKey(const std::string& key) { |
| return key.substr(arraysize(kAccountKeyStart) - 1); |
| } |
| +std::string MakeHeartbeatKey(const std::string& scope) { |
|
Nicolas Zea
2015/05/04 17:45:28
remind me, what is the scope derived from?
fgorski
2015/05/04 18:14:54
It is simply a token uniquely identifying componen
|
| + return kHeartbeatKeyStart + scope; |
| +} |
| + |
| +std::string ParseHeartbeatKey(const std::string& key) { |
| + return key.substr(arraysize(kHeartbeatKeyStart) - 1); |
| +} |
| + |
| // Note: leveldb::Slice keeps a pointer to the data in |s|, which must therefore |
| // outlive the slice. |
| // For example: MakeSlice(MakeOutgoingKey(x)) is invalid. |
| @@ -194,6 +209,11 @@ class GCMStoreImpl::Backend |
| const UpdateCallback& callback); |
| void SetLastTokenFetchTime(const base::Time& time, |
| const UpdateCallback& callback); |
| + void AddHeartbeatInterval(const std::string& scope, |
| + int interval_ms, |
| + const UpdateCallback& callback); |
| + void RemoveHeartbeatInterval(const std::string& scope, |
| + const UpdateCallback& callback); |
| void SetValue(const std::string& key, |
| const std::string& value, |
| const UpdateCallback& callback); |
| @@ -213,6 +233,7 @@ class GCMStoreImpl::Backend |
| std::string* digest); |
| bool LoadAccountMappingInfo(AccountMappings* account_mappings); |
| bool LoadLastTokenFetchTime(base::Time* last_token_fetch_time); |
| + bool LoadHeartbeatIntervals(std::map<std::string, int>* heartbeat_intervals); |
| const base::FilePath path_; |
| scoped_refptr<base::SequencedTaskRunner> foreground_task_runner_; |
| @@ -273,7 +294,9 @@ LoadStatus GCMStoreImpl::Backend::OpenStoreAndLoadData(LoadResult* result) { |
| if (!LoadAccountMappingInfo(&result->account_mappings)) |
| return LOADING_ACCOUNT_MAPPING_FAILED; |
| if (!LoadLastTokenFetchTime(&result->last_token_fetch_time)) |
| - return LOADING_LAST_TOKEN_TIME_FAILED; |
| + return LOADING_LAST_TOKEN_TIME_FAILED; |
| + if (!LoadHeartbeatIntervals(&result->heartbeat_intervals)) |
| + return LOADING_HEARTBEAT_INTERVALS_FAILED; |
| return LOADING_SUCCEEDED; |
| } |
| @@ -688,6 +711,52 @@ void GCMStoreImpl::Backend::SetLastTokenFetchTime( |
| foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok())); |
| } |
| +void GCMStoreImpl::Backend::AddHeartbeatInterval( |
| + const std::string& scope, |
| + int interval_ms, |
| + const UpdateCallback& callback) { |
| + DVLOG(1) << "Saving a heartbeat interval: scope: " << scope |
| + << " interval: " << interval_ms << "ms."; |
| + if (!db_.get()) { |
| + LOG(ERROR) << "GCMStore db doesn't exist."; |
| + foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false)); |
| + return; |
| + } |
| + |
| + leveldb::WriteOptions write_options; |
| + write_options.sync = true; |
| + |
| + std::string data = base::IntToString(interval_ms); |
| + std::string key = MakeHeartbeatKey(scope); |
| + const leveldb::Status s = |
| + db_->Put(write_options, MakeSlice(key), MakeSlice(data)); |
| + if (!s.ok()) |
| + LOG(ERROR) << "LevelDB adding heartbeat interval failed: " << s.ToString(); |
| + foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok())); |
| +} |
| + |
| +void GCMStoreImpl::Backend::RemoveHeartbeatInterval( |
| + const std::string& scope, |
| + const UpdateCallback& callback) { |
| + if (!db_.get()) { |
| + LOG(ERROR) << "GCMStore db doesn't exist."; |
| + foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false)); |
| + return; |
| + } |
| + |
| + leveldb::WriteOptions write_options; |
| + write_options.sync = true; |
| + |
| + leveldb::Status s = |
| + db_->Delete(write_options, MakeSlice(MakeHeartbeatKey(scope))); |
| + |
| + if (!s.ok()) { |
| + LOG(ERROR) << "LevelDB removal of heartbeat interval failed: " |
| + << s.ToString(); |
| + } |
| + foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok())); |
| +} |
| + |
| void GCMStoreImpl::Backend::SetValue(const std::string& key, |
| const std::string& value, |
| const UpdateCallback& callback) { |
| @@ -929,6 +998,30 @@ bool GCMStoreImpl::Backend::LoadLastTokenFetchTime( |
| return true; |
| } |
| +bool GCMStoreImpl::Backend::LoadHeartbeatIntervals( |
| + std::map<std::string, int>* heartbeat_intervals) { |
| + leveldb::ReadOptions read_options; |
| + read_options.verify_checksums = true; |
| + |
| + scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options)); |
| + for (iter->Seek(MakeSlice(kHeartbeatKeyStart)); |
| + iter->Valid() && iter->key().ToString() < kHeartbeatKeyEnd; |
| + iter->Next()) { |
| + std::string scope = ParseHeartbeatKey(iter->key().ToString()); |
| + int interval_ms; |
| + if (!base::StringToInt(iter->value().ToString(), &interval_ms)) { |
| + DVLOG(1) << "Failed to parse heartbeat interval info with scope: " |
| + << scope; |
| + return false; |
| + } |
| + DVLOG(1) << "Found heartbeat interval with scope: " << scope |
| + << " interval: " << interval_ms << "ms."; |
| + (*heartbeat_intervals)[scope] = interval_ms; |
| + } |
| + |
| + return true; |
| +} |
| + |
| GCMStoreImpl::GCMStoreImpl( |
| const base::FilePath& path, |
| scoped_refptr<base::SequencedTaskRunner> blocking_task_runner, |
| @@ -1159,6 +1252,28 @@ void GCMStoreImpl::SetLastTokenFetchTime(const base::Time& time, |
| callback)); |
| } |
| +void GCMStoreImpl::AddHeartbeatInterval(const std::string& scope, |
| + int interval_ms, |
| + const UpdateCallback& callback) { |
| + blocking_task_runner_->PostTask( |
| + FROM_HERE, |
| + base::Bind(&GCMStoreImpl::Backend::AddHeartbeatInterval, |
| + backend_, |
| + scope, |
| + interval_ms, |
| + callback)); |
| +} |
| + |
| +void GCMStoreImpl::RemoveHeartbeatInterval(const std::string& scope, |
| + const UpdateCallback& callback) { |
| + blocking_task_runner_->PostTask( |
| + FROM_HERE, |
| + base::Bind(&GCMStoreImpl::Backend::RemoveHeartbeatInterval, |
| + backend_, |
| + scope, |
| + callback)); |
| +} |
| + |
| void GCMStoreImpl::SetValueForTesting(const std::string& key, |
| const std::string& value, |
| const UpdateCallback& callback) { |