Пример #1
0
        private void AsyncOperationCompleting()
        {
            int oldValue = Interlocked.CompareExchange(ref _activeAsyncOperation, 0, 1);

            Debug.Assert(oldValue == 1, $"Expected {nameof(_activeAsyncOperation)} to be 1, got {oldValue}");
        }
Пример #2
0
        /// <summary>
        /// Rebuild the status cache. This will run the background status to
        /// generate status results, and update the serialized status cache
        /// file.
        /// </summary>
        private bool TryRebuildStatusCache()
        {
            try
            {
                this.context.FileSystem.CreateDirectory(this.context.Enlistment.GitStatusCacheFolder);
            }
            catch (Exception ex) when(ex is IOException || ex is UnauthorizedAccessException)
            {
                EventMetadata metadata = new EventMetadata();

                metadata.Add("Area", EtwArea);
                metadata.Add("Exception", ex.ToString());

                this.context.Tracer.RelatedWarning(
                    metadata,
                    string.Format("GitStatusCache is unable to create git status cache folder at {0}.", this.context.Enlistment.GitStatusCacheFolder));
                return(false);
            }

            // The status cache is regenerated on mount. This means that even if the write to temp file
            // and rename operation doesn't complete (due to a system crash), and there is a torn write,
            // GVFS is still protected because a new status cache file will be generated on mount.
            string tmpStatusFilePath = Path.Combine(this.context.Enlistment.GitStatusCacheFolder, Path.GetRandomFileName() + "_status.tmp");

            GitProcess.Result statusResult = null;

            // Do not modify this block unless you completely understand the comments and code within
            {
                // We MUST set the state to Rebuilding _immediately before_ we call the `git status` command. That allows us to
                // check afterwards if anything happened during the status command that should invalidate the cache, and we
                // can discard its results if that happens.
                this.cacheState = CacheState.Rebuilding;

                GitProcess git = this.context.Enlistment.CreateGitProcess();
                statusResult = git.SerializeStatus(
                    allowObjectDownloads: true,
                    serializePath: tmpStatusFilePath);
            }

            bool rebuildSucceeded = false;

            if (statusResult.ExitCodeIsSuccess)
            {
                lock (this.cacheFileLock)
                {
                    // Only update the cache if our state is still Rebuilding. Otherwise, this indicates that another call
                    // to Invalidate came in, and moved the state back to Dirty.
                    if (this.cacheState == CacheState.Rebuilding)
                    {
                        rebuildSucceeded = this.MoveCacheFileToFinalLocation(tmpStatusFilePath);
                        if (rebuildSucceeded)
                        {
                            // We have to check the state once again, because it could have been invalidated while we were
                            // copying the file in the previous step. Here we do it as a CompareExchange to minimize any further races.
                            if (Interlocked.CompareExchange(ref this.cacheState, CacheState.Clean, CacheState.Rebuilding) != CacheState.Rebuilding)
                            {
                                // We did not succeed in setting the state to Clean. Note that we have already overwritten the on disk cache,
                                // but all users of the cache file first check the cacheState, and since the cacheState is not Clean, no one
                                // should ever read it.

                                rebuildSucceeded = false;
                            }
                        }

                        if (!rebuildSucceeded)
                        {
                            this.cacheState = CacheState.Dirty;
                        }
                    }
                }

                if (!rebuildSucceeded)
                {
                    try
                    {
                        this.context.FileSystem.DeleteFile(tmpStatusFilePath);
                    }
                    catch (Exception ex) when(ex is IOException || ex is UnauthorizedAccessException)
                    {
                        EventMetadata metadata = new EventMetadata();

                        metadata.Add("Area", EtwArea);
                        metadata.Add("Exception", ex.ToString());

                        this.context.Tracer.RelatedError(
                            metadata,
                            string.Format("GitStatusCache is unable to delete temporary status cache file at {0}.", tmpStatusFilePath));
                    }
                }
            }
            else
            {
                this.statistics.RecordBackgroundStatusScanError();
                this.context.Tracer.RelatedInfo("GitStatusCache.TryRebuildStatusCache: Error generating status: {0}", statusResult.Errors);
            }

            return(rebuildSucceeded);
        }
        /// <summary>Allocate a new PerCoreLockedStacks and try to store it into the <see cref="_buckets"/> array.</summary>
        private PerCoreLockedStacks CreatePerCoreLockedStacks(int bucketIndex)
        {
            var inst = new PerCoreLockedStacks();

            return(Interlocked.CompareExchange(ref _buckets[bucketIndex], inst, null) ?? inst);
        }
Пример #4
0
        private bool PutSlotCopy(TKeyStore key, object value, int fullHash)
        {
            Debug.Assert(key != null);
            Debug.Assert(value != TOMBSTONE);
            Debug.Assert(value != null);
            Debug.Assert(!(value is Prime));

            var curTable = this;

TRY_WITH_NEW_TABLE:

            var curEntries = curTable._entries;
            int lenMask = curEntries.Length - 1;
            int idx     = ReduceHashToIndex(fullHash, lenMask);

            // Spin till we get a slot for the key or force a resizing.
            int reprobeCnt = 0;

            while (true)
            {
                var entryHash = curEntries[idx].hash;
                if (entryHash == 0)
                {
                    // Slot is completely clean, claim the hash
                    Debug.Assert(fullHash != 0);
                    entryHash = Interlocked.CompareExchange(ref curEntries[idx].hash, fullHash, 0);
                    if (entryHash == 0)
                    {
                        entryHash = fullHash;
                        if (entryHash == ZEROHASH)
                        {
                            // "added" entry for zero key
                            curTable.allocatedSlotCount.Increment();
                            break;
                        }
                    }
                }

                if (entryHash == fullHash)
                {
                    // hash is good, one way or another, claim the key
                    if (curTable.TryClaimSlotForCopy(ref curEntries[idx].key, key))
                    {
                        break;
                    }
                }

                // this slot contains a different key

                // here we know that this slot does not map to our key
                // and must reprobe or resize
                // hitting reprobe limit or finding TOMBPRIMEHASH here means that
                // we will not find an appropriate slot in this table
                // but there could be more in the new one
                if (++reprobeCnt >= ReprobeLimit(lenMask) |
                    entryHash == TOMBPRIMEHASH)
                {
                    var resized = curTable.Resize();
                    curTable = resized;
                    goto TRY_WITH_NEW_TABLE;
                }

                // quadratic reprobing
                idx = (idx + reprobeCnt) & lenMask; // Reprobe!
            } // End of spinning till we get a Key slot

            // Found the proper Key slot, now update the Value.
            var entryValue = curEntries[idx].value;

            // See if we want to move to a new table (to avoid high average re-probe counts).
            // We only check on the initial set of a Value from null to
            // not-null (i.e., once per key-insert).
            var newTable = curTable._newTable;

            // newTable == entryValue only when both are nulls
            if ((object)newTable == (object)entryValue &&
                curTable.TableIsCrowded(lenMask))
            {
                // Force the new table copy to start
                newTable = curTable.Resize();
                Debug.Assert(curTable._newTable != null && curTable._newTable == newTable);
            }

            // See if we are moving to a new table.
            // If so, copy our slot and retry in the new table.
            if (newTable != null)
            {
                var newTable1 = curTable.CopySlotAndGetNewTable(idx, shouldHelp: false);
                Debug.Assert(newTable == newTable1);
                curTable = newTable;
                goto TRY_WITH_NEW_TABLE;
            }

            // We are finally prepared to update the existing table
            // if entry value is null and our CAS succeeds - we did the update!
            // otherwise someone else copied the value
            // table-copy does not (effectively) increase the number of live k/v pairs
            // so no need to update size
            return(curEntries[idx].value == null &&
                   Interlocked.CompareExchange(ref curEntries[idx].value, value, null) == null);
        }
            internal static void Add(ref StatisticsState state, TimeSpan time, long value)
            {
                StatisticsState State;
                var             Wait = new SpinWait();

                for (; ;)
                {
                    State = Volatile.Read(ref state);

                    var Interval = State._Interval;

                    if (Interval == TimeSpan.Zero)
                    {
                        Interlocked.Add(ref State._Current, value);

                        return;
                    }

                    var Finish = State._Time + Interval;

                    if (time < Finish)
                    {
                        // Still within the time interval
                        if (Interlocked.Add(ref State._Current, value) >= value)
                        {
                            return;
                        }

                        // If the result is less than our input value, this state has been expired (added to -1)
                        // Restore the expired state. Since our previous addition opens a window where another thread can successfully add,
                        // we take the old current value and use it for our own addition
                        value = Interlocked.Exchange(ref State._Current, -1) + 1;

                        // Wait a moment for the other thread to finish replacing the state
                        Wait.SpinOnce();
                    }
                    else if (time < Finish + Interval)
                    {
                        // We're within the next time interval, flag the state as expired so we can lock in that interval
                        var Previous = Interlocked.Exchange(ref State._Current, -1);

                        if (Previous != -1)
                        {
                            var NewState = new StatisticsState(Interval, time, value, Previous);

                            // Replace the current state with a new state
                            if (Interlocked.CompareExchange(ref state, NewState, State) == State)
                            {
                                return;
                            }
                        }
                        else
                        {
                            // Wait a moment for the other thread to finish replacing the state
                            Wait.SpinOnce();
                        }

                        // Another thread is performing a replacement, wait and try again
                    }
                    else
                    {
                        // Two intervals have passed since this state began recording, so we replace with a zero previous record
                        var NewState = new StatisticsState(Interval, time, value);

                        // Replace the current state with a new state
                        if (Interlocked.CompareExchange(ref state, NewState, State) == State)
                        {
                            return;
                        }

                        // Another thread is performing a replacement, wait and try again
                    }
                }
            }
