예제 #1
0
        /// <summary>
        /// After insert, checks whether a split should be initiated and whether there are buckets which need to be split
        /// </summary>
        private void PerformPostInsertSplitOperations(ref Accessors accessors, int count)
        {
            // If necessary, trigger a split.
            if (Buckets.GrowIfNecessary(ref m_buckets, count))
            {
                return;
            }

            int splitBucketNo;
            int targetBucketNo;

            if (m_buckets.TryGetBucketToSplit(out splitBucketNo, out targetBucketNo))
            {
                // Only need to get lock for split bucket since target bucket
                // will always use the same lock
                int splitLockNo = GetLockNo(splitBucketNo);
                using (var writeLock = m_locks.AcquireWriteLock(splitLockNo, allowReads: true))
                {
                    var nodeIndex = m_buckets[splitBucketNo];
                    if (nodeIndex >= 0)
                    {
                        // We only need to exclude reads if the bucket actually has nodes which may need to be split.
                        writeLock.ExcludeReads();
                    }

                    int lastSplitNodeIndex  = -3;
                    int lastTargetNodeIndex = -3;

                    while (nodeIndex >= 0)
                    {
                        var node          = accessors.Nodes[nodeIndex];
                        var nextNodeIndex = node.Next;
                        int bucketNo      = m_buckets.GetBucketNo(node.Hashcode);

                        Node newNode;
                        if (bucketNo == splitBucketNo)
                        {
                            newNode            = new Node(node.Hashcode, lastSplitNodeIndex);
                            lastSplitNodeIndex = nodeIndex;
                        }
                        else
                        {
                            newNode             = new Node(node.Hashcode, lastTargetNodeIndex);
                            lastTargetNodeIndex = nodeIndex;
                        }

                        accessors.Nodes[nodeIndex] = newNode;
                        nodeIndex = nextNodeIndex;
                    }

                    m_buckets.SetBucketHeadNodeIndexDirect(splitBucketNo, lastSplitNodeIndex);
                    m_buckets.SetBucketHeadNodeIndexDirect(targetBucketNo, lastTargetNodeIndex);

                    m_buckets.EndBucketSplit();
                }
            }
        }