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

Side by Side Diff: ios/web/crw_browsing_data_store.mm

Issue 1154923003: Fixing an edge case in CRWBrowsingDataStore (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: y Created 5 years, 6 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
« no previous file with comments | « no previous file | ios/web/crw_browsing_data_store_unittest.mm » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 #import "ios/web/public/crw_browsing_data_store.h" 5 #import "ios/web/public/crw_browsing_data_store.h"
6 6
7 #import <Foundation/Foundation.h> 7 #import <Foundation/Foundation.h>
8 8
9 #include "base/ios/ios_util.h" 9 #include "base/ios/ios_util.h"
10 #import "base/ios/weak_nsobject.h" 10 #import "base/ios/weak_nsobject.h"
(...skipping 26 matching lines...) Expand all
37 // thread. 37 // thread.
38 @property(nonatomic, readonly) NSArray* allBrowsingDataManagers; 38 @property(nonatomic, readonly) NSArray* allBrowsingDataManagers;
39 // Returns an array of browsing data managers for the given |browsingDataTypes|. 39 // Returns an array of browsing data managers for the given |browsingDataTypes|.
40 - (NSArray*)browsingDataManagersForBrowsingDataTypes: 40 - (NSArray*)browsingDataManagersForBrowsingDataTypes:
41 (web::BrowsingDataTypes)browsingDataTypes; 41 (web::BrowsingDataTypes)browsingDataTypes;
42 42
43 // Redefined to be read-write. Must be called from the main thread. 43 // Redefined to be read-write. Must be called from the main thread.
44 @property(nonatomic, assign) CRWBrowsingDataStoreMode mode; 44 @property(nonatomic, assign) CRWBrowsingDataStoreMode mode;
45 // Sets the mode iff there are no more stash or restore operations that are 45 // Sets the mode iff there are no more stash or restore operations that are
46 // still pending. |mode| can only be either |ACTIVE| or |INACTIVE|. 46 // still pending. |mode| can only be either |ACTIVE| or |INACTIVE|.
47 - (void)setModeIfNotStashingOrRestoring:(CRWBrowsingDataStoreMode)mode; 47 // |handler| is called immediately (in the same runloop) with a BOOL indicating
48 // whether the mode change was successful or not. |handler| can be nil.
49 - (void)finalizeChangeToMode:(CRWBrowsingDataStoreMode)mode
50 andCallCompletionHandler:(void (^)(BOOL modeChangeWasSuccessful))handler;
51
52 // The number of stash or restore operations that are still pending.
53 @property(nonatomic, assign) NSUInteger numberOfPendingStashOrRestoreOperations;
48 54
49 // Performs operations of type |operationType| on each of the 55 // Performs operations of type |operationType| on each of the
50 // |browsingDataManagers|. 56 // |browsingDataManagers|.
51 // The kind of operations are: 57 // The kind of operations are:
52 // 1) STASH: Stash operation involves stashing browsing data that web views 58 // 1) STASH: Stash operation involves stashing browsing data that web views
53 // (UIWebViews and WKWebViews) create to the associated BrowserState's state 59 // (UIWebViews and WKWebViews) create to the associated BrowserState's state
54 // path. 60 // path.
55 // 2) RESTORE: Restore operation involves restoring browsing data from the 61 // 2) RESTORE: Restore operation involves restoring browsing data from the
56 // associated BrowserState's state path so that web views (UIWebViews and 62 // associated BrowserState's state path so that web views (UIWebViews and
57 // WKWebViews) can read from them. 63 // WKWebViews) can read from them.
(...skipping 21 matching lines...) Expand all
79 @implementation CRWBrowsingDataStore { 85 @implementation CRWBrowsingDataStore {
80 web::BrowserState* _browserState; // Weak, owns this object. 86 web::BrowserState* _browserState; // Weak, owns this object.
81 // The mode of the CRWBrowsingDataStore. 87 // The mode of the CRWBrowsingDataStore.
82 CRWBrowsingDataStoreMode _mode; 88 CRWBrowsingDataStoreMode _mode;
83 // The dictionary that maps a browsing data type to its 89 // The dictionary that maps a browsing data type to its
84 // CRWBrowsingDataManager. 90 // CRWBrowsingDataManager.
85 base::scoped_nsobject<NSDictionary> _browsingDataTypeMap; 91 base::scoped_nsobject<NSDictionary> _browsingDataTypeMap;
86 // The last operation that was enqueued to be run. Can be stash, restore or a 92 // The last operation that was enqueued to be run. Can be stash, restore or a
87 // delete operation. 93 // delete operation.
88 base::scoped_nsobject<NSOperation> _lastDispatchedOperation; 94 base::scoped_nsobject<NSOperation> _lastDispatchedOperation;
89 // The last stash or restore operations that was dispatched to be run. 95 // The number of stash or restore operations that are still pending. If this
90 base::scoped_nsobject<NSOperation> _lastDispatchedStashOrRestoreOperation; 96 // value > 0 the mode of the CRWBrowsingDataStore is SYNCHRONIZING. The mode
97 // can be made ACTIVE or INACTIVE only be set when this value is 0.
98 NSUInteger _numberOfPendingStashOrRestoreOperations;
91 } 99 }
92 100
93 + (NSOperationQueue*)operationQueueForStashAndRestoreOperations { 101 + (NSOperationQueue*)operationQueueForStashAndRestoreOperations {
94 static dispatch_once_t onceToken = 0; 102 static dispatch_once_t onceToken = 0;
95 static NSOperationQueue* operationQueueForStashAndRestoreOperations = nil; 103 static NSOperationQueue* operationQueueForStashAndRestoreOperations = nil;
96 dispatch_once(&onceToken, ^{ 104 dispatch_once(&onceToken, ^{
97 operationQueueForStashAndRestoreOperations = 105 operationQueueForStashAndRestoreOperations =
98 [[NSOperationQueue alloc] init]; 106 [[NSOperationQueue alloc] init];
99 [operationQueueForStashAndRestoreOperations 107 [operationQueueForStashAndRestoreOperations
100 setMaxConcurrentOperationCount:1U]; 108 setMaxConcurrentOperationCount:1U];
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
165 enumerateKeysAndObjectsUsingBlock:^(NSNumber* dataType, 173 enumerateKeysAndObjectsUsingBlock:^(NSNumber* dataType,
166 id<CRWBrowsingDataManager> manager, 174 id<CRWBrowsingDataManager> manager,
167 BOOL*) { 175 BOOL*) {
168 if ([dataType unsignedIntegerValue] & browsingDataTypes) { 176 if ([dataType unsignedIntegerValue] & browsingDataTypes) {
169 [result addObject:manager]; 177 [result addObject:manager];
170 } 178 }
171 }]; 179 }];
172 return result; 180 return result;
173 } 181 }
174 182
183 + (BOOL)automaticallyNotifiesObserversForKey:(NSString*)key {
184 // It is necessary to override this for |mode| because the default KVO
185 // behavior in NSObject is to fire a notification irrespective of if an actual
186 // change was made to the ivar or not. The |mode| property needs fine grained
187 // control over the actual notifications being fired since observers need to
188 // be notified iff the |mode| actually changed.
189 if ([key isEqual:@"mode"]) {
190 return NO;
191 }
192 return [super automaticallyNotifiesObserversForKey:(NSString*)key];
193 }
194
175 - (CRWBrowsingDataStoreMode)mode { 195 - (CRWBrowsingDataStoreMode)mode {
176 DCHECK([NSThread isMainThread]); 196 DCHECK([NSThread isMainThread]);
177 return _mode; 197 return _mode;
178 } 198 }
179 199
180 - (void)setMode:(CRWBrowsingDataStoreMode)mode { 200 - (void)setMode:(CRWBrowsingDataStoreMode)mode {
181 DCHECK([NSThread isMainThread]); 201 DCHECK([NSThread isMainThread]);
202 if (_mode == mode) {
203 return;
204 }
205 if (mode == ACTIVE || mode == INACTIVE) {
206 DCHECK(!self.numberOfPendingStashOrRestoreOperations);
207 }
208 [self willChangeValueForKey:@"mode"];
182 _mode = mode; 209 _mode = mode;
210 [self didChangeValueForKey:@"mode"];
183 } 211 }
184 212
185 - (void)setModeIfNotStashingOrRestoring:(CRWBrowsingDataStoreMode)mode { 213 - (void)finalizeChangeToMode:(CRWBrowsingDataStoreMode)mode
214 andCallCompletionHandler:(void (^)(BOOL modeChangeWasSuccessful))handler {
186 DCHECK([NSThread isMainThread]); 215 DCHECK([NSThread isMainThread]);
187 DCHECK_NE(SYNCHRONIZING, mode); 216 DCHECK_NE(SYNCHRONIZING, mode);
188 if ([_lastDispatchedStashOrRestoreOperation isFinished]) { 217
189 _mode = mode; 218 BOOL modeChangeWasSuccessful = NO;
219 if (!self.numberOfPendingStashOrRestoreOperations) {
220 [self setMode:mode];
221 modeChangeWasSuccessful = YES;
222 }
223 if (handler) {
224 handler(modeChangeWasSuccessful);
190 } 225 }
191 } 226 }
192 227
193 - (void)makeActiveWithCompletionHandler:(ProceduralBlock)completionHandler { 228 - (NSUInteger)numberOfPendingStashOrRestoreOperations {
229 DCHECK([NSThread isMainThread]);
230 return _numberOfPendingStashOrRestoreOperations;
231 }
232
233 - (void)setNumberOfPendingStashOrRestoreOperations:
234 (NSUInteger)numberOfPendingStashOrRestoreOperations {
235 DCHECK([NSThread isMainThread]);
236 _numberOfPendingStashOrRestoreOperations =
237 numberOfPendingStashOrRestoreOperations;
238 }
239
240 - (void)makeActiveWithCompletionHandler:
241 (void (^)(BOOL success))completionHandler {
194 DCHECK([NSThread isMainThread]); 242 DCHECK([NSThread isMainThread]);
195 243
196 base::WeakNSObject<CRWBrowsingDataStore> weakSelf(self); 244 base::WeakNSObject<CRWBrowsingDataStore> weakSelf(self);
197 [self performOperationWithType:RESTORE 245 [self performOperationWithType:RESTORE
198 browsingDataManagers:[self allBrowsingDataManagers] 246 browsingDataManagers:[self allBrowsingDataManagers]
199 completionHandler:^{ 247 completionHandler:^{
200 [weakSelf setModeIfNotStashingOrRestoring:ACTIVE]; 248 [weakSelf finalizeChangeToMode:ACTIVE
201 if (completionHandler) { 249 andCallCompletionHandler:completionHandler];
202 completionHandler();
203 }
204 }]; 250 }];
205 } 251 }
206 252
207 - (void)makeInactiveWithCompletionHandler:(ProceduralBlock)completionHandler { 253 - (void)makeInactiveWithCompletionHandler:
254 (void (^)(BOOL success))completionHandler {
208 DCHECK([NSThread isMainThread]); 255 DCHECK([NSThread isMainThread]);
209 256
210 base::WeakNSObject<CRWBrowsingDataStore> weakSelf(self); 257 base::WeakNSObject<CRWBrowsingDataStore> weakSelf(self);
211 [self performOperationWithType:STASH 258 [self performOperationWithType:STASH
212 browsingDataManagers:[self allBrowsingDataManagers] 259 browsingDataManagers:[self allBrowsingDataManagers]
213 completionHandler:^{ 260 completionHandler:^{
214 [weakSelf setModeIfNotStashingOrRestoring:INACTIVE]; 261 [weakSelf finalizeChangeToMode:INACTIVE
215 if (completionHandler) { 262 andCallCompletionHandler:completionHandler];
216 completionHandler();
217 }
218 }]; 263 }];
219 } 264 }
220 265
221 - (void)removeDataOfTypes:(web::BrowsingDataTypes)browsingDataTypes 266 - (void)removeDataOfTypes:(web::BrowsingDataTypes)browsingDataTypes
222 completionHandler:(ProceduralBlock)completionHandler { 267 completionHandler:(ProceduralBlock)completionHandler {
223 DCHECK([NSThread isMainThread]); 268 DCHECK([NSThread isMainThread]);
224 269
225 NSArray* browsingDataManagers = 270 NSArray* browsingDataManagers =
226 [self browsingDataManagersForBrowsingDataTypes:browsingDataTypes]; 271 [self browsingDataManagersForBrowsingDataTypes:browsingDataTypes];
227 [self performOperationWithType:REMOVE 272 [self performOperationWithType:REMOVE
(...skipping 27 matching lines...) Expand all
255 selector = @selector(restoreData); 300 selector = @selector(restoreData);
256 break; 301 break;
257 case REMOVE: 302 case REMOVE:
258 selector = @selector(removeData); 303 selector = @selector(removeData);
259 break; 304 break;
260 default: 305 default:
261 NOTREACHED(); 306 NOTREACHED();
262 break; 307 break;
263 }; 308 };
264 309
310 if (operationType == RESTORE || operationType == STASH) {
311 [self setMode:SYNCHRONIZING];
312 ++self.numberOfPendingStashOrRestoreOperations;
313 completionHandler = ^{
314 --self.numberOfPendingStashOrRestoreOperations;
315 // It is safe to this and does not lead to the block (|completionHandler|)
316 // retaining itself.
317 completionHandler();
318 };
319 }
320
265 id callCompletionHandlerOnMainThread = ^{ 321 id callCompletionHandlerOnMainThread = ^{
266 // This can be called on a background thread, hence the need to bounce to 322 // This is called on a background thread, hence the need to bounce to the
267 // the main thread. 323 // main thread.
268 dispatch_async(dispatch_get_main_queue(), ^{ 324 dispatch_async(dispatch_get_main_queue(), ^{
269 completionHandler(); 325 completionHandler();
270 }); 326 });
271 }; 327 };
272 base::scoped_nsobject<NSOperation> operation([self 328 base::scoped_nsobject<NSOperation> operation([self
273 newOperationWithBrowsingDataManagers:browsingDataManagers 329 newOperationWithBrowsingDataManagers:browsingDataManagers
274 selector:selector 330 selector:selector
275 completionHandler:callCompletionHandlerOnMainThread]); 331 completionHandler:callCompletionHandlerOnMainThread]);
276 332
277 if (operationType == RESTORE || operationType == STASH) {
278 _mode = SYNCHRONIZING;
279 _lastDispatchedStashOrRestoreOperation.reset([operation retain]);
280 }
281 333
282 NSOperationQueue* queue = nil; 334 NSOperationQueue* queue = nil;
283 switch (operationType) { 335 switch (operationType) {
284 case STASH: 336 case STASH:
285 case RESTORE: 337 case RESTORE:
286 queue = [CRWBrowsingDataStore operationQueueForStashAndRestoreOperations]; 338 queue = [CRWBrowsingDataStore operationQueueForStashAndRestoreOperations];
287 break; 339 break;
288 case REMOVE: 340 case REMOVE:
289 queue = [CRWBrowsingDataStore operationQueueForRemoveOperations]; 341 queue = [CRWBrowsingDataStore operationQueueForRemoveOperations];
290 break; 342 break;
(...skipping 27 matching lines...) Expand all
318 DCHECK(queue); 370 DCHECK(queue);
319 371
320 if (_lastDispatchedOperation) { 372 if (_lastDispatchedOperation) {
321 [operation addDependency:_lastDispatchedOperation]; 373 [operation addDependency:_lastDispatchedOperation];
322 } 374 }
323 _lastDispatchedOperation.reset([operation retain]); 375 _lastDispatchedOperation.reset([operation retain]);
324 [queue addOperation:operation]; 376 [queue addOperation:operation];
325 } 377 }
326 378
327 @end 379 @end
OLDNEW
« no previous file with comments | « no previous file | ios/web/crw_browsing_data_store_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698