Пример #6
0
        private static bool CopySlot(ref Entry oldEntry, DictionaryImpl <TKey, TKeyStore, TValue> newTable)
        {
            Debug.Assert(newTable != null);

            // Blindly set the hash from 0 to TOMBPRIMEHASH, to eagerly stop
            // fresh put's from claiming new slots in the old table when the old
            // table is mid-resize.
            var hash = oldEntry.hash;

            if (hash == 0)
            {
                hash = Interlocked.CompareExchange(ref oldEntry.hash, TOMBPRIMEHASH, 0);
                if (hash == 0)
                {
                    // slot was not claimed, copy is done here
                    return(true);
                }
            }

            if (hash == TOMBPRIMEHASH)
            {
                // slot was trivially copied, but not by us
                return(false);
            }

            // Prevent new values from appearing in the old table.
            // Box what we see in the old table, to prevent further updates.
            // NOTE: Read of the value below must happen before reading of the key,
            // however this read does not need to be volatile since we will have
            // some fences in between reads.
            object oldval = oldEntry.value;

            // already boxed?
            Prime box = oldval as Prime;

            if (box != null)
            {
                // volatile read here since we need to make sure
                // that the key read below happens after we have read oldval above
                Volatile.Read(ref box.originalValue);
            }
            else
            {
                do
                {
                    box = EntryValueNullOrDead(oldval) ?
                          TOMBPRIME :
                          new Prime(oldval);

                    // CAS down a box'd version of oldval
                    // also works as a complete fence between reading the value and the key
                    object prev = Interlocked.CompareExchange(ref oldEntry.value, box, oldval);

                    if (prev == oldval)
                    {
                        // If we made the Value slot hold a TOMBPRIME, then we both
                        // prevented further updates here but also the (absent)
                        // oldval is vacuously available in the new table.  We
                        // return with true here: any thread looking for a value for
                        // this key can correctly go straight to the new table and
                        // skip looking in the old table.
                        if (box == TOMBPRIME)
                        {
                            return(true);
                        }

                        // Break loop; oldval is now boxed by us
                        // it still needs to be copied into the new table.
                        break;
                    }

                    oldval = prev;
                    box    = oldval as Prime;
                }while (box == null);
            }

            if (box == TOMBPRIME)
            {
                // Copy already complete here, but not by us.
                return(false);
            }

            // Copy the value into the new table, but only if we overwrite a null.
            // If another value is already in the new table, then somebody else
            // wrote something there and that write is happens-after any value that
            // appears in the old table.  If putIfMatch does not find a null in the
            // new table - somebody else should have recorded the null-not_null
            // transition in this copy.
            object originalValue = box.originalValue;

            Debug.Assert(originalValue != TOMBSTONE);

            // since we have a real value, there must be a nontrivial key in the table
            // regular read is ok because value is always CASed down after the key
            // and we ensured that we read the key after the value with fences above
            var  key           = oldEntry.key;
            bool copiedIntoNew = newTable.PutSlotCopy(key, originalValue, hash);

            // Finally, now that any old value is exposed in the new table, we can
            // forever hide the old-table value by gently inserting TOMBPRIME value.
            // This will stop other threads from uselessly attempting to copy this slot
            // (i.e., it's a speed optimization not a correctness issue).
            // Check if we are not too late though, to not pay for MESI RFO and
            // GC fence needlessly.
            if (oldEntry.value != TOMBPRIME)
            {
                oldEntry.value = TOMBPRIME;
            }

            // if we failed to copy, it means something has already appeared in
            // the new table and old value should have been copied before that (not by us).
            return(copiedIntoNew);
        }
Пример #7
0
        // 1) finds or creates a slot for the key
        // 2) sets the slot value to the putval if original value meets expVal condition
        // 3) returns true if the value was actually changed
        // Note that pre-existence of the slot is irrelevant
        // since slot without a value is as good as no slot at all
        internal sealed override bool PutIfMatch(TKey key, object newVal, ref object oldVal, ValueMatch match)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            var curTable = this;
            int fullHash = curTable.hash(key);

TRY_WITH_NEW_TABLE:

            Debug.Assert(newVal != null);
            Debug.Assert(!(newVal is Prime));

            var curEntries = curTable._entries;
            int lenMask    = curEntries.Length - 1;
            int idx        = ReduceHashToIndex(fullHash, lenMask);

            // Spin till we get a slot for the key or force a resizing.
            int reprobeCnt = 0;

            while (true)
            {
                // hash, key and value are all CAS-ed down and follow a specific sequence of states.
                // hence the order of their reads is irrelevant and they do not need to be volatile
                var entryHash = curEntries[idx].hash;
                if (entryHash == 0)
                {
                    // Found an unassigned slot - which means this
                    // key has never been in this table.
                    if (newVal == TOMBSTONE)
                    {
                        Debug.Assert(match == ValueMatch.NotNullOrDead || match == ValueMatch.OldValue);
                        oldVal = null;
                        goto FAILED;
                    }
                    else
                    {
                        // Slot is completely clean, claim the hash first
                        Debug.Assert(fullHash != 0);
                        entryHash = Interlocked.CompareExchange(ref curEntries[idx].hash, fullHash, 0);
                        if (entryHash == 0)
                        {
                            entryHash = fullHash;
                            if (entryHash == ZEROHASH)
                            {
                                // "added" entry for zero key
                                curTable.allocatedSlotCount.Increment();
                                break;
                            }
                        }
                    }
                }

                if (entryHash == fullHash)
                {
                    // hash is good, one way or another,
                    // try claiming the slot for the key
                    if (curTable.TryClaimSlotForPut(ref curEntries[idx].key, key))
                    {
                        break;
                    }
                }

                // here we know that this slot does not map to our key
                // and must reprobe or resize
                // hitting reprobe limit or finding TOMBPRIMEHASH here means that the key is not in this table,
                // but there could be more in the new table
                if (++reprobeCnt >= ReprobeLimit(lenMask) |
                    entryHash == TOMBPRIMEHASH)
                {
                    // start resize or get new table if resize is already in progress
                    var newTable1 = curTable.Resize();
                    // help along an existing copy
                    curTable.HelpCopy();
                    curTable = newTable1;
                    goto TRY_WITH_NEW_TABLE;
                }

                curTable.ReprobeResizeCheck(reprobeCnt, lenMask);

                // quadratic reprobing
                idx = (idx + reprobeCnt) & lenMask;
            }

            // Found the proper Key slot, now update the Value.
            // We never put a null, so Value slots monotonically move from null to
            // not-null (deleted Values use Tombstone).

            // volatile read to make sure we read the element before we read the _newTable
            // that would guarantee that as long as _newTable == null, entryValue cannot be a Prime.
            var entryValue = Volatile.Read(ref curEntries[idx].value);

            // See if we want to move to a new table (to avoid high average re-probe counts).
            // We only check on the initial set of a Value from null to
            // not-null (i.e., once per key-insert).
            var newTable = curTable._newTable;

            // newTable == entryValue only when both are nulls
            if ((object)newTable == (object)entryValue &&
                curTable.TableIsCrowded(lenMask))
            {
                // Force the new table copy to start
                newTable = curTable.Resize();
                Debug.Assert(curTable._newTable != null && newTable == curTable._newTable);
            }

            // See if we are moving to a new table.
            // If so, copy our slot and retry in the new table.
            if (newTable != null)
            {
                var newTable1 = curTable.CopySlotAndGetNewTable(idx, shouldHelp: true);
                Debug.Assert(newTable == newTable1);
                curTable = newTable;
                goto TRY_WITH_NEW_TABLE;
            }

            // We are finally prepared to update the existing table
            while (true)
            {
                Debug.Assert(!(entryValue is Prime));
                var entryValueNullOrDead = EntryValueNullOrDead(entryValue);

                switch (match)
                {
                case ValueMatch.Any:
                    if (newVal == entryValue)
                    {
                        // Do not update!
                        goto FAILED;
                    }
                    break;

                case ValueMatch.NullOrDead:
                    if (entryValueNullOrDead)
                    {
                        break;
                    }

                    oldVal = entryValue;
                    goto FAILED;

                case ValueMatch.NotNullOrDead:
                    if (entryValueNullOrDead)
                    {
                        goto FAILED;
                    }
                    break;

                case ValueMatch.OldValue:
                    Debug.Assert(oldVal != null);
                    if (!oldVal.Equals(entryValue))
                    {
                        oldVal = entryValue;
                        goto FAILED;
                    }
                    break;
                }

                // Actually change the Value
                var prev = Interlocked.CompareExchange(ref curEntries[idx].value, newVal, entryValue);
                if (prev == entryValue)
                {
                    // CAS succeeded - we did the update!
                    // Adjust sizes
                    if (entryValueNullOrDead)
                    {
                        oldVal = null;
                        if (newVal != TOMBSTONE)
                        {
                            curTable._size.Increment();
                        }
                    }
                    else
                    {
                        oldVal = prev;
                        if (newVal == TOMBSTONE)
                        {
                            curTable._size.Decrement();
                        }
                    }

                    return(true);
                }
                // Else CAS failed

                // If a Prime'd value got installed, we need to re-run the put on the new table.
                if (prev is Prime)
                {
                    curTable = curTable.CopySlotAndGetNewTable(idx, shouldHelp: true);
                    goto TRY_WITH_NEW_TABLE;
                }

                // Otherwise we lost the CAS to another racing put.
                // Simply retry from the start.
                entryValue = prev;
            }

