Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix map iterators #73

Merged
merged 7 commits into from
Apr 9, 2020
Merged

Fix map iterators #73

merged 7 commits into from
Apr 9, 2020

Conversation

qurbonzoda
Copy link
Contributor

Also addresses #68

@qurbonzoda qurbonzoda requested a review from ilya-g March 27, 2020 01:53
override fun setValue(newValue: V): V {
val result = value
value = newValue
builder[key] = newValue
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is the bug #68.
The value is updated bypassing the iterator this mutable entry was obtained from.

@@ -144,6 +147,7 @@ internal abstract class PersistentHashMapBaseIterator<K, V, T>(node: TrieNode<K,
if (i > 0) {
path[i - 1].moveToNextNode()
}
path[i].reset(TrieNode.EMPTY.buffer, 0)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we release iterated nodes to avoid memory leaks

// assert(buffer[nodeIndex] !== newNode)

val newNodeBuffer = newNode.buffer
if (newNodeBuffer.size == 2 && newNode.nodeMap == 0) {
Copy link
Contributor Author

@qurbonzoda qurbonzoda Mar 30, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here canonicalisation of trie can change order of iteration (see below), therefore I removed canonicalisation for mutable maps as the update may be made by an iterator currently iterating the map builder.

------------------------------          iterator.remove() after            -------------------------------
| k1 | v1 | k3 | v3 | child1 |      iterator.next() returned (k4, v4)      | k1 | v1 | k2 | v2 | k3 | v3 |
------------------------|-----                                             -------------------------------
                        |                       -->
              ---------------------
              | k4 | v4 | k2 | v2 |
              ---------------------

mutator.size--
mutator.operationResult = valueAtKeyIndex(keyIndex)
if (buffer.size == ENTRY_SIZE) return null
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mutable map is not canonicalised, nodes containing a single entry can occur.

// assert(hasEntryAt(positionMask))
// assert(buffer.size > ENTRY_SIZE) // can be false only for the root node
if (buffer.size == ENTRY_SIZE) return null
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The persistent map could be built by a non-canonical builder

@qurbonzoda qurbonzoda merged commit 0a322dd into master Apr 9, 2020
@qurbonzoda qurbonzoda deleted the fix-map-iterators branch August 24, 2020 02:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants