Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(78)

Side by Side Diff: google_apis/gcm/engine/gcm_store_impl.cc

Issue 1121003003: [GCM] Adding handling of heartbeat intervals to the GCM store. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@heartbeat-gcm
Patch Set: Adding histrograms Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "google_apis/gcm/engine/gcm_store_impl.h" 5 #include "google_apis/gcm/engine/gcm_store_impl.h"
6 6
7 #include "base/basictypes.h" 7 #include "base/basictypes.h"
8 #include "base/bind.h" 8 #include "base/bind.h"
9 #include "base/callback.h" 9 #include "base/callback.h"
10 #include "base/files/file_path.h" 10 #include "base/files/file_path.h"
(...skipping 29 matching lines...) Expand all
40 RELOADING_OPEN_STORE, 40 RELOADING_OPEN_STORE,
41 OPENING_STORE_FAILED, 41 OPENING_STORE_FAILED,
42 LOADING_DEVICE_CREDENTIALS_FAILED, 42 LOADING_DEVICE_CREDENTIALS_FAILED,
43 LOADING_REGISTRATION_FAILED, 43 LOADING_REGISTRATION_FAILED,
44 LOADING_INCOMING_MESSAGES_FAILED, 44 LOADING_INCOMING_MESSAGES_FAILED,
45 LOADING_OUTGOING_MESSAGES_FAILED, 45 LOADING_OUTGOING_MESSAGES_FAILED,
46 LOADING_LAST_CHECKIN_INFO_FAILED, 46 LOADING_LAST_CHECKIN_INFO_FAILED,
47 LOADING_GSERVICE_SETTINGS_FAILED, 47 LOADING_GSERVICE_SETTINGS_FAILED,
48 LOADING_ACCOUNT_MAPPING_FAILED, 48 LOADING_ACCOUNT_MAPPING_FAILED,
49 LOADING_LAST_TOKEN_TIME_FAILED, 49 LOADING_LAST_TOKEN_TIME_FAILED,
50 LOADING_HEARTBEAT_INTERVALS_FAILED,
50 51
51 // NOTE: always keep this entry at the end. Add new status types only 52 // NOTE: always keep this entry at the end. Add new status types only
52 // immediately above this line. Make sure to update the corresponding 53 // immediately above this line. Make sure to update the corresponding
53 // histogram enum accordingly. 54 // histogram enum accordingly.
54 LOAD_STATUS_COUNT 55 LOAD_STATUS_COUNT
55 }; 56 };
56 57
57 // Limit to the number of outstanding messages per app. 58 // Limit to the number of outstanding messages per app.
58 const int kMessagesPerAppLimit = 20; 59 const int kMessagesPerAppLimit = 20;
59 60
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 // Key used to indicate how many accounts were last checked in with this device. 92 // Key used to indicate how many accounts were last checked in with this device.
92 const char kLastCheckinAccountsKey[] = "last_checkin_accounts_count"; 93 const char kLastCheckinAccountsKey[] = "last_checkin_accounts_count";
93 // Key used to timestamp last checkin (marked with G services settings update). 94 // Key used to timestamp last checkin (marked with G services settings update).
94 const char kLastCheckinTimeKey[] = "last_checkin_time"; 95 const char kLastCheckinTimeKey[] = "last_checkin_time";
95 // Lowest lexicographically ordered account key. 96 // Lowest lexicographically ordered account key.
96 // Used for prefixing account information. 97 // Used for prefixing account information.
97 const char kAccountKeyStart[] = "account1-"; 98 const char kAccountKeyStart[] = "account1-";
98 // Key guaranteed to be higher than all account keys. 99 // Key guaranteed to be higher than all account keys.
99 // Used for limiting iteration. 100 // Used for limiting iteration.
100 const char kAccountKeyEnd[] = "account2-"; 101 const char kAccountKeyEnd[] = "account2-";
102 // Lowest lexicographically ordered heartbeat key.
103 // Used for prefixing account information.
104 const char kHeartbeatKeyStart[] = "heartbeat1-";
105 // Key guaranteed to be higher than all heartbeat keys.
106 // Used for limiting iteration.
107 const char kHeartbeatKeyEnd[] = "heartbeat2-";
101 // Key used for last token fetch time. 108 // Key used for last token fetch time.
102 const char kLastTokenFetchTimeKey[] = "last_token_fetch_time"; 109 const char kLastTokenFetchTimeKey[] = "last_token_fetch_time";
103 110
104 std::string MakeRegistrationKey(const std::string& app_id) { 111 std::string MakeRegistrationKey(const std::string& app_id) {
105 return kRegistrationKeyStart + app_id; 112 return kRegistrationKeyStart + app_id;
106 } 113 }
107 114
108 std::string ParseRegistrationKey(const std::string& key) { 115 std::string ParseRegistrationKey(const std::string& key) {
109 return key.substr(arraysize(kRegistrationKeyStart) - 1); 116 return key.substr(arraysize(kRegistrationKeyStart) - 1);
110 } 117 }
(...skipping 19 matching lines...) Expand all
130 } 137 }
131 138
132 std::string MakeAccountKey(const std::string& account_id) { 139 std::string MakeAccountKey(const std::string& account_id) {
133 return kAccountKeyStart + account_id; 140 return kAccountKeyStart + account_id;
134 } 141 }
135 142
136 std::string ParseAccountKey(const std::string& key) { 143 std::string ParseAccountKey(const std::string& key) {
137 return key.substr(arraysize(kAccountKeyStart) - 1); 144 return key.substr(arraysize(kAccountKeyStart) - 1);
138 } 145 }
139 146
147 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
148 return kHeartbeatKeyStart + scope;
149 }
150
151 std::string ParseHeartbeatKey(const std::string& key) {
152 return key.substr(arraysize(kHeartbeatKeyStart) - 1);
153 }
154
140 // Note: leveldb::Slice keeps a pointer to the data in |s|, which must therefore 155 // Note: leveldb::Slice keeps a pointer to the data in |s|, which must therefore
141 // outlive the slice. 156 // outlive the slice.
142 // For example: MakeSlice(MakeOutgoingKey(x)) is invalid. 157 // For example: MakeSlice(MakeOutgoingKey(x)) is invalid.
143 leveldb::Slice MakeSlice(const base::StringPiece& s) { 158 leveldb::Slice MakeSlice(const base::StringPiece& s) {
144 return leveldb::Slice(s.begin(), s.size()); 159 return leveldb::Slice(s.begin(), s.size());
145 } 160 }
146 161
147 } // namespace 162 } // namespace
148 163
149 class GCMStoreImpl::Backend 164 class GCMStoreImpl::Backend
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
187 void SetGServicesSettings( 202 void SetGServicesSettings(
188 const std::map<std::string, std::string>& settings, 203 const std::map<std::string, std::string>& settings,
189 const std::string& digest, 204 const std::string& digest,
190 const UpdateCallback& callback); 205 const UpdateCallback& callback);
191 void AddAccountMapping(const AccountMapping& account_mapping, 206 void AddAccountMapping(const AccountMapping& account_mapping,
192 const UpdateCallback& callback); 207 const UpdateCallback& callback);
193 void RemoveAccountMapping(const std::string& account_id, 208 void RemoveAccountMapping(const std::string& account_id,
194 const UpdateCallback& callback); 209 const UpdateCallback& callback);
195 void SetLastTokenFetchTime(const base::Time& time, 210 void SetLastTokenFetchTime(const base::Time& time,
196 const UpdateCallback& callback); 211 const UpdateCallback& callback);
212 void AddHeartbeatInterval(const std::string& scope,
213 int interval_ms,
214 const UpdateCallback& callback);
215 void RemoveHeartbeatInterval(const std::string& scope,
216 const UpdateCallback& callback);
197 void SetValue(const std::string& key, 217 void SetValue(const std::string& key,
198 const std::string& value, 218 const std::string& value,
199 const UpdateCallback& callback); 219 const UpdateCallback& callback);
200 220
201 private: 221 private:
202 friend class base::RefCountedThreadSafe<Backend>; 222 friend class base::RefCountedThreadSafe<Backend>;
203 ~Backend(); 223 ~Backend();
204 224
205 LoadStatus OpenStoreAndLoadData(LoadResult* result); 225 LoadStatus OpenStoreAndLoadData(LoadResult* result);
206 bool LoadDeviceCredentials(uint64* android_id, uint64* security_token); 226 bool LoadDeviceCredentials(uint64* android_id, uint64* security_token);
207 bool LoadRegistrations(RegistrationInfoMap* registrations); 227 bool LoadRegistrations(RegistrationInfoMap* registrations);
208 bool LoadIncomingMessages(std::vector<std::string>* incoming_messages); 228 bool LoadIncomingMessages(std::vector<std::string>* incoming_messages);
209 bool LoadOutgoingMessages(OutgoingMessageMap* outgoing_messages); 229 bool LoadOutgoingMessages(OutgoingMessageMap* outgoing_messages);
210 bool LoadLastCheckinInfo(base::Time* last_checkin_time, 230 bool LoadLastCheckinInfo(base::Time* last_checkin_time,
211 std::set<std::string>* accounts); 231 std::set<std::string>* accounts);
212 bool LoadGServicesSettings(std::map<std::string, std::string>* settings, 232 bool LoadGServicesSettings(std::map<std::string, std::string>* settings,
213 std::string* digest); 233 std::string* digest);
214 bool LoadAccountMappingInfo(AccountMappings* account_mappings); 234 bool LoadAccountMappingInfo(AccountMappings* account_mappings);
215 bool LoadLastTokenFetchTime(base::Time* last_token_fetch_time); 235 bool LoadLastTokenFetchTime(base::Time* last_token_fetch_time);
236 bool LoadHeartbeatIntervals(std::map<std::string, int>* heartbeat_intervals);
216 237
217 const base::FilePath path_; 238 const base::FilePath path_;
218 scoped_refptr<base::SequencedTaskRunner> foreground_task_runner_; 239 scoped_refptr<base::SequencedTaskRunner> foreground_task_runner_;
219 scoped_ptr<Encryptor> encryptor_; 240 scoped_ptr<Encryptor> encryptor_;
220 241
221 scoped_ptr<leveldb::DB> db_; 242 scoped_ptr<leveldb::DB> db_;
222 }; 243 };
223 244
224 GCMStoreImpl::Backend::Backend( 245 GCMStoreImpl::Backend::Backend(
225 const base::FilePath& path, 246 const base::FilePath& path,
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
266 &result->last_checkin_accounts)) { 287 &result->last_checkin_accounts)) {
267 return LOADING_LAST_CHECKIN_INFO_FAILED; 288 return LOADING_LAST_CHECKIN_INFO_FAILED;
268 } 289 }
269 if (!LoadGServicesSettings(&result->gservices_settings, 290 if (!LoadGServicesSettings(&result->gservices_settings,
270 &result->gservices_digest)) { 291 &result->gservices_digest)) {
271 return load_status = LOADING_GSERVICE_SETTINGS_FAILED; 292 return load_status = LOADING_GSERVICE_SETTINGS_FAILED;
272 } 293 }
273 if (!LoadAccountMappingInfo(&result->account_mappings)) 294 if (!LoadAccountMappingInfo(&result->account_mappings))
274 return LOADING_ACCOUNT_MAPPING_FAILED; 295 return LOADING_ACCOUNT_MAPPING_FAILED;
275 if (!LoadLastTokenFetchTime(&result->last_token_fetch_time)) 296 if (!LoadLastTokenFetchTime(&result->last_token_fetch_time))
276 return LOADING_LAST_TOKEN_TIME_FAILED; 297 return LOADING_LAST_TOKEN_TIME_FAILED;
298 if (!LoadHeartbeatIntervals(&result->heartbeat_intervals))
299 return LOADING_HEARTBEAT_INTERVALS_FAILED;
277 300
278 return LOADING_SUCCEEDED; 301 return LOADING_SUCCEEDED;
279 } 302 }
280 303
281 void GCMStoreImpl::Backend::Load(const LoadCallback& callback) { 304 void GCMStoreImpl::Backend::Load(const LoadCallback& callback) {
282 scoped_ptr<LoadResult> result(new LoadResult()); 305 scoped_ptr<LoadResult> result(new LoadResult());
283 LoadStatus load_status = OpenStoreAndLoadData(result.get()); 306 LoadStatus load_status = OpenStoreAndLoadData(result.get());
284 UMA_HISTOGRAM_ENUMERATION("GCM.LoadStatus", load_status, LOAD_STATUS_COUNT); 307 UMA_HISTOGRAM_ENUMERATION("GCM.LoadStatus", load_status, LOAD_STATUS_COUNT);
285 if (load_status != LOADING_SUCCEEDED) { 308 if (load_status != LOADING_SUCCEEDED) {
286 result->Reset(); 309 result->Reset();
(...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after
681 const leveldb::Status s = 704 const leveldb::Status s =
682 db_->Put(write_options, 705 db_->Put(write_options,
683 MakeSlice(kLastTokenFetchTimeKey), 706 MakeSlice(kLastTokenFetchTimeKey),
684 MakeSlice(base::Int64ToString(time.ToInternalValue()))); 707 MakeSlice(base::Int64ToString(time.ToInternalValue())));
685 708
686 if (!s.ok()) 709 if (!s.ok())
687 LOG(ERROR) << "LevelDB setting last token fetching time: " << s.ToString(); 710 LOG(ERROR) << "LevelDB setting last token fetching time: " << s.ToString();
688 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok())); 711 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok()));
689 } 712 }
690 713
714 void GCMStoreImpl::Backend::AddHeartbeatInterval(
715 const std::string& scope,
716 int interval_ms,
717 const UpdateCallback& callback) {
718 DVLOG(1) << "Saving a heartbeat interval: scope: " << scope
719 << " interval: " << interval_ms << "ms.";
720 if (!db_.get()) {
721 LOG(ERROR) << "GCMStore db doesn't exist.";
722 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
723 return;
724 }
725
726 leveldb::WriteOptions write_options;
727 write_options.sync = true;
728
729 std::string data = base::IntToString(interval_ms);
730 std::string key = MakeHeartbeatKey(scope);
731 const leveldb::Status s =
732 db_->Put(write_options, MakeSlice(key), MakeSlice(data));
733 if (!s.ok())
734 LOG(ERROR) << "LevelDB adding heartbeat interval failed: " << s.ToString();
735 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok()));
736 }
737
738 void GCMStoreImpl::Backend::RemoveHeartbeatInterval(
739 const std::string& scope,
740 const UpdateCallback& callback) {
741 if (!db_.get()) {
742 LOG(ERROR) << "GCMStore db doesn't exist.";
743 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
744 return;
745 }
746
747 leveldb::WriteOptions write_options;
748 write_options.sync = true;
749
750 leveldb::Status s =
751 db_->Delete(write_options, MakeSlice(MakeHeartbeatKey(scope)));
752
753 if (!s.ok()) {
754 LOG(ERROR) << "LevelDB removal of heartbeat interval failed: "
755 << s.ToString();
756 }
757 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok()));
758 }
759
691 void GCMStoreImpl::Backend::SetValue(const std::string& key, 760 void GCMStoreImpl::Backend::SetValue(const std::string& key,
692 const std::string& value, 761 const std::string& value,
693 const UpdateCallback& callback) { 762 const UpdateCallback& callback) {
694 DVLOG(1) << "Injecting a value to GCM Store for testing. Key: " 763 DVLOG(1) << "Injecting a value to GCM Store for testing. Key: "
695 << key << ", Value: " << value; 764 << key << ", Value: " << value;
696 if (!db_.get()) { 765 if (!db_.get()) {
697 LOG(ERROR) << "GCMStore db doesn't exist."; 766 LOG(ERROR) << "GCMStore db doesn't exist.";
698 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false)); 767 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
699 return; 768 return;
700 } 769 }
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after
922 "Failed to restore last token fetching time. Using default = 0."; 991 "Failed to restore last token fetching time. Using default = 0.";
923 time_internal = 0LL; 992 time_internal = 0LL;
924 } 993 }
925 994
926 // In case we cannot read last token fetching time, we default it to 0. 995 // In case we cannot read last token fetching time, we default it to 0.
927 *last_token_fetch_time = base::Time::FromInternalValue(time_internal); 996 *last_token_fetch_time = base::Time::FromInternalValue(time_internal);
928 997
929 return true; 998 return true;
930 } 999 }
931 1000
1001 bool GCMStoreImpl::Backend::LoadHeartbeatIntervals(
1002 std::map<std::string, int>* heartbeat_intervals) {
1003 leveldb::ReadOptions read_options;
1004 read_options.verify_checksums = true;
1005
1006 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
1007 for (iter->Seek(MakeSlice(kHeartbeatKeyStart));
1008 iter->Valid() && iter->key().ToString() < kHeartbeatKeyEnd;
1009 iter->Next()) {
1010 std::string scope = ParseHeartbeatKey(iter->key().ToString());
1011 int interval_ms;
1012 if (!base::StringToInt(iter->value().ToString(), &interval_ms)) {
1013 DVLOG(1) << "Failed to parse heartbeat interval info with scope: "
1014 << scope;
1015 return false;
1016 }
1017 DVLOG(1) << "Found heartbeat interval with scope: " << scope
1018 << " interval: " << interval_ms << "ms.";
1019 (*heartbeat_intervals)[scope] = interval_ms;
1020 }
1021
1022 return true;
1023 }
1024
932 GCMStoreImpl::GCMStoreImpl( 1025 GCMStoreImpl::GCMStoreImpl(
933 const base::FilePath& path, 1026 const base::FilePath& path,
934 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner, 1027 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
935 scoped_ptr<Encryptor> encryptor) 1028 scoped_ptr<Encryptor> encryptor)
936 : backend_(new Backend(path, 1029 : backend_(new Backend(path,
937 base::MessageLoopProxy::current(), 1030 base::MessageLoopProxy::current(),
938 encryptor.Pass())), 1031 encryptor.Pass())),
939 blocking_task_runner_(blocking_task_runner), 1032 blocking_task_runner_(blocking_task_runner),
940 weak_ptr_factory_(this) { 1033 weak_ptr_factory_(this) {
941 } 1034 }
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after
1152 void GCMStoreImpl::SetLastTokenFetchTime(const base::Time& time, 1245 void GCMStoreImpl::SetLastTokenFetchTime(const base::Time& time,
1153 const UpdateCallback& callback) { 1246 const UpdateCallback& callback) {
1154 blocking_task_runner_->PostTask( 1247 blocking_task_runner_->PostTask(
1155 FROM_HERE, 1248 FROM_HERE,
1156 base::Bind(&GCMStoreImpl::Backend::SetLastTokenFetchTime, 1249 base::Bind(&GCMStoreImpl::Backend::SetLastTokenFetchTime,
1157 backend_, 1250 backend_,
1158 time, 1251 time,
1159 callback)); 1252 callback));
1160 } 1253 }
1161 1254
1255 void GCMStoreImpl::AddHeartbeatInterval(const std::string& scope,
1256 int interval_ms,
1257 const UpdateCallback& callback) {
1258 blocking_task_runner_->PostTask(
1259 FROM_HERE,
1260 base::Bind(&GCMStoreImpl::Backend::AddHeartbeatInterval,
1261 backend_,
1262 scope,
1263 interval_ms,
1264 callback));
1265 }
1266
1267 void GCMStoreImpl::RemoveHeartbeatInterval(const std::string& scope,
1268 const UpdateCallback& callback) {
1269 blocking_task_runner_->PostTask(
1270 FROM_HERE,
1271 base::Bind(&GCMStoreImpl::Backend::RemoveHeartbeatInterval,
1272 backend_,
1273 scope,
1274 callback));
1275 }
1276
1162 void GCMStoreImpl::SetValueForTesting(const std::string& key, 1277 void GCMStoreImpl::SetValueForTesting(const std::string& key,
1163 const std::string& value, 1278 const std::string& value,
1164 const UpdateCallback& callback) { 1279 const UpdateCallback& callback) {
1165 blocking_task_runner_->PostTask( 1280 blocking_task_runner_->PostTask(
1166 FROM_HERE, 1281 FROM_HERE,
1167 base::Bind(&GCMStoreImpl::Backend::SetValue, 1282 base::Bind(&GCMStoreImpl::Backend::SetValue,
1168 backend_, 1283 backend_,
1169 key, 1284 key,
1170 value, 1285 value,
1171 callback)); 1286 callback));
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
1222 removed_message_counts.begin(); 1337 removed_message_counts.begin();
1223 iter != removed_message_counts.end(); ++iter) { 1338 iter != removed_message_counts.end(); ++iter) {
1224 DCHECK_NE(app_message_counts_.count(iter->first), 0U); 1339 DCHECK_NE(app_message_counts_.count(iter->first), 0U);
1225 app_message_counts_[iter->first] -= iter->second; 1340 app_message_counts_[iter->first] -= iter->second;
1226 DCHECK_GE(app_message_counts_[iter->first], 0); 1341 DCHECK_GE(app_message_counts_[iter->first], 0);
1227 } 1342 }
1228 callback.Run(true); 1343 callback.Run(true);
1229 } 1344 }
1230 1345
1231 } // namespace gcm 1346 } // namespace gcm
OLDNEW
« no previous file with comments | « google_apis/gcm/engine/gcm_store_impl.h ('k') | google_apis/gcm/engine/gcm_store_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698