18
18
#import " GDTStorage_Private.h"
19
19
20
20
#import < GoogleDataTransport/GDTPrioritizer.h>
21
+ #import < GoogleDataTransport/GDTStoredEvent.h>
21
22
22
23
#import " GDTAssert.h"
23
24
#import " GDTConsoleLogger.h"
@@ -55,8 +56,8 @@ - (instancetype)init {
55
56
self = [super init ];
56
57
if (self) {
57
58
_storageQueue = dispatch_queue_create (" com.google.GDTStorage" , DISPATCH_QUEUE_SERIAL);
58
- _eventHashToFile = [[NSMutableDictionary alloc ] init ];
59
- _targetToEventHashSet = [[NSMutableDictionary alloc ] init ];
59
+ _targetToEventSet = [[NSMutableDictionary alloc ] init ];
60
+ _storedEvents = [[NSMutableOrderedSet alloc ] init ];
60
61
_uploader = [GDTUploadCoordinator sharedInstance ];
61
62
}
62
63
return self;
@@ -65,94 +66,64 @@ - (instancetype)init {
65
66
- (void )storeEvent : (GDTEvent *)event {
66
67
[self createEventDirectoryIfNotExists ];
67
68
68
- // This is done to ensure that event is deallocated at the end of the ensuing block.
69
- __block GDTEvent *shortLivedEvent = event;
70
- __weak GDTEvent *weakShortLivedEvent = event;
71
- event = nil ;
72
-
73
69
dispatch_async (_storageQueue, ^{
74
70
// Check that a backend implementation is available for this target.
75
- NSInteger target = shortLivedEvent .target ;
71
+ NSInteger target = event .target ;
76
72
77
73
// Check that a prioritizer is available for this target.
78
74
id <GDTPrioritizer> prioritizer = [GDTRegistrar sharedInstance ].targetToPrioritizer [@(target)];
79
75
GDTAssert (prioritizer, @" There's no prioritizer registered for the given target." );
80
76
81
77
// Write the transport bytes to disk, get a filename.
82
- GDTAssert (shortLivedEvent .dataObjectTransportBytes ,
83
- @" The event should have been serialized to bytes " );
84
- NSURL *eventFile = [ self saveEventBytesToDisk: shortLivedEvent.dataObjectTransportBytes
85
- eventHash: shortLivedEvent.hash ];
78
+ GDTAssert (event .dataObjectTransportBytes , @" The event should have been serialized to bytes " );
79
+ NSURL *eventFile = [ self saveEventBytesToDisk: event.dataObjectTransportBytes
80
+ eventHash: event.hash];
81
+ GDTStoredEvent *storedEvent = [event storedEventWithFileURL: eventFile ];
86
82
87
83
// Add event to tracking collections.
88
- [self addEventToTrackingCollections: shortLivedEvent eventFile: eventFile ];
84
+ [self addEventToTrackingCollections: storedEvent ];
89
85
90
86
// Check the QoS, if it's high priority, notify the target that it has a high priority event.
91
- if (shortLivedEvent .qosTier == GDTEventQoSFast) {
92
- NSSet <NSNumber *> *allEventsForTarget = self.targetToEventHashSet [@( target) ];
87
+ if (event .qosTier == GDTEventQoSFast) {
88
+ NSSet <GDTStoredEvent *> *allEventsForTarget = self.targetToEventSet [storedEvent. target];
93
89
[self .uploader forceUploadEvents: allEventsForTarget target: target];
94
90
}
95
91
96
- // Have the prioritizer prioritize the event, enforcing that they do not retain it.
97
- @autoreleasepool {
98
- [prioritizer prioritizeEvent: shortLivedEvent];
99
- shortLivedEvent = nil ;
100
- }
101
- if (weakShortLivedEvent) {
102
- GDTLogError (GDTMCEEventWasIllegallyRetained, @" %@ " ,
103
- @" An event should not be retained outside of storage." );
104
- };
92
+ // Have the prioritizer prioritize the event.
93
+ [prioritizer prioritizeEvent: storedEvent];
105
94
});
106
95
}
107
96
108
- - (void )removeEvents : (NSSet <NSNumber *> *)eventHashes target : (NSNumber *)target {
109
- dispatch_sync (_storageQueue, ^{
110
- for (NSNumber *eventHash in eventHashes) {
111
- [self removeEvent: eventHash target: target];
112
- }
113
- });
114
- }
115
-
116
- - (NSDictionary <NSNumber *, NSURL *> *)eventHashesToFiles : (NSSet <NSNumber *> *)eventHashes {
117
- NSMutableDictionary <NSNumber *, NSURL *> *eventHashesToFiles = [[NSMutableDictionary alloc ] init ];
118
- dispatch_sync (_storageQueue, ^{
119
- for (NSNumber *hashNumber in eventHashes) {
120
- NSURL *eventURL = self.eventHashToFile [hashNumber];
121
- GDTAssert (eventURL, @" An event file URL couldn't be found for the given hash" );
122
- eventHashesToFiles[hashNumber] = eventURL;
97
+ - (void )removeEvents : (NSSet <GDTStoredEvent *> *)events {
98
+ NSSet <GDTStoredEvent *> *eventsToRemove = [events copy ];
99
+ dispatch_async (_storageQueue, ^{
100
+ // Check that a prioritizer is available for this target.
101
+ id <GDTPrioritizer> prioritizer;
102
+
103
+ for (GDTStoredEvent *event in eventsToRemove) {
104
+ // Remove from disk, first and foremost.
105
+ NSError *error;
106
+ [[NSFileManager defaultManager ] removeItemAtURL: event.eventFileURL error: &error];
107
+ GDTAssert (error == nil , @" There was an error removing an event file: %@ " , error);
108
+
109
+ if (!prioritizer) {
110
+ prioritizer = [GDTRegistrar sharedInstance ].targetToPrioritizer [event.target];
111
+ } else {
112
+ GDTAssert (prioritizer == [GDTRegistrar sharedInstance ].targetToPrioritizer [event.target],
113
+ @" All logs within an upload set should have the same prioritizer." );
114
+ }
115
+
116
+ // Remove from the tracking collections.
117
+ [self .storedEvents removeObject: event];
118
+ [self .targetToEventSet[event.target] removeObject: event];
123
119
}
120
+ GDTAssert (prioritizer, @" There's no prioritizer registered for the given target." );
121
+ [prioritizer unprioritizeEvents: events];
124
122
});
125
- return eventHashesToFiles;
126
123
}
127
124
128
125
#pragma mark - Private helper methods
129
126
130
- /* * Removes the corresponding event file from disk.
131
- *
132
- * @param eventHash The hash value of the original event.
133
- * @param target The target of the original event.
134
- */
135
- - (void )removeEvent : (NSNumber *)eventHash target : (NSNumber *)target {
136
- NSURL *eventFile = self.eventHashToFile [eventHash];
137
-
138
- // Remove from disk, first and foremost.
139
- NSError *error;
140
- [[NSFileManager defaultManager ] removeItemAtURL: eventFile error: &error];
141
- GDTAssert (error == nil , @" There was an error removing an event file: %@ " , error);
142
-
143
- // Remove from the tracking collections.
144
- [self .eventHashToFile removeObjectForKey: eventHash];
145
- NSMutableSet <NSNumber *> *eventHashes = self.targetToEventHashSet [target];
146
- GDTAssert (eventHashes, @" There wasn't an event set for this target." );
147
- [eventHashes removeObject: eventHash];
148
- // It's fine to not remove the set if it's empty.
149
-
150
- // Check that a prioritizer is available for this target.
151
- id <GDTPrioritizer> prioritizer = [GDTRegistrar sharedInstance ].targetToPrioritizer [target];
152
- GDTAssert (prioritizer, @" There's no prioritizer registered for the given target." );
153
- [prioritizer unprioritizeEvent: eventHash];
154
- }
155
-
156
127
/* * Creates the storage directory if it does not exist. */
157
128
- (void )createEventDirectoryIfNotExists {
158
129
NSError *error;
@@ -179,6 +150,9 @@ - (NSURL *)saveEventBytesToDisk:(NSData *)transportBytes eventHash:(NSUInteger)e
179
150
NSString *event = [NSString stringWithFormat: @" event-%lu " , (unsigned long )eventHash];
180
151
NSURL *eventFilePath = [NSURL fileURLWithPath: [storagePath stringByAppendingPathComponent: event]];
181
152
153
+ GDTAssert (![[NSFileManager defaultManager ] fileExistsAtPath: eventFilePath.path],
154
+ @" An event shouldn't already exist at this path: %@ " , eventFilePath.path );
155
+
182
156
BOOL writingSuccess = [transportBytes writeToURL: eventFilePath atomically: YES ];
183
157
if (!writingSuccess) {
184
158
GDTLogError (GDTMCEFileWriteError, @" An event file could not be written: %@ " , eventFilePath);
@@ -193,29 +167,22 @@ - (NSURL *)saveEventBytesToDisk:(NSData *)transportBytes eventHash:(NSUInteger)e
193
167
* thread safety.
194
168
*
195
169
* @param event The event to track.
196
- * @param eventFile The file the event has been saved to.
197
170
*/
198
- - (void )addEventToTrackingCollections : (GDTEvent *)event eventFile : (NSURL *)eventFile {
199
- NSInteger target = event.target ;
200
- NSNumber *eventHash = @(event.hash );
201
- NSNumber *targetNumber = @(target);
202
- self.eventHashToFile [eventHash] = eventFile;
203
- NSMutableSet <NSNumber *> *events = self.targetToEventHashSet [targetNumber];
204
- if (events) {
205
- [events addObject: eventHash];
206
- } else {
207
- NSMutableSet <NSNumber *> *eventSet = [NSMutableSet setWithObject: eventHash];
208
- self.targetToEventHashSet [targetNumber] = eventSet;
209
- }
171
+ - (void )addEventToTrackingCollections : (GDTStoredEvent *)event {
172
+ [_storedEvents addObject: event];
173
+ NSMutableSet <GDTStoredEvent *> *events = self.targetToEventSet [event.target];
174
+ events = events ? events : [[NSMutableSet alloc ] init ];
175
+ [events addObject: event];
176
+ _targetToEventSet[event.target] = events;
210
177
}
211
178
212
179
#pragma mark - NSSecureCoding
213
180
214
- /* * The NSKeyedCoder key for the eventHashToFile property. */
215
- static NSString *const kGDTEventHashToFileKey = @" eventHashToFileKey " ;
181
+ /* * The NSKeyedCoder key for the storedEvents property. */
182
+ static NSString *const kGDTStorageStoredEventsKey = @" GDTStorageStoredEventsKey " ;
216
183
217
- /* * The NSKeyedCoder key for the targetToEventHashSet property. */
218
- static NSString *const kGDTTargetToEventHashSetKey = @" targetToEventHashSetKey " ;
184
+ /* * The NSKeyedCoder key for the targetToEventSet property. */
185
+ static NSString *const kGDTStorageTargetToEventSetKey = @" GDTStorageTargetToEventSetKey " ;
219
186
220
187
+ (BOOL )supportsSecureCoding {
221
188
return YES ;
@@ -225,20 +192,20 @@ - (instancetype)initWithCoder:(NSCoder *)aDecoder {
225
192
// Create the singleton and populate its ivars.
226
193
GDTStorage *sharedInstance = [self .class sharedInstance ];
227
194
dispatch_sync (sharedInstance.storageQueue , ^{
228
- Class NSMutableDictionaryClass = [NSMutableDictionary class ];
229
- sharedInstance-> _eventHashToFile = [aDecoder decodeObjectOfClass: NSMutableDictionaryClass
230
- forKey: kGDTEventHashToFileKey ];
231
- sharedInstance-> _targetToEventHashSet =
232
- [aDecoder decodeObjectOfClass: NSMutableDictionaryClass forKey: kGDTTargetToEventHashSetKey ];
195
+ sharedInstance-> _storedEvents = [aDecoder decodeObjectOfClass: [ NSMutableOrderedSet class ]
196
+ forKey: kGDTStorageStoredEventsKey ];
197
+ sharedInstance-> _targetToEventSet =
198
+ [aDecoder decodeObjectOfClass: [ NSMutableDictionary class ]
199
+ forKey: kGDTStorageTargetToEventSetKey ];
233
200
});
234
201
return sharedInstance;
235
202
}
236
203
237
204
- (void )encodeWithCoder : (NSCoder *)aCoder {
238
205
GDTStorage *sharedInstance = [self .class sharedInstance ];
239
206
dispatch_sync (sharedInstance.storageQueue , ^{
240
- [aCoder encodeObject: sharedInstance->_eventHashToFile forKey: kGDTEventHashToFileKey ];
241
- [aCoder encodeObject: sharedInstance->_targetToEventHashSet forKey: kGDTTargetToEventHashSetKey ];
207
+ [aCoder encodeObject: sharedInstance->_storedEvents forKey: kGDTStorageStoredEventsKey ];
208
+ [aCoder encodeObject: sharedInstance->_targetToEventSet forKey: kGDTStorageTargetToEventSetKey ];
242
209
});
243
210
}
244
211
0 commit comments