FAILED:
            return(false);
        }
Пример #8
0
 internal void EnsureSetItem(ComMethodDesc candidate)
 {
     Interlocked.CompareExchange(ref _setItem, candidate, null);
 }
Пример #9
0
        /// <summary>
        /// 初始化
        /// </summary>
        internal void Start()
        {
            int isDisposed = 1;

            SubBuffer.PoolBufferFull buffer = default(SubBuffer.PoolBufferFull);
            try
            {
                if (checkStateFile())
                {
                    byte[] stateData = new byte[stateBufferSize];
                    stateFileStream = new FileStream(stateFileName, FileMode.Open, FileAccess.ReadWrite, FileShare.Read, stateBufferSize, FileOptions.None);
                    stateFileStream.Seek(-stateBufferSize, SeekOrigin.End);
                    stateFileStream.Read(stateData, 0, stateBufferSize);
                    fixed(byte *stateDataFixed = stateData)
                    {
                        identity       = *(ulong *)stateDataFixed;
                        dataFileLength = *(long *)(stateDataFixed + sizeof(ulong));
                    }
                    if (((uint)identity & (DataCountPerFile - 1)) == 0)
                    {
                        dataFileLength = 0;
                    }
                    if (dataFileLength == 0)
                    {
                        FileInfo dataFileInfo = new FileInfo(dataFileName);
                        if (dataFileInfo.Exists)
                        {
                            if (dataFileInfo.Length == 0)
                            {
                                dataFileInfo.Delete();
                            }
                            else
                            {
                                AutoCSer.IO.File.MoveBak(dataFileInfo.FullName);
                            }
                        }
                        dataFileStream = new FileStream(dataFileInfo.FullName, FileMode.CreateNew, FileAccess.Write, FileShare.Read, bufferPool.Size, FileOptions.None);
                    }
                    else
                    {
                        FileInfo dataFileInfo = new FileInfo(dataFileName);
                        if (!dataFileInfo.Exists)
                        {
                            Node.Cache.TcpServer.Log.Add(Log.LogType.Error, "没有找到消息队列数据文件 " + dataFileInfo.FullName);
                            return;
                        }
                        if (dataFileInfo.Length < dataFileLength)
                        {
                            Node.Cache.TcpServer.Log.Add(Log.LogType.Error, "消息队列数据文件 " + dataFileInfo.FullName + " 大小错误 " + dataFileInfo.Length.toString() + " < " + dataFileLength.toString());
                            return;
                        }
                        dataFileStream = new FileStream(dataFileInfo.FullName, FileMode.Open, FileAccess.Write, FileShare.Read, bufferPool.Size, FileOptions.None);
                        if (dataFileStream.Length > dataFileLength)
                        {
                            dataFileStream.SetLength(dataFileLength);
                            dataFileStream.Flush(true);
                        }
                        dataFileStream.Seek(0, SeekOrigin.End);

                        FileInfo indexFileInfo = new FileInfo(getIndexFileName(identity));
                        bufferPool.Get(ref buffer);
                        fixed(byte *bufferFixed = buffer.Buffer)
                        {
                            byte *bufferStart = bufferFixed + buffer.StartIndex, end = bufferStart + buffer.Length;
                            ulong baseIdentity = this.baseIdentity;

                            if (indexFileInfo.Exists && indexFileInfo.Length >= sizeof(int) * 2)
                            {
                                #region 初始化数据文件数据包索引信息
                                int  count = (int)(indexFileInfo.Length >> 3), index = 0;
                                long fileIndex = 0;
                                indexs = new LeftArray <PacketIndex>(count);
                                PacketIndex[] indexArray = indexs.Array;
                                using (FileStream indexFileStream = new FileStream(indexFileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferPool.Size, FileOptions.None))
                                {
                                    do
                                    {
                                        indexFileStream.Read(buffer.Buffer, buffer.StartIndex, buffer.Length);
                                        byte *read = bufferStart;
                                        do
                                        {
                                            indexArray[index].Set(baseIdentity + *(uint *)read, fileIndex += *(int *)(read + sizeof(int)));
                                            if (++index == count)
                                            {
                                                break;
                                            }
                                        }while ((read += sizeof(int) * 2) != end);
                                    }while (index != count);
                                }
                                while (index != 0)
                                {
                                    if ((fileIndex = indexArray[--index].FileIndex) == dataFileLength)
                                    {
                                        if (indexArray[index].Identity == identity)
                                        {
                                            indexs.Length = index + 1;
                                        }
                                        break;
                                    }
                                    if (fileIndex < dataFileLength)
                                    {
                                        break;
                                    }
                                }
                                #endregion
                            }
                            if (indexs.Length == 0)
                            {
                                #region 重建数据文件数据包索引信息
                                if (indexs.Array == null)
                                {
                                    indexs = new LeftArray <PacketIndex>(1 << 10);
                                }
                                indexs.Array[0].Set(baseIdentity);
                                indexs.Length = 1;
                                int  bufferIndex = 0, readBufferSize = Math.Min(buffer.Length, createIndexBufferSize), bufferEndIndex, dataSize;
                                long nextFileSize = dataFileLength, fileIndex = 0;
                                using (FileStream fileStream = new FileStream(dataFileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, readBufferSize, FileOptions.None))
                                {
                                    readBufferSize -= sizeof(int);
                                    do
                                    {
                                        bufferEndIndex  = fileStream.Read(buffer.Buffer, buffer.StartIndex + bufferIndex, readBufferSize - bufferIndex);
                                        nextFileSize   -= bufferEndIndex;
                                        bufferEndIndex += bufferIndex - sizeof(int) * 3;
                                        bufferIndex     = 0;
                                        do
                                        {
                                            byte *read = bufferStart + bufferIndex;
                                            dataSize = *(int *)read;
                                            if (dataSize < 0)
                                            {
                                                baseIdentity += *(uint *)(read + sizeof(int) * 2);
                                                bufferIndex  += -dataSize + PacketHeaderSize + sizeof(int);
                                            }
                                            else
                                            {
                                                baseIdentity += *(uint *)(read + sizeof(int));
                                                bufferIndex  += dataSize + PacketHeaderSize;
                                            }
                                            indexs.PrepLength(1);
                                            indexs.Array[indexs.Length].Set(baseIdentity, fileIndex + bufferIndex);
                                            ++indexs.Length;
                                        }while (bufferIndex <= bufferEndIndex);
                                        fileIndex += bufferIndex;
                                        switch (dataSize = bufferIndex - bufferEndIndex)
                                        {
                                        case 1:
                                        case 2:
                                        case 3:
                                            *(ulong *)bufferStart = *(ulong *)(bufferStart + bufferIndex);
                                            *(uint *)(bufferStart + sizeof(ulong)) = *(uint *)(bufferStart + (bufferIndex + sizeof(ulong)));
                                            bufferIndex = sizeof(int) * 3 - dataSize;
                                            break;

                                        case 4:
                                        case 5:
                                        case 6:
                                        case 7:
                                            *(ulong *)bufferStart = *(ulong *)(bufferStart + bufferIndex);
                                            bufferIndex           = sizeof(int) * 3 - dataSize;
                                            break;

                                        case 8:
                                        case 9:
                                        case 10:
                                        case 11:
                                            *(uint *)bufferStart = *(uint *)(bufferStart + bufferIndex);
                                            bufferIndex          = sizeof(int) * 3 - dataSize;
                                            break;

                                        case 12: bufferIndex = 0; break;

                                        default:
                                            fileStream.Seek(dataSize -= sizeof(int) * 3, SeekOrigin.Current);
                                            nextFileSize             -= dataSize;
                                            bufferIndex = 0;
                                            break;
                                        }
                                    }while (nextFileSize > 0);
                                }
                                #endregion
                            }
                        }
                    }
                }
                else
                {
                    stateFileStream = new FileStream(stateFileName, FileMode.CreateNew, FileAccess.Write, FileShare.Read, stateBufferSize, FileOptions.None);
                    FileInfo dataFileInfo = new FileInfo(dataFileName);
                    if (dataFileInfo.Exists)
                    {
                        if (dataFileInfo.Length == 0)
                        {
                            dataFileInfo.Delete();
                        }
                        else
                        {
                            AutoCSer.IO.File.MoveBak(dataFileInfo.FullName);
                        }
                    }
                    dataFileStream = new FileStream(dataFileName, FileMode.CreateNew, FileAccess.Write, FileShare.Read, bufferPool.Size, FileOptions.None);
                }
                if (indexs.Array == null)
                {
                    indexs = new LeftArray <PacketIndex>(1 << 10);
                }
                if (indexs.Length == 0)
                {
                    indexs.Array[0].Set(baseIdentity);
                    indexs.Length = 1;
                }
                writeHandle = write;
                StatePacketIndex.Set(identity, dataFileLength);
                AutoCSer.DomainUnload.Unloader.Add(disposeHandle, DomainUnload.Type.Action);
                isDisposed = 0;
            }
            finally
            {
                buffer.TryFree();
                if (isDisposed == 0)
                {
                    Interlocked.Exchange(ref isWrite, 0);
                    onStart();
                    if (!bufferQueue.IsEmpty && Interlocked.CompareExchange(ref isWrite, 1, 0) == 0)
                    {
                        write();
                    }
                }
                else
                {
                    indexs.Length = 0;
                    Dispose();
                }
            }
        }
