Skip to content

Commit ab35faf

Browse files
committed
Dynamic buffer experiment
1 parent 85f7e2f commit ab35faf

File tree

2 files changed

+50
-93
lines changed

2 files changed

+50
-93
lines changed

Example/Example/Info.plist

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
33
<plist version="1.0">
44
<dict>
5-
<key>NSUserTrackingUsageDescription</key>
6-
<string>This identifier will be used to deliver personalized ads to you.</string>
5+
<key>CFBundleURLTypes</key>
6+
<array/>
77
<key>UIApplicationSceneManifest</key>
88
<dict>
99
<key>UIApplicationSupportsMultipleScenes</key>

MindboxLogger/Shared/LoggerRepository/MBLoggerCoreDataManager.swift

Lines changed: 48 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,11 @@ public class MBLoggerCoreDataManager {
2525
static let model = "CDLogMessage"
2626
static let dbSizeLimitKB: Int = 10_000
2727
static let operationLimitBeforeNeedToDelete = 20
28-
static let batchSize = 10
28+
// static let batchSize = 10
2929
}
3030

31-
private var logBuffer: [LogMessage] = []
31+
private var logQueue: [LogMessage] = []
32+
private var isWriting = false
3233

3334
private let queue = DispatchQueue(label: "com.Mindbox.loggerManager", qos: .utility)
3435
private var persistentStoreDescription: NSPersistentStoreDescription?
@@ -85,122 +86,78 @@ public class MBLoggerCoreDataManager {
8586
}()
8687

