Skip to content

Commit 6bba3ed

Browse files
authored
SWIFT-1072 Improve result parsing performance (#595)
1 parent ac623cb commit 6bba3ed

File tree

2 files changed

+51
-18
lines changed

2 files changed

+51
-18
lines changed

Sources/MongoSwift/BSON/BSONPointerUtils.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
import CLibMongoC
22
import Foundation
3+
import NIO
34

45
internal typealias BSONPointer = UnsafePointer<bson_t>
56
internal typealias MutableBSONPointer = UnsafeMutablePointer<bson_t>
67

8+
/// This shared allocator instance should be used for all `ByteBuffer` creations.
9+
internal let MONGOSWIFT_ALLOCATOR = ByteBufferAllocator()
10+
711
/**
812
* Executes the given closure with a read-only `BSONPointer` to the provided `BSONDocument` if non-nil.
913
* The pointer will only be valid within the body of the closure, and it MUST NOT be persisted outside of it.
@@ -45,7 +49,8 @@ extension SwiftBSON.BSONDocument {
4549
}
4650
let bufferPtr = UnsafeBufferPointer(start: ptr, count: Int(bsonPtr.pointee.len))
4751
do {
48-
try self.init(fromBSON: Data(bufferPtr))
52+
let buf = MONGOSWIFT_ALLOCATOR.buffer(bytes: bufferPtr)
53+
try self.init(fromBSONWithoutValidatingElements: buf)
4954
} catch {
5055
fatalError("Failed initializing BSONDocument from bson_t: \(error)")
5156
}

Sources/MongoSwift/MongoCollection+BulkWrite.swift

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -412,29 +412,57 @@ public struct BulkWriteResult: Codable {
412412
* - `MongoError.InternalError` if an unexpected error occurs reading the reply from the server.
413413
*/
414414
fileprivate init?(reply: BSONDocument, insertedIDs: [Int: BSON]) throws {
415-
guard reply.keys.contains(where: { MongocKeys(rawValue: $0) != nil }) else {
416-
return nil
417-
}
418-
419-
self.deletedCount = reply[MongocKeys.deletedCount.rawValue]?.toInt() ?? 0
420-
421-
self.insertedCount = reply[MongocKeys.insertedCount.rawValue]?.toInt() ?? 0
422-
self.insertedIDs = insertedIDs
423-
self.matchedCount = reply[MongocKeys.matchedCount.rawValue]?.toInt() ?? 0
424-
self.modifiedCount = reply[MongocKeys.modifiedCount.rawValue]?.toInt() ?? 0
425-
self.upsertedCount = reply[MongocKeys.upsertedCount.rawValue]?.toInt() ?? 0
426-
415+
var deletedCount: Int?
416+
var insertedCount: Int?
417+
var matchedCount: Int?
418+
var modifiedCount: Int?
419+
var upsertedCount: Int?
427420
var upsertedIDs = [Int: BSON]()
428421

429-
if let upserted = reply[MongocKeys.upserted.rawValue]?.arrayValue {
430-
for upsert in upserted.compactMap({ $0.documentValue }) {
431-
guard let index = upsert["index"]?.toInt() else {
432-
throw MongoError.InternalError(message: "Could not cast upserted index to `Int`")
422+
// To improve the performance of this initializer, we perform only a single walk over the entire document and
423+
// record the values as they are encountered instead of doing repeated random lookups, since each lookup
424+
// would result in a traversal of the document.
425+
var seenKey = false
426+
for (k, v) in reply {
427+
guard let key = MongocKeys(rawValue: k) else {
428+
continue
429+
}
430+
431+
seenKey = true
432+
433+
switch key {
434+
case .deletedCount:
435+
deletedCount = v.toInt()
436+
case .insertedCount:
437+
insertedCount = v.toInt()
438+
case .matchedCount:
439+
matchedCount = v.toInt()
440+
case .modifiedCount:
441+
modifiedCount = v.toInt()
442+
case .upsertedCount:
443+
upsertedCount = v.toInt()
444+
case .upserted:
445+
if let upserted = reply[MongocKeys.upserted.rawValue]?.arrayValue?.compactMap({ $0.documentValue }) {
446+
for upsert in upserted {
447+
guard let index = upsert["index"]?.toInt() else {
448+
throw MongoError.InternalError(message: "Could not cast upserted index to `Int`")
449+
}
450+
upsertedIDs[index] = upsert["_id"]
451+
}
433452
}
434-
upsertedIDs[index] = upsert["_id"]
435453
}
436454
}
437455

456+
guard seenKey else {
457+
return nil
458+
}
459+
460+
self.deletedCount = deletedCount ?? 0
461+
self.insertedCount = insertedCount ?? 0
462+
self.insertedIDs = insertedIDs
463+
self.matchedCount = matchedCount ?? 0
464+
self.modifiedCount = modifiedCount ?? 0
465+
self.upsertedCount = upsertedCount ?? 0
438466
self.upsertedIDs = upsertedIDs
439467
}
440468

0 commit comments

Comments
 (0)