Пример #10
0
 /// <summary>
 /// Set the dirty flag to 1 (is Dirty) if the flag was not already set.
 /// This is private so because an external caller should not be able to declare the cache is dirty.
 /// </summary>
 /// <returns><code>true</code> if the cache was not dirty before and <code>false</code> otherwise</returns>
 private bool TestSetDirtyFlag()
 {
     return(Interlocked.CompareExchange(location1: ref _isCacheDirty, value: 1, comparand: 0) == 0);
 }
Пример #11
0
 /// <summary>
 /// Reset the dirty flag to 0 (is Not Dirty) if the flag was already set.
 /// This is public so that external callers can inform the cache that they have consumed the updated cache event.
 /// </summary>
 /// <returns><code>true</code> if the cache was dirty before and <code>false</code> otherwise</returns>
 public bool TestResetDirtyFlag()
 {
     return(Interlocked.CompareExchange(location1: ref _isCacheDirty, value: 0, comparand: 1) == 1);
 }
Пример #12
0
        /// <summary>
        /// Execute the background task
        /// </summary>
        /// <param name="context"></param>
        public void Run(BackgroundTaskExecuteContext context)
        {
            var logger = HostContainer.GetInstance <ILogger>();

            if (Interlocked.CompareExchange(ref _hasActiveTask, 1, 0) == 0)
            {
                var countUsers = 0;
                try
                {
                    logger.Info(string.Format("[{0}] Start account expires notification task", EzCMSContants.AccountExpiresNotificationTaskName));
                    //Update the background task last running time
                    var backgroundTaskService = HostContainer.GetInstance <IEzBackgroundTaskService>();
                    backgroundTaskService.UpdateLastRunningTimeTask(GetType());

                    var userService          = HostContainer.GetInstance <IUserService>();
                    var emailLogService      = HostContainer.GetInstance <IEmailLogService>();
                    var emailTemplateService = HostContainer.GetInstance <IEmailTemplateService>();

                    var nearExpirationDateUsers = userService.GetUsersNearExpirationDate().ToList();

                    foreach (var user in nearExpirationDateUsers)
                    {
                        if (user.AccountExpiresDate.HasValue)
                        {
                            var authorizeCode = PasswordUtilities.EncryptString(String.Format("{0}{1}{2}", user.Id,
                                                                                              FrameworkConstants.UniqueLinkSeparator, user.Email));
                            var extendExpirationDateLink =
                                UrlUtilities.GenerateUrl(HttpContext.Current.Request.RequestContext, "Account",
                                                         "ExtendAccountExpiresDate",
                                                         new
                            {
                                area          = "Admin",
                                authorizeCode = authorizeCode
                            }, true);

                            var model = new NotifyAccountExpiredEmailModel
                            {
                                FullName                 = user.FullName,
                                Username                 = user.Username,
                                Email                    = user.Email,
                                ExpirationDate           = user.AccountExpiresDate.Value,
                                ExtendExpirationDateLink = extendExpirationDateLink
                            };

                            var emailResponse = emailTemplateService.ParseEmail(EmailEnums.EmailTemplateType.AccountExpiredNotification, model);
                            var emailLog      = new EmailLog
                            {
                                To       = user.Email,
                                ToName   = user.FullName,
                                From     = emailResponse.From,
                                FromName = emailResponse.FromName,
                                CC       = emailResponse.CC,
                                Bcc      = emailResponse.BCC,
                                Subject  = emailResponse.Subject,
                                Body     = emailResponse.Body,
                                Priority = EmailEnums.EmailPriority.Medium
                            };
                            emailLogService.CreateEmail(emailLog, true);
                            countUsers++;
                        }
                    }
                }
                catch (Exception exception)
                {
                    logger.Error(exception);
                }

                logger.Info(string.Format("[{0}] End account expires notification task. Notify to {1} account(s) near expiration date", EzCMSContants.AccountExpiresNotificationTaskName, countUsers));
                Interlocked.Exchange(ref _hasActiveTask, 0);
            }
        }
Пример #13
0
        private object ExchangeInstanceConditionally <TService>(ref object instance, Func <TService> factory)
        {
            Interlocked.CompareExchange(ref instance, factory(), null);

            return(instance);
        }
Пример #14
0
        // Called by Perform, by Sync, by above.

        public static bool SendEDSMEvents(Action <string> log, IEnumerable <HistoryEntry> helist, bool manual = false)
        {
            System.Diagnostics.Debug.WriteLine("Send " + helist.Count());

            int      eventCount = 0;
            bool     hasbeta    = false;
            DateTime betatime   = DateTime.MinValue;

            lock (alwaysDiscard)                    // use this as a perm proxy to lock discardEvents
            {
                foreach (HistoryEntry he in helist) // push list of events to historylist queue..
                {
                    if (!he.EdsmSync)               // if we have not sent it..
                    {
                        string eventtype = he.EntryType.ToString();

                        if (he.Commander.Name.StartsWith("[BETA]", StringComparison.InvariantCultureIgnoreCase) || he.IsBetaMessage)
                        {
                            hasbeta  = true;
                            betatime = he.EventTimeUTC;
                            he.journalEntry.SetEdsmSync();       // crappy slow but unusual, but lets mark them as sent..
                        }
                        else if (!(he.MultiPlayer || discardEvents.Contains(eventtype) || alwaysDiscard.Contains(eventtype)))
                        {
                            historylist.Enqueue(new HistoryQueueEntry {
                                HistoryEntry = he, Logger = log, ManualSync = manual
                            });
                            eventCount++;
                        }
                    }
                }
            }

            if (hasbeta && eventCount == 0)
            {
                log?.Invoke($"Cannot send Beta logs to EDSM - most recent timestamp: {betatime.ToString("yyyy-MM-dd'T'HH:mm:ss'Z'")}");
            }

            if (manual)     // if in manual mode, we want to tell the user the end, so push an end marker
            {
                string logline = (eventCount > 0) ? $"Sending {eventCount} journal event(s) to EDSM" : "No new events to send to EDSM";
                log?.Invoke(logline);

                if (eventCount > 0)      // push end of sync event.
                {
                    historylist.Enqueue(new HistoryQueueEntry {
                        HistoryEntry = null, Logger = log, ManualSync = manual
                    });
                }
            }

            if (eventCount > 0)
            {
                historyevent.Set();

                // Start the sync thread if it's not already running
                if (Interlocked.CompareExchange(ref running, 1, 0) == 0)
                {
                    Exit = false;
                    exitevent.Reset();
                    ThreadEDSMSync              = new System.Threading.Thread(new System.Threading.ThreadStart(SyncThread));
                    ThreadEDSMSync.Name         = "EDSM Journal Sync";
                    ThreadEDSMSync.IsBackground = true;
                    ThreadEDSMSync.Start();
                }
            }

            return(true);
        }
Пример #15
0
 /// <summary>
 /// Sets the timer as triggered
 /// </summary>
 void Set()
 {
     Interlocked.CompareExchange(ref _triggered, 1, 0);
 }