8788
// MARK: - CRUD Operations
88-
// public func create(message: String, timestamp: Date, completion: (() -> Void)? = nil) {
89-
// queue.async {
90-
// do {
91-
// let isTimeToDelete = self.writeCount == 0
92-
// self.writeCount += 1
93-
// if isTimeToDelete && self.getDBFileSize() > Constants.dbSizeLimitKB {
94-
// try self.delete()
95-
// }
96-
//
97-
// try self.context.executePerformAndWait {
98-
// let entity = CDLogMessage(context: self.context)
99-
// entity.message = message
100-
// entity.timestamp = timestamp
101-
// try self.saveEvent(withContext: self.context)
102-
//
103-
// completion?()
104-
// }
105-
// } catch {}
106-
// }
107-
// }
108-
10989
public func create(message: String, timestamp: Date, completion: (() -> Void)? = nil) {
110-
guard #available(iOS 15.0, *) else { return }
111-
112-
let signpostID = Self.signposter.makeSignpostID()
90+
queue.async { [weak self] in
91+
guard let self = self else { return }
92+
self.logQueue.append(LogMessage(timestamp: timestamp, message: message))
11393

114-
let state = Self.signposter.beginInterval(#function, id: signpostID, "Start creating")
115-
116-
queue.async {
117-
Self.signposter.emitEvent("Start creating LogMessage for buffer", id: signpostID)
118-
self.logBuffer.append(LogMessage(timestamp: timestamp, message: message))
119-
120-
if self.logBuffer.count >= Constants.batchSize {
121-
Self.signposter.emitEvent("Start flushing buffer if logBuffer is full", id: signpostID)
122-
self.flushBuffer()
123-
Self.signposter.endInterval(#function, state, "End flushing buffer")
124-
completion?()
125-
return
94+
if !self.isWriting {
95+
self.writeNextBatch()
12696
}
12797

128-
Self.signposter.endInterval(#function, state, "End creating LogMessage for buffer")
12998
completion?()
13099
}
131100
}
132101

133-
private func flushBuffer() {
134-
guard #available(iOS 15.0, *) else { return }
135-
136-
let signpostID = Self.signposterFlushBuffer.makeSignpostID()
102+
private func writeNextBatch() {
103+
guard !logQueue.isEmpty else { return }
137104

138-
let state = Self.signposterFlushBuffer.beginInterval(#function, id: signpostID, "Start flushing buffer")
139-
140-
guard !logBuffer.isEmpty else {
141-
Self.signposterFlushBuffer.endInterval(#function, state, "LogBuffer isEmpty")
142-
return
143-
}
105+
isWriting = true
106+
let logsToWrite = logQueue
107+
logQueue.removeAll()
144108

145109
if #available(iOS 13.0, *) {
146-
// Use NSBatchInsertRequest for iOS 13 and above
147-
Self.signposterFlushBuffer.emitEvent("Core Data Insert Batch Operation Started", id: signpostID)
148-
performBatchInsert()
110+
performBatchInsert(logs: logsToWrite)
149111
} else {
150-
// Fallback to context-based insertion for iOS 12
151-
performContextInsertion()
112+
performContextInsertion(logs: logsToWrite)
152113
}
153-
154-
Self.signposterFlushBuffer.endInterval(#function, state, "End flushing buffer")
155-
checkDatabaseSizeAndDeleteIfNeeded()
156-
//
157-
// do {
158-
// try context.executePerformAndWait {
159-
// for log in self.logBuffer {
160-
// Self.signposterFlushBuffer.emitEvent("CDLog creating for context", id: signpostID)
161-
// let entity = CDLogMessage(context: self.context)
162-
// entity.message = log.message
163-
// entity.timestamp = log.timestamp
164-
// }
165-
//
166-
// Self.signposterFlushBuffer.emitEvent("Core Data Save Context Operation Started", id: signpostID)
167-
// try self.saveEvent(withContext: self.context)
168-
// self.logBuffer.removeAll()
169-
// self.checkDatabaseSizeAndDeleteIfNeeded()
170-
// Self.signposterFlushBuffer.endInterval(#function, state, "End flushing buffer")
171-
// }
172-
// } catch {
173-
// print("Failed to flush logs: \(error)")
174-
// Self.signposterFlushBuffer.endInterval(#function, state, "Error occurred during flushing buffer")
175-
// }
176114
}
177115

178116
@available(iOS 13.0, *)
179-
private func performBatchInsert() {
180-
let insertData = logBuffer.map { ["message": $0.message, "timestamp": $0.timestamp] }
117+
private func performBatchInsert(logs: [LogMessage]) {
118+
print(#function)
119+
print(logs.count)
120+
let insertData = logs.map { ["message": $0.message, "timestamp": $0.timestamp] }
181121
let insertRequest = NSBatchInsertRequest(entityName: Constants.model, objects: insertData)
182122

183-
do {
184-
try context.execute(insertRequest)
185-
logBuffer.removeAll()
186-
} catch {
187-
print("Failed to batch insert logs: \(error)")
123+
context.perform { [weak self] in
124+
guard let self = self else { return }
125+
do {
126+
try self.context.execute(insertRequest)
127+
self.finishWriting()
128+
} catch {
129+
print("Failed to batch insert logs: \(error)")
130+
self.finishWriting()
131+
}
188132
}
189133
}
190134

191-
private func performContextInsertion() {
192-
do {
193-
try context.executePerformAndWait {
194-
for log in self.logBuffer {
135+
private func performContextInsertion(logs: [LogMessage]) {
136+
context.perform { [weak self] in
137+
guard let self = self else { return }
138+
do {
139+
for log in logs {
195140
let entity = CDLogMessage(context: self.context)
196141
entity.message = log.message
197142
entity.timestamp = log.timestamp
198143
}
199144
try self.saveEvent(withContext: self.context)
200-
self.logBuffer.removeAll()
145+
self.finishWriting()
146+
} catch {
147+
print("Failed to flush logs: \(error)")
148+
self.finishWriting()
149+
}
150+
}
151+
}
152+
153+
private func finishWriting() {
154+
self.queue.async { [weak self] in
155+
guard let self = self else { return }
156+
self.isWriting = false
157+
self.checkDatabaseSizeAndDeleteIfNeeded()
158+
if !self.logQueue.isEmpty {
159+
self.writeNextBatch()
201160
}
202-
} catch {
203-
print("Failed to flush logs: \(error)")
204161
}
205162
}
206163

0 commit comments

Comments
 (0)