Skip to content

Commit 983fa51

Browse files
[FSSDK-11900] fix: potential concurrent issue for cmab decision (#608)
* refactor: improve thread safety in getDecision function - Introduce a lock array to prevent race conditions - Implement getLockIndex method for calculating lock index based on user and rule IDs * refactor: update getLockIndex algorithm - Replace hash function with MurmurHash3 for improved performance - Calculate lockIndex directly instead of using intermediate variables
1 parent 5f38cf5 commit 983fa51

File tree

1 file changed

+24
-9
lines changed

1 file changed

+24
-9
lines changed

Sources/CMAB/CmabService.swift

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,25 +48,40 @@ class DefaultCmabService: CmabService {
4848
private let cmabCache: LruCache<String, CmabCacheValue>
4949
private let logger = OPTLoggerFactory.getLogger()
5050

51+
private static let NUM_LOCKS = 1000
52+
private let locks: [NSLock]
53+
5154
init(cmabClient: CmabClient, cmabCache: LruCache<String, CmabCacheValue>) {
5255
self.cmabClient = cmabClient
5356
self.cmabCache = cmabCache
57+
self.locks = (0..<Self.NUM_LOCKS).map { _ in NSLock() }
58+
}
59+
60+
private func getLockIndex(userId: String, ruleId: String) -> Int {
61+
let combinedKey = userId + ruleId
62+
let hashValue = MurmurHash3.hash32(key: combinedKey)
63+
let lockIndex = Int(hashValue) % Self.NUM_LOCKS
64+
return lockIndex
5465
}
5566

5667
func getDecision(config: ProjectConfig,
5768
userContext: OptimizelyUserContext,
5869
ruleId: String,
5970
options: [OptimizelyDecideOption]) -> Result<CmabDecision, Error> {
60-
var result: Result<CmabDecision, Error>!
61-
let semaphore = DispatchSemaphore(value: 0)
62-
getDecision(config: config,
63-
userContext: userContext,
64-
ruleId: ruleId, options: options) { _result in
65-
result = _result
66-
semaphore.signal()
71+
let lockIdx = getLockIndex(userId: userContext.userId, ruleId: ruleId)
72+
let lock = locks[lockIdx]
73+
return lock.withLock {
74+
var result: Result<CmabDecision, Error>!
75+
let semaphore = DispatchSemaphore(value: 0)
76+
getDecision(config: config,
77+
userContext: userContext,
78+
ruleId: ruleId, options: options) { _result in
79+
result = _result
80+
semaphore.signal()
81+
}
82+
semaphore.wait()
83+
return result
6784
}
68-
semaphore.wait()
69-
return result
7085
}
7186

7287
func getDecision(config: ProjectConfig,

0 commit comments

Comments
 (0)