Пример #16
0
        /// <summary>
        /// 写入数据
        /// </summary>
        private unsafe void write()
        {
            FileBuffers buffer = default(FileBuffers);
            int         bigBufferSize;
            bool        isCopyBuffer, isNeedDispose = false;

            try
            {
                bufferPool.Get(ref buffer.Buffer);
                DateTime callbackTime = Date.NowTime.Now;
                fixed(byte *bufferFixed = buffer.Buffer.Buffer)
                {
                    byte *bufferStart = bufferFixed + buffer.Buffer.StartIndex;

GETQUEUE:
                    //Thread.Sleep(0);
                    Buffer head = bufferQueue.GetClear();

                    if (head != null)
                    {
                        int    index = PacketHeaderSize, dataCount = 0;
                        Buffer data = head;
                        do
                        {
                            data.Identity = identity;
                            int dataSize = data.Data.GetSerializeBufferSize(out isCopyBuffer);
CHECKSIZE:
                            if (dataSize + index <= buffer.Buffer.Length)
                            {
                                data.Data.SerializeBuffer(bufferStart + index);
                                if (isCopyBuffer)
                                {
                                    data.Data.SerializeBuffer(ref buffer.Buffer, index);
                                }
                                index += dataSize;
                                ++dataCount;
                                ++identity;
                            }
                            else if (dataCount != 0)
                            {
                                *(int *)bufferStart = index - PacketHeaderSize;
                                *(int *)(bufferStart + sizeof(int)) = dataCount;
                                write(ref buffer, bufferStart);
                                index     = PacketHeaderSize;
                                dataCount = 0;
                                goto CHECKSIZE;
                            }
                            else
                            {
                                #region 写入大数据
                                ++identity;
                                if (bigBuffer.Length < (bigBufferSize = dataSize + PacketHeaderSize))
                                {
                                    bigBuffer = new byte[Math.Max(bigBufferSize, bigBuffer.Length << 1)];
                                    fixed(byte *bigBufferFixed = bigBuffer)
                                    {
                                        *(int *)bigBufferFixed = dataSize;
                                        *(int *)(bigBufferFixed + sizeof(int)) = 1;
                                        data.Data.SerializeBuffer(bigBufferFixed + PacketHeaderSize, bigBuffer);
                                        if (dataSize >= Config.MinCompressSize)
                                        {
                                            if (AutoCSer.IO.Compression.DeflateCompressor.Get(bigBuffer, PacketHeaderSize, dataSize, ref buffer.CompressionBuffer, ref buffer.CompressionData, PacketHeaderSize + sizeof(int), PacketHeaderSize + sizeof(int)))
                                            {
                                                writeCompression(ref buffer.CompressionData, bigBufferFixed);
                                                buffer.CompressionBuffer.TryFree();
                                                goto CHECKIDENTITY;
                                            }
                                            buffer.CompressionBuffer.TryFree();
                                        }
                                    }
                                    dataFileStream.Write(bigBuffer, 0, bigBufferSize);
                                    dataFileLength += bigBufferSize;
                                    setIndex();
                                    #endregion
                            }
CHECKIDENTITY:
                            if (((uint)identity & (DataCountPerFile - 1)) == 0)
                            {
                                #region 切换数据文件
                                if (dataCount != 0)
                                {
                                    *(int *)bufferStart = index - PacketHeaderSize;
                                    *(int *)(bufferStart + sizeof(int)) = dataCount;
                                    write(ref buffer, bufferStart);
                                    index     = PacketHeaderSize;
                                    dataCount = 0;
                                }
                                dataFileStream.Flush(true);
                                dataFileStream.Dispose();
                                dataFileStream = null;
                                writeState(ref buffer.Buffer);
                                writeIndex(ref buffer.Buffer);

                                FileInfo dataFileInfo = new FileInfo(dataFileName);
                                if (dataFileInfo.Exists)
                                {
                                    if (dataFileInfo.Length == 0)
                                    {
                                        dataFileInfo.Delete();
                                    }
                                    else
                                    {
                                        AutoCSer.IO.File.MoveBak(dataFileInfo.FullName);
                                    }
                                }
                                dataFileStream = new FileStream(dataFileInfo.FullName, FileMode.CreateNew, FileAccess.Write, FileShare.Read, bufferPool.Size, FileOptions.None);
                                dataFileLength = 0;
                                #endregion
                            }
                            else if (dataCount == MaxPacketCount)
                            {
                                *(int *)bufferStart = index - PacketHeaderSize;
                                *(int *)(bufferStart + sizeof(int)) = MaxPacketCount;
                                write(ref buffer, bufferStart);
                                index     = PacketHeaderSize;
                                dataCount = 0;
                            }

                            if (data.LinkNext == null)
                            {
                                if (bufferQueue.IsEmpty || callbackTime != Date.NowTime.Now)
                                    break; }
                                data.LinkNext = bufferQueue.GetClear();
                            }
                            data = data.LinkNext;
                        }while (true);

                        if (dataCount != 0)
                        {
                            *(int *)bufferStart = index - PacketHeaderSize;
                            *(int *)(bufferStart + sizeof(int)) = dataCount;
                            write(ref buffer, bufferStart);
                        }
                        dataFileStream.Flush(true);
                        writeState(ref buffer.Buffer);
                        if (ReadCount == 0)
                        {
                            do
                            {
                                head = head.Callback();
                            }while (head != null);
                        }
                        else
                        {
                            QueueTaskThread.Thread.Default.Add(new QueueTaskThread.Append(head));
                        }
                        callbackTime = Date.NowTime.Now;
                    }
                    if (this.isNeedDispose != 0)
                    {
                        isNeedDispose = true;
                        return;
                    }
                    if (!bufferQueue.IsEmpty)
                    {
                        goto GETQUEUE;
                    }
                    Interlocked.Exchange(ref isWrite, 0);
                    if (!bufferQueue.IsEmpty && Interlocked.CompareExchange(ref isWrite, 1, 0) == 0)
                    {
                        goto GETQUEUE;
                    }
                }
            }
            catch (Exception error)
            {
                isNeedDispose = true;
                AutoCSer.Log.Pub.Log.Add(Log.LogType.Fatal, error);
            }
            finally
            {
                buffer.Free();
                if (isNeedDispose)
                {
                    Dispose();
                }
            }
        }
Пример #17
0
 bool IWeakReferenceable.SetWeakRef(WeakRefTracker value) {
     return Interlocked.CompareExchange<WeakRefTracker>(ref _tracker, value, null) == null;
 }
Пример #18
0
        public void AccessRandomKeys()
        {
            using (var conn = Create(allowAdmin: true))
            {
                var cluster        = conn.GetDatabase();
                int slotMovedCount = 0;
                conn.HashSlotMoved += (s, a) =>
                {
                    Output.WriteLine("{0} moved from {1} to {2}", a.HashSlot, Describe(a.OldEndPoint), Describe(a.NewEndPoint));
                    Interlocked.Increment(ref slotMovedCount);
                };
                var       pairs = new Dictionary <string, string>();
                const int COUNT = 500;
                Task[]    send  = new Task[COUNT];
                int       index = 0;

                var servers = conn.GetEndPoints().Select(x => conn.GetServer(x));
                foreach (var server in servers)
                {
                    if (!server.IsSlave)
                    {
                        server.Ping();
                        server.FlushAllDatabases();
                    }
                }

                for (int i = 0; i < COUNT; i++)
                {
                    var key   = Guid.NewGuid().ToString();
                    var value = Guid.NewGuid().ToString();
                    pairs.Add(key, value);
                    send[index++] = cluster.StringSetAsync(key, value);
                }
                conn.WaitAll(send);

                var expected = new string[COUNT];
                var actual   = new Task <RedisValue> [COUNT];
                index = 0;
                foreach (var pair in pairs)
                {
                    expected[index] = pair.Value;
                    actual[index]   = cluster.StringGetAsync(pair.Key);
                    index++;
                }
                cluster.WaitAll(actual);
                for (int i = 0; i < COUNT; i++)
                {
                    Assert.Equal(expected[i], (string)actual[i].Result);
                }

                int total = 0;
                Parallel.ForEach(servers, server =>
                {
                    if (!server.IsSlave)
                    {
                        int count = server.Keys(pageSize: 100).Count();
                        Output.WriteLine("{0} has {1} keys", server.EndPoint, count);
                        Interlocked.Add(ref total, count);
                    }
                });

                foreach (var server in servers)
                {
                    var counters = server.GetCounters();
                    Output.WriteLine(counters.ToString());
                }
                int final = Interlocked.CompareExchange(ref total, 0, 0);
                Assert.Equal(COUNT, final);
                Assert.Equal(0, Interlocked.CompareExchange(ref slotMovedCount, 0, 0));
            }
        }
