Open xanderdunn opened 4 years ago
Hi @xanderdunn, first of all, I have to say that I don’t have experience with Swift on server and such multithreaded environments. Also, I haven’t tested OrderedDictionary
in such scenarios, so there might be potential issues within the library itself.
Do you have any thoughts on what might be going wrong here?
From what I can see in your very detailed description of the issue, it looks like it has something to do with access from multiple threads. Are you modifying the ordered dictionary dataStreams
while iterating over it, possibly from other threads, i.e. setting values to nil
for certain keys in the loop?
OrderedDictionary.orderedValues
returns a lazy sequence that operates on the underlying structure. In the upcoming version of the library (v4.0) I plan to change that to creating a copied Array
, but it’ll take some time until I release it. In the meantime, I’d suggest you to create a copy of the values (data streams) and iterate over it.
for myDataStream in Array(self.dataStreams.orderedValues) {
stopStreamsFutures.append(myDataStream.close())
}
There is a situation where I will set values to nil for existing keys when those MyData objects are no longer needed: self.dataStreams[myData] = nil, but this is indicated as the correct way to remove key-value pairs in the example code.
Yes, that’s correct. As mentioned above, the question is where this is triggered.
@lukaskubanek Thanks very much for the input. We recently switched over to InsertionOrderedDictionary
here, a part of a library that we were already using for other data structures.
We had another, unrelated situation where setting keys equal to nil and then later setting that same key to a non-nil value on OrderedDictionary
caused inconsistencies. The .count
of the OrderedDictionary
was off and our checksums were failing as a result of it. This situation was not multi-threaded. The OrderedDictionary
was read or written to only from the main thread. Unfortunately we haven't created a minimally reproducing example. If I were to start with a test for this, I'd try iterating through hundreds of thousands of non-unique key-value pairs, with random values that could include nil, and repeatedly set the keys on the OrderedDictionary
to any non-unique value. Check that .count
remains sane. You can close this issue when you'd like since we're no longer using the library.
Thanks for creating and maintaining this library, it's been very useful to me.
I recently encountered the below crashing error in OrderedDictionary while running my server:
which corresponds to this line. It appears that it's attempting to return
nil
for an existing key.My full backtrace:
MyDataHandler.swift:360 is this code in my project:
self.dataStreams
is:and
MyData
is a struct:I don't see this error on every server run. The only unusual aspect of this server run is that it hit a rare case where
MyData
keys had to be removed from the OrderedDictionary. There is a situation where I will set values tonil
for existing keys when thoseMyData
objects are no longer needed:self.dataStreams[myData] = nil
, but this is indicated as the correct way to remove key-value pairs in the example code. One possibility is that the keys that were set tonil
were later added back with a new value, but I don't think that should matter.My server is heavily multi-threaded, but I don't currently see any potential concurrency issues here. This particular call in my code is at the end of the server's life when a
stop
command has been issued to flush and close all data streams. The call is made on the main thread. Running with the thread sanitizer doesn't show any issues.Do you have any thoughts on what might be going wrong here?