internal void ExpandStorage(int newCount) { // There is no need to take additional locks (assuming that a read lock is already being held), // because of the way how every expandable array takes care of its expansion (e.g. grow-only, block-oriented). // Compaction might break this logic, but it will have to be executed while holding StructureLock in writable mode. // The only important global state is our capacity, which is a volatile variable. var currentCapacity = m_capacity; if (currentCapacity < newCount) { if (!StructureLock.IsReadLockHeld && !StructureLock.IsWriteLockHeld && !StructureLock.IsUpgradeableReadLockHeld) { throw new InvalidOperationException("StructureLock must be held in any mode in order to start expansion"); } var newCapacity = newCount - (newCount % GrowthIncrement) + GrowthIncrement; // first, expand field storage int goodCount; do { goodCount = 0; foreach (var store in ColumnStores) { if (m_capacity >= newCapacity) { // some other thread has completed the expansion // stop whatever we are doing here return; } // use "Try" variation here to allow multi-threaded allocation for blocks if (store.TryEnsureCapacity(newCapacity)) { goodCount++; } } if (goodCount <= ColumnStores.Length / 2) { // seems like other threads are making progress on expansion too, // let them do something Thread.Yield(); } } while (goodCount != ColumnStores.Length && m_capacity < newCapacity); // also expand backbone structures DocumentKeys.EnsureCapacity(newCapacity); ValidDocumentsBitmap.EnsureCapacity(newCapacity); // have to be careful here, multiple threads compete to set this value // some of those had new value for capacity larger or smaller than ours currentCapacity = m_capacity; while (currentCapacity < newCapacity) { currentCapacity = Interlocked.CompareExchange(ref m_capacity, newCapacity, currentCapacity); } } }
unsafe ExpandableArrayOfKeys GenerateKeys(ulong count) { var result = new ExpandableArrayOfKeys(_pool); result.EnsureCapacity(count); var key = new byte[10]; for (ulong i = 1; i <= count; i++) { var val = i; byte pos = 1; while (val != 0) { key[pos++] = (byte)val; val >>= 8; } key[0] = (byte)(pos-1); //result[i-1] = key; if (!result.TrySetAt((int)i - 1, key)) { throw new Exception("Failed to set a key element at " + (i-1)); } } for (ulong i = 1; i <= count; i++) { var storedKey = result.GetAt(i-1); var val = i; byte pos = 1; while (val != 0) { key[pos++] = (byte)val; val >>= 8; } key[0] = (byte)(pos-1); if (storedKey[0] != key[0]) { throw new Exception("Length prefix broken at " + (i - 1)); } for (var j = 0; j <= key[0]; j++) { //Console.Write(storedKey[j]); //Console.Write(','); if (storedKey[j] != key[j]) { throw new Exception("Data broken at " + (i - 1) + ", offset " + j); } } //Console.WriteLine(); } return result; }
unsafe ExpandableArrayOfKeys GenerateKeys(ulong count) { var result = new ExpandableArrayOfKeys(_pool); result.EnsureCapacity(count); var key = new byte[10]; for (ulong i = 1; i <= count; i++) { var val = i; byte pos = 1; while (val != 0) { key[pos++] = (byte)val; val >>= 8; } key[0] = (byte)(pos - 1); //result[i-1] = key; if (!result.TrySetAt((int)i - 1, key)) { throw new Exception("Failed to set a key element at " + (i - 1)); } } for (ulong i = 1; i <= count; i++) { var storedKey = result.GetAt(i - 1); var val = i; byte pos = 1; while (val != 0) { key[pos++] = (byte)val; val >>= 8; } key[0] = (byte)(pos - 1); if (storedKey[0] != key[0]) { throw new Exception("Length prefix broken at " + (i - 1)); } for (var j = 0; j <= key[0]; j++) { //Console.Write(storedKey[j]); //Console.Write(','); if (storedKey[j] != key[j]) { throw new Exception("Data broken at " + (i - 1) + ", offset " + j); } } //Console.WriteLine(); } return(result); }