Пример #19
0
        // Resizing after too many probes.  "How Big???" heuristics are here.
        // Callers will (not this routine) help any in-progress copy.
        // Since this routine has a fast cutout for copy-already-started, callers
        // MUST 'help_copy' lest we have a path which forever runs through
        // 'resize' only to discover a copy-in-progress which never progresses.
        private DictionaryImpl <TKey, TKeyStore, TValue> ResizeImpl()
        {
            // No copy in-progress, so start one.
            //First up: compute new table size.
            int oldlen = _entries.Length;

            const int MAX_SIZE       = 1 << 30;
            const int MAX_CHURN_SIZE = 1 << 15;

            // First size estimate is roughly inverse of ProbeLimit
            int sz    = Size + (MIN_SIZE >> REPROBE_LIMIT_SHIFT);
            int newsz = sz < (MAX_SIZE >> REPROBE_LIMIT_SHIFT) ?
                        sz << REPROBE_LIMIT_SHIFT :
                        sz;

            // if new table would shrink or hold steady,
            // we must be resizing because of churn.
            // target churn based resize rate to be about 1 per RESIZE_TICKS_TARGET
            if (newsz <= oldlen)
            {
                var resizeSpan = CurrentTickMillis() - _topDict._lastResizeTickMillis;

                // note that CurrentTicks() will wrap around every 50 days.
                // For our purposes that is tolerable since it just
                // adds a possibility that in some rare cases a churning resize will not be
                // considered a churning one.
                if (resizeSpan < RESIZE_MILLIS_TARGET)
                {
                    // last resize too recent, expand
                    newsz = oldlen < MAX_CHURN_SIZE ? oldlen << 1 : oldlen;
                }
                else
                {
                    // do not allow shrink too fast
                    newsz = Math.Max(newsz, (int)((long)oldlen * RESIZE_MILLIS_TARGET / resizeSpan));
                }
            }

            // Align up to a power of 2
            newsz = AlignToPowerOfTwo(newsz);

            // Size calculation: 2 words (K+V) per table entry, plus a handful.  We
            // guess at 32-bit pointers; 64-bit pointers screws up the size calc by
            // 2x but does not screw up the heuristic very much.
            //
            // TODO: VS some tuning may be needed
            int kBs4 = (((newsz << 1) + 4) << 3 /*word to bytes*/) >> 12 /*kBs4*/;

            var newTable = _newTable;

            // Now, if allocation is big enough,
            // limit the number of threads actually allocating memory to a
            // handful - lest we have 750 threads all trying to allocate a giant
            // resized array.
            // conveniently, Increment is also a full fence
            if (kBs4 > 0 && Interlocked.Increment(ref _resizers) >= 2)
            {
                // Already 2 guys trying; wait and see
                // See if resize is already in progress
                if (newTable != null)
                {
                    return(newTable);         // Use the new table already
                }

                SpinWait.SpinUntil(() => _newTable != null, 8 * kBs4);
                newTable = _newTable;
            }

            // Last check, since the 'new' below is expensive and there is a chance
            // that another thread slipped in a new table while we ran the heuristic.
            newTable = _newTable;
            // See if resize is already in progress
            if (newTable != null)
            {
                return(newTable);          // Use the new table already
            }

            newTable = CreateNew(newsz);

            // The new table must be CAS'd in to ensure only 1 winner
            var prev = _newTable ??
                       Interlocked.CompareExchange(ref _newTable, newTable, null);

            if (prev != null)
            {
                return(prev);
            }
            else
            {
                //Console.WriteLine("resized: " + newsz);
                return(newTable);
            }
        }
        internal void DoGet(HttpContext context)
        {
            HttpRequest  request  = context.Request;
            HttpResponse response = context.Response;
            string       key      = this.CreateKey(request);
            CacheEntry   entry    = (CacheEntry)HttpRuntime.CacheInternal.Get(key, CacheGetOptions.ReturnCacheEntry);

            if (entry == null)
            {
                this.ReportNotFound(context);
            }
            else
            {
                string        str     = request.Headers["Http_Exclusive"];
                CachedContent content = (CachedContent)entry.Value;
                content._spinLock.AcquireWriterLock();
                try
                {
                    if (content._content == null)
                    {
                        this.ReportNotFound(context);
                    }
                    else
                    {
                        int comparand = content._extraFlags;
                        if (((comparand & 1) != 0) && (comparand == Interlocked.CompareExchange(ref content._extraFlags, comparand & -2, comparand)))
                        {
                            this.ReportActionFlags(context, 1);
                        }
                        if (str == "release")
                        {
                            int num;
                            if (this.GetRequiredNonNegativeInt32HeaderValue(context, "Http_LockCookie", out num))
                            {
                                if (content._locked)
                                {
                                    if (num == content._lockCookie)
                                    {
                                        content._locked = false;
                                    }
                                    else
                                    {
                                        this.ReportLocked(context, content);
                                    }
                                }
                                else
                                {
                                    context.Response.StatusCode = 200;
                                }
                            }
                        }
                        else if (content._locked)
                        {
                            this.ReportLocked(context, content);
                        }
                        else
                        {
                            if (str == "acquire")
                            {
                                content._locked      = true;
                                content._utcLockDate = DateTime.UtcNow;
                                content._lockCookie++;
                                response.AppendHeader("LockCookie", content._lockCookie.ToString(CultureInfo.InvariantCulture));
                            }
                            response.AppendHeader("Timeout", ((int)(entry.SlidingExpiration.Ticks / 0x23c34600L)).ToString(CultureInfo.InvariantCulture));
                            Stream outputStream = response.OutputStream;
                            byte[] buffer       = content._content;
                            outputStream.Write(buffer, 0, buffer.Length);
                            response.Flush();
                        }
                    }
                }
                finally
                {
                    content._spinLock.ReleaseWriterLock();
                }
            }
        }
Пример #21
0
        internal sealed override TValue GetOrAdd(TKey key, Func <TKey, TValue> valueFactory)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            if (valueFactory == null)
            {
                throw new ArgumentNullException(nameof(valueFactory));
            }

            object newValObj = null;
            TValue result    = default(TValue);

            var curTable = this;
            int fullHash = curTable.hash(key);

TRY_WITH_NEW_TABLE:

            var curEntries = curTable._entries;
            int lenMask = curEntries.Length - 1;
            int idx     = ReduceHashToIndex(fullHash, lenMask);

            // Spin till we get a slot for the key or force a resizing.
            int reprobeCnt = 0;

            while (true)
            {
                // hash, key and value are all CAS-ed down and follow a specific sequence of states.
                // hence the order of their reads is irrelevant and they do not need to be volatile
                var entryHash = curEntries[idx].hash;
                if (entryHash == 0)
                {
                    // Found an unassigned slot - which means this
                    // key has never been in this table.
                    // Slot is completely clean, claim the hash first
                    Debug.Assert(fullHash != 0);
                    entryHash = Interlocked.CompareExchange(ref curEntries[idx].hash, fullHash, 0);
                    if (entryHash == 0)
                    {
                        entryHash = fullHash;
                        if (entryHash == ZEROHASH)
                        {
                            // "added" entry for zero key
                            curTable.allocatedSlotCount.Increment();
                            break;
                        }
                    }
                }

                if (entryHash == fullHash)
                {
                    // hash is good, one way or another,
                    // try claiming the slot for the key
                    if (curTable.TryClaimSlotForPut(ref curEntries[idx].key, key))
                    {
                        break;
                    }
                }

                // here we know that this slot does not map to our key
                // and must reprobe or resize
                // hitting reprobe limit or finding TOMBPRIMEHASH here means that the key is not in this table,
                // but there could be more in the new table
                if (++reprobeCnt >= ReprobeLimit(lenMask) |
                    entryHash == TOMBPRIMEHASH)
                {
                    // start resize or get new table if resize is already in progress
                    var newTable1 = curTable.Resize();
                    // help along an existing copy
                    curTable.HelpCopy();
                    curTable = newTable1;
                    goto TRY_WITH_NEW_TABLE;
                }

                curTable.ReprobeResizeCheck(reprobeCnt, lenMask);

                // quadratic reprobing
                idx = (idx + reprobeCnt) & lenMask;
            }

            // Found the proper Key slot, now update the Value.
            // We never put a null, so Value slots monotonically move from null to
            // not-null (deleted Values use Tombstone).

            // volatile read to make sure we read the element before we read the _newTable
            // that would guarantee that as long as _newTable == null, entryValue cannot be a Prime.
            var entryValue = Volatile.Read(ref curEntries[idx].value);

            // See if we want to move to a new table (to avoid high average re-probe counts).
            // We only check on the initial set of a Value from null to
            // not-null (i.e., once per key-insert).
            var newTable = curTable._newTable;

            // newTable == entryValue only when both are nulls
            if ((object)newTable == (object)entryValue &&
                curTable.TableIsCrowded(lenMask))
            {
                // Force the new table copy to start
                newTable = curTable.Resize();
                Debug.Assert(curTable._newTable != null && curTable._newTable == newTable);
            }

            // See if we are moving to a new table.
            // If so, copy our slot and retry in the new table.
            if (newTable != null)
            {
                var newTable1 = curTable.CopySlotAndGetNewTable(idx, shouldHelp: true);
                Debug.Assert(newTable == newTable1);
                curTable = newTable;
                goto TRY_WITH_NEW_TABLE;
            }

            if (!EntryValueNullOrDead(entryValue))
            {
                goto GOT_PREV_VALUE;
            }

            // prev value is not null, dead or prime.
            // let's try install new value
            newValObj = newValObj ?? ToObjectValue(result = valueFactory(key));
            while (true)
            {
                Debug.Assert(!(entryValue is Prime));

                // Actually change the Value
                var prev = Interlocked.CompareExchange(ref curEntries[idx].value, newValObj, entryValue);
                if (prev == entryValue)
                {
                    // CAS succeeded - we did the update!
                    // Adjust sizes
                    curTable._size.Increment();
                    goto DONE;
                }
                // Else CAS failed

                // If a Prime'd value got installed, we need to re-run the put on the new table.
                if (prev is Prime)
                {
                    curTable = curTable.CopySlotAndGetNewTable(idx, shouldHelp: true);
                    goto TRY_WITH_NEW_TABLE;
                }

                // Otherwise we lost the CAS to another racing put.
                entryValue = prev;
                if (!EntryValueNullOrDead(entryValue))
                {
                    goto GOT_PREV_VALUE;
                }
            }

GOT_PREV_VALUE:
            // PERF: this would be nice to have as a helper,
            // but it does not get inlined
            if (default(TValue) == null && entryValue == NULLVALUE)
            {
                entryValue = null;
            }
            result = (TValue)entryValue;

DONE:
            return(result);
        }
