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

Side by Side Diff: net/tools/testserver/chromiumsync.py

Issue 9460047: sync: remove use of protobuf extensions in protocol to reduce static init overhead. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fred's review Created 8 years, 9 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 | Annotate | Revision Log
OLDNEW
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 # Copyright (c) 2012 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 """An implementation of the server side of the Chromium sync protocol. 5 """An implementation of the server side of the Chromium sync protocol.
6 6
7 The details of the protocol are described mostly by comments in the protocol 7 The details of the protocol are described mostly by comments in the protocol
8 buffer definition at chrome/browser/sync/protocol/sync.proto. 8 buffer definition at chrome/browser/sync/protocol/sync.proto.
9 """ 9 """
10 10
(...skipping 19 matching lines...) Expand all
30 import preference_specifics_pb2 30 import preference_specifics_pb2
31 import search_engine_specifics_pb2 31 import search_engine_specifics_pb2
32 import session_specifics_pb2 32 import session_specifics_pb2
33 import sync_pb2 33 import sync_pb2
34 import sync_enums_pb2 34 import sync_enums_pb2
35 import theme_specifics_pb2 35 import theme_specifics_pb2
36 import typed_url_specifics_pb2 36 import typed_url_specifics_pb2
37 37
38 # An enumeration of the various kinds of data that can be synced. 38 # An enumeration of the various kinds of data that can be synced.
39 # Over the wire, this enumeration is not used: a sync object's type is 39 # Over the wire, this enumeration is not used: a sync object's type is
40 # inferred by which EntitySpecifics extension it has. But in the context 40 # inferred by which EntitySpecifics field it has. But in the context
41 # of a program, it is useful to have an enumeration. 41 # of a program, it is useful to have an enumeration.
42 ALL_TYPES = ( 42 ALL_TYPES = (
43 TOP_LEVEL, # The type of the 'Google Chrome' folder. 43 TOP_LEVEL, # The type of the 'Google Chrome' folder.
44 APPS, 44 APPS,
45 APP_NOTIFICATION, 45 APP_NOTIFICATION,
46 APP_SETTINGS, 46 APP_SETTINGS,
47 AUTOFILL, 47 AUTOFILL,
48 AUTOFILL_PROFILE, 48 AUTOFILL_PROFILE,
49 BOOKMARK, 49 BOOKMARK,
50 EXTENSIONS, 50 EXTENSIONS,
(...skipping 10 matching lines...) Expand all
61 # to the client. This would be specified by the url that triggers the error. 61 # to the client. This would be specified by the url that triggers the error.
62 # Note: This enum should be kept in the same order as the enum in sync_test.h. 62 # Note: This enum should be kept in the same order as the enum in sync_test.h.
63 SYNC_ERROR_FREQUENCY = ( 63 SYNC_ERROR_FREQUENCY = (
64 ERROR_FREQUENCY_NONE, 64 ERROR_FREQUENCY_NONE,
65 ERROR_FREQUENCY_ALWAYS, 65 ERROR_FREQUENCY_ALWAYS,
66 ERROR_FREQUENCY_TWO_THIRDS) = range(3) 66 ERROR_FREQUENCY_TWO_THIRDS) = range(3)
67 67
68 # Well-known server tag of the top level 'Google Chrome' folder. 68 # Well-known server tag of the top level 'Google Chrome' folder.
69 TOP_LEVEL_FOLDER_TAG = 'google_chrome' 69 TOP_LEVEL_FOLDER_TAG = 'google_chrome'
70 70
71 # Given a sync type from ALL_TYPES, find the extension token corresponding 71 # Given a sync type from ALL_TYPES, find the FieldDescriptor corresponding
72 # to that datatype. Note that TOP_LEVEL has no such token. 72 # to that datatype. Note that TOP_LEVEL has no such token.
73 SYNC_TYPE_TO_EXTENSION = { 73 SYNC_TYPE_FIELDS = sync_pb2.EntitySpecifics.DESCRIPTOR.fields_by_name
74 APP_NOTIFICATION: app_notification_specifics_pb2.app_notification, 74 SYNC_TYPE_TO_DESCRIPTOR = {
75 APP_SETTINGS: app_setting_specifics_pb2.app_setting, 75 APP_NOTIFICATION: SYNC_TYPE_FIELDS['app_notification'],
76 APPS: app_specifics_pb2.app, 76 APP_SETTINGS: SYNC_TYPE_FIELDS['app_setting'],
77 AUTOFILL: autofill_specifics_pb2.autofill, 77 APPS: SYNC_TYPE_FIELDS['app'],
78 AUTOFILL_PROFILE: autofill_specifics_pb2.autofill_profile, 78 AUTOFILL: SYNC_TYPE_FIELDS['autofill'],
79 BOOKMARK: bookmark_specifics_pb2.bookmark, 79 AUTOFILL_PROFILE: SYNC_TYPE_FIELDS['autofill_profile'],
80 EXTENSION_SETTINGS: extension_setting_specifics_pb2.extension_setting, 80 BOOKMARK: SYNC_TYPE_FIELDS['bookmark'],
81 EXTENSIONS: extension_specifics_pb2.extension, 81 EXTENSION_SETTINGS: SYNC_TYPE_FIELDS['extension_setting'],
82 NIGORI: nigori_specifics_pb2.nigori, 82 EXTENSIONS: SYNC_TYPE_FIELDS['extension'],
83 PASSWORD: password_specifics_pb2.password, 83 NIGORI: SYNC_TYPE_FIELDS['nigori'],
84 PREFERENCE: preference_specifics_pb2.preference, 84 PASSWORD: SYNC_TYPE_FIELDS['password'],
85 SEARCH_ENGINE: search_engine_specifics_pb2.search_engine, 85 PREFERENCE: SYNC_TYPE_FIELDS['preference'],
86 SESSION: session_specifics_pb2.session, 86 SEARCH_ENGINE: SYNC_TYPE_FIELDS['search_engine'],
87 THEME: theme_specifics_pb2.theme, 87 SESSION: SYNC_TYPE_FIELDS['session'],
88 TYPED_URL: typed_url_specifics_pb2.typed_url, 88 THEME: SYNC_TYPE_FIELDS['theme'],
89 TYPED_URL: SYNC_TYPE_FIELDS['typed_url'],
89 } 90 }
90 91
91 # The parent ID used to indicate a top-level node. 92 # The parent ID used to indicate a top-level node.
92 ROOT_ID = '0' 93 ROOT_ID = '0'
93 94
94 # Unix time epoch in struct_time format. The tuple corresponds to UTC Wednesday 95 # Unix time epoch in struct_time format. The tuple corresponds to UTC Wednesday
95 # Jan 1 1970, 00:00:00, non-dst. 96 # Jan 1 1970, 00:00:00, non-dst.
96 UNIX_TIME_EPOCH = (1970, 1, 1, 0, 0, 0, 3, 1, 0) 97 UNIX_TIME_EPOCH = (1970, 1, 1, 0, 0, 0, 3, 1, 0)
97 98
98 class Error(Exception): 99 class Error(Exception):
99 """Error class for this module.""" 100 """Error class for this module."""
100 101
101 102
102 class ProtobufExtensionNotUnique(Error): 103 class ProtobufDataTypeFieldNotUnique(Error):
103 """An entry should not have more than one protobuf extension present.""" 104 """An entry should not have more than one data type present."""
104 105
105 106
106 class DataTypeIdNotRecognized(Error): 107 class DataTypeIdNotRecognized(Error):
107 """The requested data type is not recognized.""" 108 """The requested data type is not recognized."""
108 109
109 110
110 class MigrationDoneError(Error): 111 class MigrationDoneError(Error):
111 """A server-side migration occurred; clients must re-sync some datatypes. 112 """A server-side migration occurred; clients must re-sync some datatypes.
112 113
113 Attributes: 114 Attributes:
(...skipping 22 matching lines...) Expand all
136 137
137 def GetEntryType(entry): 138 def GetEntryType(entry):
138 """Extract the sync type from a SyncEntry. 139 """Extract the sync type from a SyncEntry.
139 140
140 Args: 141 Args:
141 entry: A SyncEntity protobuf object whose type to determine. 142 entry: A SyncEntity protobuf object whose type to determine.
142 Returns: 143 Returns:
143 An enum value from ALL_TYPES if the entry's type can be determined, or None 144 An enum value from ALL_TYPES if the entry's type can be determined, or None
144 if the type cannot be determined. 145 if the type cannot be determined.
145 Raises: 146 Raises:
146 ProtobufExtensionNotUnique: More than one type was indicated by the entry. 147 ProtobufDataTypeFieldNotUnique: More than one type was indicated by
148 the entry.
147 """ 149 """
148 if entry.server_defined_unique_tag == TOP_LEVEL_FOLDER_TAG: 150 if entry.server_defined_unique_tag == TOP_LEVEL_FOLDER_TAG:
149 return TOP_LEVEL 151 return TOP_LEVEL
150 entry_types = GetEntryTypesFromSpecifics(entry.specifics) 152 entry_types = GetEntryTypesFromSpecifics(entry.specifics)
151 if not entry_types: 153 if not entry_types:
152 return None 154 return None
153 155
154 # If there is more than one, either there's a bug, or else the caller 156 # If there is more than one, either there's a bug, or else the caller
155 # should use GetEntryTypes. 157 # should use GetEntryTypes.
156 if len(entry_types) > 1: 158 if len(entry_types) > 1:
157 raise ProtobufExtensionNotUnique 159 raise ProtobufDataTypeFieldNotUnique
158 return entry_types[0] 160 return entry_types[0]
159 161
160 162
161 def GetEntryTypesFromSpecifics(specifics): 163 def GetEntryTypesFromSpecifics(specifics):
162 """Determine the sync types indicated by an EntitySpecifics's extension(s). 164 """Determine the sync types indicated by an EntitySpecifics's field(s).
163 165
164 If the specifics have more than one recognized extension (as commonly 166 If the specifics have more than one recognized data type field (as commonly
165 happens with the requested_types field of GetUpdatesMessage), all types 167 happens with the requested_types field of GetUpdatesMessage), all types
166 will be returned. Callers must handle the possibility of the returned 168 will be returned. Callers must handle the possibility of the returned
167 value having more than one item. 169 value having more than one item.
168 170
169 Args: 171 Args:
170 specifics: A EntitySpecifics protobuf message whose extensions to 172 specifics: A EntitySpecifics protobuf message whose extensions to
171 enumerate. 173 enumerate.
172 Returns: 174 Returns:
173 A list of the sync types (values from ALL_TYPES) associated with each 175 A list of the sync types (values from ALL_TYPES) associated with each
174 recognized extension of the specifics message. 176 recognized extension of the specifics message.
175 """ 177 """
176 return [data_type for data_type, extension 178 return [data_type for data_type, field_descriptor
177 in SYNC_TYPE_TO_EXTENSION.iteritems() 179 in SYNC_TYPE_TO_DESCRIPTOR.iteritems()
178 if specifics.HasExtension(extension)] 180 if specifics.HasField(field_descriptor.name)]
179 181
180 182
181 def SyncTypeToProtocolDataTypeId(data_type): 183 def SyncTypeToProtocolDataTypeId(data_type):
182 """Convert from a sync type (python enum) to the protocol's data type id.""" 184 """Convert from a sync type (python enum) to the protocol's data type id."""
183 return SYNC_TYPE_TO_EXTENSION[data_type].number 185 return SYNC_TYPE_TO_DESCRIPTOR[data_type].number
184 186
185 187
186 def ProtocolDataTypeIdToSyncType(protocol_data_type_id): 188 def ProtocolDataTypeIdToSyncType(protocol_data_type_id):
187 """Convert from the protocol's data type id to a sync type (python enum).""" 189 """Convert from the protocol's data type id to a sync type (python enum)."""
188 for data_type, protocol_extension in SYNC_TYPE_TO_EXTENSION.iteritems(): 190 for data_type, field_descriptor in SYNC_TYPE_TO_DESCRIPTOR.iteritems():
189 if protocol_extension.number == protocol_data_type_id: 191 if field_descriptor.number == protocol_data_type_id:
190 return data_type 192 return data_type
191 raise DataTypeIdNotRecognized 193 raise DataTypeIdNotRecognized
192 194
193 195
194 def DataTypeStringToSyncTypeLoose(data_type_string): 196 def DataTypeStringToSyncTypeLoose(data_type_string):
195 """Converts a human-readable string to a sync type (python enum). 197 """Converts a human-readable string to a sync type (python enum).
196 198
197 Capitalization and pluralization don't matter; this function is appropriate 199 Capitalization and pluralization don't matter; this function is appropriate
198 for values that might have been typed by a human being; e.g., command-line 200 for values that might have been typed by a human being; e.g., command-line
199 flags or query parameters. 201 flags or query parameters.
200 """ 202 """
201 if data_type_string.isdigit(): 203 if data_type_string.isdigit():
202 return ProtocolDataTypeIdToSyncType(int(data_type_string)) 204 return ProtocolDataTypeIdToSyncType(int(data_type_string))
203 name = data_type_string.lower().rstrip('s') 205 name = data_type_string.lower().rstrip('s')
204 for data_type, protocol_extension in SYNC_TYPE_TO_EXTENSION.iteritems(): 206 for data_type, field_descriptor in SYNC_TYPE_TO_DESCRIPTOR.iteritems():
205 if protocol_extension.name.lower().rstrip('s') == name: 207 if field_descriptor.name.lower().rstrip('s') == name:
206 return data_type 208 return data_type
207 raise DataTypeIdNotRecognized 209 raise DataTypeIdNotRecognized
208 210
209 211
210 def SyncTypeToString(data_type): 212 def SyncTypeToString(data_type):
211 """Formats a sync type enum (from ALL_TYPES) to a human-readable string.""" 213 """Formats a sync type enum (from ALL_TYPES) to a human-readable string."""
212 return SYNC_TYPE_TO_EXTENSION[data_type].name 214 return SYNC_TYPE_TO_DESCRIPTOR[data_type].name
213 215
214 216
215 def CallerInfoToString(caller_info_source): 217 def CallerInfoToString(caller_info_source):
216 """Formats a GetUpdatesSource enum value to a readable string.""" 218 """Formats a GetUpdatesSource enum value to a readable string."""
217 return sync_pb2.GetUpdatesCallerInfo.DESCRIPTOR.enum_types_by_name[ 219 return sync_pb2.GetUpdatesCallerInfo.DESCRIPTOR.enum_types_by_name[
218 'GetUpdatesSource'].values_by_number[caller_info_source].name 220 'GetUpdatesSource'].values_by_number[caller_info_source].name
219 221
220 222
221 def ShortDatatypeListSummary(data_types): 223 def ShortDatatypeListSummary(data_types):
222 """Formats compactly a list of sync types (python enums) for human eyes. 224 """Formats compactly a list of sync types (python enums) for human eyes.
(...skipping 11 matching lines...) Expand all
234 simple_text = '+'.join(sorted([SyncTypeToString(x) for x in included])) 236 simple_text = '+'.join(sorted([SyncTypeToString(x) for x in included]))
235 all_but_text = 'all except %s' % ( 237 all_but_text = 'all except %s' % (
236 '+'.join(sorted([SyncTypeToString(x) for x in excluded]))) 238 '+'.join(sorted([SyncTypeToString(x) for x in excluded])))
237 if len(included) < len(excluded) or len(simple_text) <= len(all_but_text): 239 if len(included) < len(excluded) or len(simple_text) <= len(all_but_text):
238 return simple_text 240 return simple_text
239 else: 241 else:
240 return all_but_text 242 return all_but_text
241 243
242 244
243 def GetDefaultEntitySpecifics(data_type): 245 def GetDefaultEntitySpecifics(data_type):
244 """Get an EntitySpecifics having a sync type's default extension value.""" 246 """Get an EntitySpecifics having a sync type's default field value."""
245 specifics = sync_pb2.EntitySpecifics() 247 specifics = sync_pb2.EntitySpecifics()
246 if data_type in SYNC_TYPE_TO_EXTENSION: 248 if data_type in SYNC_TYPE_TO_DESCRIPTOR:
247 extension_handle = SYNC_TYPE_TO_EXTENSION[data_type] 249 descriptor = SYNC_TYPE_TO_DESCRIPTOR[data_type]
248 specifics.Extensions[extension_handle].SetInParent() 250 getattr(specifics, descriptor.name).SetInParent()
249 return specifics 251 return specifics
250 252
251 253
252 class PermanentItem(object): 254 class PermanentItem(object):
253 """A specification of one server-created permanent item. 255 """A specification of one server-created permanent item.
254 256
255 Attributes: 257 Attributes:
256 tag: A known-to-the-client value that uniquely identifies a server-created 258 tag: A known-to-the-client value that uniquely identifies a server-created
257 permanent item. 259 permanent item.
258 name: The human-readable display name for this item. 260 name: The human-readable display name for this item.
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after
473 entry.sync_timestamp = self._version 475 entry.sync_timestamp = self._version
474 476
475 # Preserve the originator info, which the client is not required to send 477 # Preserve the originator info, which the client is not required to send
476 # when updating. 478 # when updating.
477 base_entry = self._entries.get(entry.id_string) 479 base_entry = self._entries.get(entry.id_string)
478 if base_entry: 480 if base_entry:
479 entry.originator_cache_guid = base_entry.originator_cache_guid 481 entry.originator_cache_guid = base_entry.originator_cache_guid
480 entry.originator_client_item_id = base_entry.originator_client_item_id 482 entry.originator_client_item_id = base_entry.originator_client_item_id
481 483
482 self._entries[entry.id_string] = copy.deepcopy(entry) 484 self._entries[entry.id_string] = copy.deepcopy(entry)
483 # Store the current time since the Unix epoch in milliseconds.
484 self._entries[entry.id_string].mtime = (int((time.mktime(time.gmtime()) -
485 time.mktime(UNIX_TIME_EPOCH))*1000))
486 485
487 def _ServerTagToId(self, tag): 486 def _ServerTagToId(self, tag):
488 """Determine the server ID from a server-unique tag. 487 """Determine the server ID from a server-unique tag.
489 488
490 The resulting value is guaranteed not to collide with the other ID 489 The resulting value is guaranteed not to collide with the other ID
491 generation methods. 490 generation methods.
492 491
493 Args: 492 Args:
494 datatype: The sync type (python enum) of the identified object. 493 datatype: The sync type (python enum) of the identified object.
495 tag: The unique, known-to-the-client tag of a server-generated item. 494 tag: The unique, known-to-the-client tag of a server-generated item.
(...skipping 375 matching lines...) Expand 10 before | Expand all | Expand 10 after
871 # we ignore insert_after_item_id (an older style). 870 # we ignore insert_after_item_id (an older style).
872 self._WritePosition(entry, entry.parent_id_string) 871 self._WritePosition(entry, entry.parent_id_string)
873 872
874 # Preserve the originator info, which the client is not required to send 873 # Preserve the originator info, which the client is not required to send
875 # when updating. 874 # when updating.
876 base_entry = self._entries.get(entry.id_string) 875 base_entry = self._entries.get(entry.id_string)
877 if base_entry and not entry.HasField('originator_cache_guid'): 876 if base_entry and not entry.HasField('originator_cache_guid'):
878 entry.originator_cache_guid = base_entry.originator_cache_guid 877 entry.originator_cache_guid = base_entry.originator_cache_guid
879 entry.originator_client_item_id = base_entry.originator_client_item_id 878 entry.originator_client_item_id = base_entry.originator_client_item_id
880 879
880 # Store the current time since the Unix epoch in milliseconds.
881 entry.mtime = (int((time.mktime(time.gmtime()) -
882 time.mktime(UNIX_TIME_EPOCH))*1000))
883
881 # Commit the change. This also updates the version number. 884 # Commit the change. This also updates the version number.
882 self._SaveEntry(entry) 885 self._SaveEntry(entry)
883 return entry 886 return entry
884 887
885 def _RewriteVersionInId(self, id_string): 888 def _RewriteVersionInId(self, id_string):
886 """Rewrites an ID so that its migration version becomes current.""" 889 """Rewrites an ID so that its migration version becomes current."""
887 parsed_id = self._ExtractIdInfo(id_string) 890 parsed_id = self._ExtractIdInfo(id_string)
888 if not parsed_id: 891 if not parsed_id:
889 return id_string 892 return id_string
890 datatype, old_migration_version, inner_id = parsed_id 893 datatype, old_migration_version, inner_id = parsed_id
(...skipping 18 matching lines...) Expand all
909 912
910 def TriggerSyncTabs(self): 913 def TriggerSyncTabs(self):
911 """Set the 'sync_tabs' field to this account's nigori node. 914 """Set the 'sync_tabs' field to this account's nigori node.
912 915
913 If the field is not currently set, will write a new nigori node entry 916 If the field is not currently set, will write a new nigori node entry
914 with the field set. Else does nothing. 917 with the field set. Else does nothing.
915 """ 918 """
916 919
917 nigori_tag = "google_chrome_nigori" 920 nigori_tag = "google_chrome_nigori"
918 nigori_original = self._entries.get(self._ServerTagToId(nigori_tag)) 921 nigori_original = self._entries.get(self._ServerTagToId(nigori_tag))
919 if (nigori_original.specifics.Extensions[nigori_specifics_pb2.nigori]. 922 if (nigori_original.specifics.nigori.sync_tabs):
920 sync_tabs):
921 return 923 return
922 nigori_new = copy.deepcopy(nigori_original) 924 nigori_new = copy.deepcopy(nigori_original)
923 nigori_new.specifics.Extensions[nigori_specifics_pb2.nigori].sync_tabs = ( 925 nigori_new.specifics.nigori.sync_tabs = True
924 True)
925 self._SaveEntry(nigori_new) 926 self._SaveEntry(nigori_new)
926 927
927 def SetInducedError(self, error, error_frequency, 928 def SetInducedError(self, error, error_frequency,
928 sync_count_before_errors): 929 sync_count_before_errors):
929 self.induced_error = error 930 self.induced_error = error
930 self.induced_error_frequency = error_frequency 931 self.induced_error_frequency = error_frequency
931 self.sync_count_before_errors = sync_count_before_errors 932 self.sync_count_before_errors = sync_count_before_errors
932 933
933 def GetInducedError(self): 934 def GetInducedError(self):
934 return self.induced_error 935 return self.induced_error
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after
1225 1226
1226 update_sieve.CheckMigrationState() 1227 update_sieve.CheckMigrationState()
1227 1228
1228 new_timestamp, entries, remaining = self.account.GetChanges(update_sieve) 1229 new_timestamp, entries, remaining = self.account.GetChanges(update_sieve)
1229 1230
1230 update_response.changes_remaining = remaining 1231 update_response.changes_remaining = remaining
1231 for entry in entries: 1232 for entry in entries:
1232 reply = update_response.entries.add() 1233 reply = update_response.entries.add()
1233 reply.CopyFrom(entry) 1234 reply.CopyFrom(entry)
1234 update_sieve.SaveProgress(new_timestamp, update_response) 1235 update_sieve.SaveProgress(new_timestamp, update_response)
OLDNEW
« no previous file with comments | « chrome/browser/webdata/autofill_profile_syncable_service_unittest.cc ('k') | net/tools/testserver/chromiumsync_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698