Пример #22
0
        internal void OnHeartbeat(bool ifConnectedOnly)
        {
            bool runThisTime = false;

            try
            {
                runThisTime = !isDisposed && Interlocked.CompareExchange(ref beating, 1, 0) == 0;
                if (!runThisTime)
                {
                    return;
                }

                uint index          = (uint)Interlocked.Increment(ref profileLogIndex);
                long newSampleCount = Interlocked.Read(ref operationCount);
                Interlocked.Exchange(ref profileLog[index % ProfileLogSamples], newSampleCount);
                Interlocked.Exchange(ref profileLastLog, newSampleCount);
                Trace("OnHeartbeat: " + (State)state);
                switch (state)
                {
                case (int)State.Connecting:
                    int  connectTimeMilliseconds = unchecked (Environment.TickCount - VolatileWrapper.Read(ref connectStartTicks));
                    bool shouldRetry             = Multiplexer.RawConfig.ReconnectRetryPolicy.ShouldRetry(Interlocked.Read(ref connectTimeoutRetryCount), connectTimeMilliseconds);
                    if (shouldRetry)
                    {
                        Interlocked.Increment(ref connectTimeoutRetryCount);
                        LastException = ExceptionFactory.UnableToConnect(Multiplexer.RawConfig.AbortOnConnectFail, "ConnectTimeout");
                        Trace("Aborting connect");
                        // abort and reconnect
                        var   snapshot = physical;
                        bool  isCurrent;
                        State oldState;
                        OnDisconnected(ConnectionFailureType.UnableToConnect, snapshot, out isCurrent, out oldState);
                        using (snapshot) { }     // dispose etc
                        TryConnect(null);
                    }
                    if (!ifConnectedOnly)
                    {
                        AbortUnsent();
                    }
                    break;

                case (int)State.ConnectedEstablishing:
                case (int)State.ConnectedEstablished:
                    var tmp = physical;
                    if (tmp != null)
                    {
                        if (state == (int)State.ConnectedEstablished)
                        {
                            Interlocked.Exchange(ref connectTimeoutRetryCount, 0);
                            tmp.Bridge.ServerEndPoint.ClearUnselectable(UnselectableFlags.DidNotRespond);
                        }
                        tmp.OnHeartbeat();
                        int writeEverySeconds  = ServerEndPoint.WriteEverySeconds,
                            checkConfigSeconds = Multiplexer.RawConfig.ConfigCheckSeconds;

                        if (state == (int)State.ConnectedEstablished && ConnectionType == ConnectionType.Interactive &&
                            checkConfigSeconds > 0 && ServerEndPoint.LastInfoReplicationCheckSecondsAgo >= checkConfigSeconds &&
                            ServerEndPoint.CheckInfoReplication())
                        {
                            // that serves as a keep-alive, if it is accepted
                        }
                        else if (writeEverySeconds > 0 && tmp.LastWriteSecondsAgo >= writeEverySeconds)
                        {
                            Trace("OnHeartbeat - overdue");
                            if (state == (int)State.ConnectedEstablished)
                            {
                                KeepAlive();
                            }
                            else
                            {
                                bool  ignore;
                                State oldState;
                                OnDisconnected(ConnectionFailureType.SocketFailure, tmp, out ignore, out oldState);
                            }
                        }
                        else if (!queue.Any() && tmp.GetSentAwaitingResponseCount() != 0)
                        {
                            // there's a chance this is a dead socket; sending data will shake that
                            // up a bit, so if we have an empty unsent queue and a non-empty sent
                            // queue, test the socket
                            KeepAlive();
                        }
                    }
                    break;

                case (int)State.Disconnected:
                    Interlocked.Exchange(ref connectTimeoutRetryCount, 0);
                    if (!ifConnectedOnly)
                    {
                        AbortUnsent();
                        Multiplexer.Trace("Resurrecting " + this.ToString());
                        GetConnection(null);
                    }
                    break;

                default:
                    Interlocked.Exchange(ref connectTimeoutRetryCount, 0);
                    if (!ifConnectedOnly)
                    {
                        AbortUnsent();
                    }
                    break;
                }
            }
            catch (Exception ex)
            {
                OnInternalError(ex);
                Trace("OnHeartbeat error: " + ex.Message);
            }
            finally
            {
                if (runThisTime)
                {
                    Interlocked.Exchange(ref beating, 0);
                }
            }
        }
Пример #23
0
        internal void HelpCopyImpl(bool copy_all)
        {
            var newTable   = _newTable;
            var oldEntries = _entries;
            int toCopy     = oldEntries.Length;

#if DEBUG
            const int CHUNK_SIZE = 16;
#else
            const int CHUNK_SIZE = 1024;
#endif
            int MIN_COPY_WORK = Math.Min(toCopy, CHUNK_SIZE); // Limit per-thread work

            bool panic        = false;
            int  claimedChunk = -1;

            while (_copyDone < toCopy)
            {
                // Still needing to copy?
                // Carve out a chunk of work.
                if (!panic)
                {
                    claimedChunk = _claimedChunk;

                    for (;;)
                    {
                        // panic check
                        // We "panic" if we have tried TWICE to copy every slot - and it still
                        // has not happened.  i.e., twice some thread somewhere claimed they
                        // would copy 'slot X' (by bumping _copyIdx) but they never claimed to
                        // have finished (by bumping _copyDone).  Our choices become limited:
                        // we can wait for the work-claimers to finish (and become a blocking
                        // algorithm) or do the copy work ourselves.  Tiny tables with huge
                        // thread counts trying to copy the table often 'panic'.
                        if (claimedChunk > (toCopy / (CHUNK_SIZE / 2)))
                        {
                            panic = true;
                            //System.Console.WriteLine("panic");
                            break;
                        }

                        var alreadyClaimed = Interlocked.CompareExchange(ref _claimedChunk, claimedChunk + 1, claimedChunk);
                        if (alreadyClaimed == claimedChunk)
                        {
                            break;
                        }

                        claimedChunk = alreadyClaimed;
                    }
                }
                else
                {
                    // we went through the whole table in panic mode
                    // there cannot be possibly anything left to copy.
                    if (claimedChunk > ((toCopy / (CHUNK_SIZE / 2)) + toCopy / CHUNK_SIZE))
                    {
                        _copyDone = toCopy;
                        PromoteNewTable();
                        return;
                    }

                    claimedChunk++;
                }

                // We now know what to copy.  Try to copy.
                int workdone  = 0;
                int copyStart = claimedChunk * CHUNK_SIZE;
                for (int i = 0; i < MIN_COPY_WORK; i++)
                {
                    if (_copyDone >= toCopy)
                    {
                        PromoteNewTable();
                        return;
                    }

                    if (CopySlot(ref oldEntries[(copyStart + i) & (toCopy - 1)], newTable))
                    {
                        workdone++;
                    }
                }

                if (workdone > 0)
                {
                    // See if we can promote
                    var copyDone = Interlocked.Add(ref _copyDone, workdone);

                    // Check for copy being ALL done, and promote.
                    if (copyDone >= toCopy)
                    {
                        PromoteNewTable();
                    }
                }

                if (!(copy_all | panic))
                {
                    return;
                }
            }

            // Extra promotion check, in case another thread finished all copying
            // then got stalled before promoting.
            PromoteNewTable();
        }
Пример #24
0
        internal void RemovePhysical(PhysicalConnection connection)
        {
#pragma warning disable 0420
            Interlocked.CompareExchange(ref physical, null, connection);
#pragma warning restore 0420
        }
Пример #25
0
            internal static void Peak(ref StatisticsState state, TimeSpan time, long value)
            {
                StatisticsState State;
                var             Wait = new SpinWait();

                for (; ;)
                {
                    State = Volatile.Read(ref state);

                    var Interval = State._Interval;

                    if (Interval == TimeSpan.Zero)
                    {
                        var OldValue = Volatile.Read(ref State._Current);

                        if (OldValue >= value || Interlocked.CompareExchange(ref State._Current, value, OldValue) >= value)
                        {
                            return;
                        }

                        continue;
                    }

                    var Finish = State._Time + Interval;

                    if (time < Finish)
                    {
                        // Still within the time interval
                        var OldValue = Volatile.Read(ref State._Current);

                        if (OldValue == -1)
                        {
                            // Expired. Wait a moment for the other thread to finish replacing the state
                            Wait.SpinOnce();
                        }
                        else
                        {
                            if (OldValue >= value || Interlocked.CompareExchange(ref State._Current, value, OldValue) >= value)
                            {
                                return;
                            }

                            // Another thread replaced our value with something greater than the previous peak, but less than our new peak
                        }
                    }
                    else if (time < Finish + Interval)
                    {
                        // We're within the next time interval, flag the state as expired so we can lock in that interval
                        var Previous = Interlocked.Exchange(ref State._Current, -1);

                        if (Previous != -1)
                        {
                            var NewState = new StatisticsState(Interval, time, value, Previous);

                            // Replace the current state with a new state
                            if (Interlocked.CompareExchange(ref state, NewState, State) == State)
                            {
                                return;
                            }
                        }
                        else
                        {
                            // Wait a moment for the other thread to finish replacing the state
                            Wait.SpinOnce();
                        }

                        // Another thread is performing a replacement, wait and try again
                    }
                    else
                    {
                        // Two intervals have passed since this state began recording, so we replace with a zero previous record
                        var NewState = new StatisticsState(Interval, time, value);

                        // Replace the current state with a new state
                        if (Interlocked.CompareExchange(ref state, NewState, State) == State)
                        {
                            return;
                        }

                        // Another thread is performing a replacement, wait and try again
                    }
                }
            }
Пример #26
0
        internal WriteResult WriteQueue(int maxWork)
        {
            bool weAreWriter        = false;
            PhysicalConnection conn = null;

            try
            {
                Trace("Writing queue from bridge");

                weAreWriter = Interlocked.CompareExchange(ref activeWriters, 1, 0) == 0;
                if (!weAreWriter)
                {
                    Trace("(aborting: existing writer)");
                    return(WriteResult.CompetingWriter);
                }

                conn = GetConnection(null);
                if (conn == null)
                {
                    AbortUnsent();
                    Trace("Connection not available; exiting");
                    return(WriteResult.NoConnection);
                }

                Message last;
                int     count = 0;
                while (true)
                {
                    var next = queue.Dequeue();
                    if (next == null)
                    {
                        Trace("Nothing to write; exiting");
                        if (count == 0)
                        {
                            conn.Flush(); // only flush on an empty run
                            return(WriteResult.NothingToDo);
                        }
                        return(WriteResult.QueueEmptyAfterWrite);
                    }
                    last = next;

                    Trace("Now pending: " + GetPendingCount());
                    if (!WriteMessageDirect(conn, next))
                    {
                        AbortUnsent();
                        Trace("write failed; connection is toast; exiting");
                        return(WriteResult.NoConnection);
                    }
                    count++;
                    if (maxWork > 0 && count >= maxWork)
                    {
                        Trace("Work limit; exiting");
                        Trace(last != null, "Flushed up to: " + last);
                        conn.Flush();
                        break;
                    }
                }
            }
            catch (IOException ex)
            {
                if (conn != null)
                {
                    conn.RecordConnectionFailed(ConnectionFailureType.SocketFailure, ex);
                    conn = null;
                }
                AbortUnsent();
            }
            catch (Exception ex)
            {
                AbortUnsent();
                OnInternalError(ex);
            }
            finally
            {
                if (weAreWriter)
                {
                    Interlocked.Exchange(ref activeWriters, 0);
                    Trace("Exiting writer");
                }
            }
            return(queue.Any() ? WriteResult.MoreWork : WriteResult.QueueEmptyAfterWrite);
        }
Пример #27
0
 internal bool EnterSession()
 {
     return(Interlocked.CompareExchange(ref _isInSession, 1, 0) == 0);
 }
Пример #28
0
 /// <summary>
 /// Resets the trigger status
 /// </summary>
 void Reset()
 {
     Interlocked.CompareExchange(ref _triggered, 0, 1);
 }
Пример #29
0
        private bool TryAuthorize(RouteInformation route, HttpContext context, DocumentDatabase database)
        {
            var feature = context.Features.Get<IHttpAuthenticationFeature>() as RavenServer.AuthenticateConnection;

            if(_auditLog != null)
            {
                if(feature.WrittenToAuditLog == 0) // intentionally racy, we'll check it again later
                {
                    // only one thread will win it, technically, there can't really be threading
                    // here, because there is a single connection, but better to be safe
                    if(Interlocked.CompareExchange(ref feature.WrittenToAuditLog, 1, 0) == 0)
                    {
                        if(feature.WrongProtocolMessage != null)
                        {
                            _auditLog.Info($"Connection from {context.Connection.RemoteIpAddress}:{context.Connection.RemotePort} " +
                                $"used the wrong protocol and will be rejected. {feature.WrongProtocolMessage}");
                        }
                        else
                        {
                            _auditLog.Info($"Connection from {context.Connection.RemoteIpAddress}:{context.Connection.RemotePort} " +
                                $"with certificate '{feature.Certificate?.Subject} ({feature.Certificate?.Thumbprint})', status: {feature.StatusForAudit}, " +
                                $"databases: [{string.Join(", ", feature.AuthorizedDatabases.Keys)}]");
                        }
                    }
                }
            }

            var authenticationStatus = feature?.Status;

            switch (route.AuthorizationStatus)
            {
                case AuthorizationStatus.UnauthenticatedClients:
                    var userWantsToAccessStudioMainPage = context.Request.Path == "/studio/index.html";
                    if (userWantsToAccessStudioMainPage)
                    {
                        switch (authenticationStatus)
                        {
                            case null:
                            case RavenServer.AuthenticationStatus.NoCertificateProvided:
                            case RavenServer.AuthenticationStatus.Expired:
                            case RavenServer.AuthenticationStatus.NotYetValid:
                            case RavenServer.AuthenticationStatus.None:
                            case RavenServer.AuthenticationStatus.UnfamiliarCertificate:
                                UnlikelyFailAuthorization(context, database?.Name, feature);
                                return false;
                        }
                    }
                    
                    return true;
                case AuthorizationStatus.ClusterAdmin:
                case AuthorizationStatus.Operator:
                case AuthorizationStatus.ValidUser:
                case AuthorizationStatus.DatabaseAdmin:

                    switch (authenticationStatus)
                    {
                        case null:
                        case RavenServer.AuthenticationStatus.NoCertificateProvided:
                        case RavenServer.AuthenticationStatus.Expired:
                        case RavenServer.AuthenticationStatus.NotYetValid:
                        case RavenServer.AuthenticationStatus.None:
                        case RavenServer.AuthenticationStatus.UnfamiliarCertificate:
                            UnlikelyFailAuthorization(context, database?.Name, feature);
                            return false;
                        case RavenServer.AuthenticationStatus.Allowed:
                            if (route.AuthorizationStatus == AuthorizationStatus.Operator || route.AuthorizationStatus == AuthorizationStatus.ClusterAdmin)
                                goto case RavenServer.AuthenticationStatus.None;

                            if (database == null)
                                return true;

                            if (feature.CanAccess(database.Name, route.AuthorizationStatus == AuthorizationStatus.DatabaseAdmin))
                                return true;

                            goto case RavenServer.AuthenticationStatus.None;
                        case RavenServer.AuthenticationStatus.Operator:
                            if (route.AuthorizationStatus == AuthorizationStatus.ClusterAdmin)
                                goto case RavenServer.AuthenticationStatus.None;
                            return true;
                        case RavenServer.AuthenticationStatus.ClusterAdmin:
                            return true;
                        default:
                            throw new ArgumentOutOfRangeException();
                    }
                default:
                    ThrowUnknownAuthStatus(route);
                    return false; // never hit
            }
        }
        /// <summary>
        /// Called when a work item stops.  The activity name = providerName + activityName without 'Stop' suffix.
        /// It updates m_current variable to track this fact.   The Stop event associated with stop should log the ActivityID associated with the event.
        ///
        /// If activity tracing is not on, then activityId and relatedActivityId are not set
        /// </summary>
        public void OnStop(string providerName, string activityName, int task, ref Guid activityId, bool useTplSource = true)
        {
            if (m_current == null)        // We are not enabled
            {
                return;
            }

            string fullActivityName = NormalizeActivityName(providerName, activityName, task);

            TplEventSource?log      = useTplSource ? TplEventSource.Log : null;
            bool           tplDebug = log != null && log.Debug;

            if (tplDebug)
            {
                log !.DebugFacilityMessage("OnStopEnter", fullActivityName);
                log !.DebugFacilityMessage("OnStopEnterActivityState", ActivityInfo.LiveActivities(m_current.Value));
            }

            while (true) // This is a retry loop.
            {
                ActivityInfo?currentActivity    = m_current.Value;
                ActivityInfo?newCurrentActivity = null;                // if we have seen any live activities (orphans), at he first one we have seen.

                // Search to find the activity to stop in one pass.   This insures that we don't let one mistake
                // (stopping something that was not started) cause all active starts to be stopped
                // By first finding the target start to stop we are more robust.
                ActivityInfo?activityToStop = FindActiveActivity(fullActivityName, currentActivity);

                // ignore stops where we can't find a start because we may have popped them previously.
                if (activityToStop == null)
                {
                    activityId = Guid.Empty;
                    // TODO add some logging about this. Basically could not find matching start.
                    if (tplDebug)
                    {
                        log !.DebugFacilityMessage("OnStopRET", "Fail");
                    }
                    return;
                }

                activityId = activityToStop.ActivityId;

                // See if there are any orphans that need to be stopped.
                ActivityInfo?orphan = currentActivity;
                while (orphan != activityToStop && orphan != null)
                {
                    if (orphan.m_stopped != 0)      // Skip dead activities.
                    {
                        orphan = orphan.m_creator;
                        continue;
                    }
                    if (orphan.CanBeOrphan())
                    {
                        // We can't pop anything after we see a valid orphan, remember this for later when we update m_current.
                        newCurrentActivity ??= orphan;
                    }
                    else
                    {
                        orphan.m_stopped = 1;
                        Debug.Assert(orphan.m_stopped != 0);
                    }
                    orphan = orphan.m_creator;
                }

                // try to Stop the activity atomically.  Other threads may be trying to do this as well.
                if (Interlocked.CompareExchange(ref activityToStop.m_stopped, 1, 0) == 0)
                {
                    // I succeeded stopping this activity. Now we update our m_current pointer

                    // If I haven't yet determined the new current activity, it is my creator.
                    newCurrentActivity ??= activityToStop.m_creator;

                    m_current.Value = newCurrentActivity;

                    if (tplDebug)
                    {
                        log !.DebugFacilityMessage("OnStopRetActivityState", ActivityInfo.LiveActivities(newCurrentActivity));
                        log !.DebugFacilityMessage("OnStopRet", activityId.ToString());
                    }
                    return;
                }
                // We failed to stop it.  We must have hit a race to stop it.  Just start over and try again.
            }
        }