private void AsyncOperationCompleting() { int oldValue = Interlocked.CompareExchange(ref _activeAsyncOperation, 0, 1); Debug.Assert(oldValue == 1, $"Expected {nameof(_activeAsyncOperation)} to be 1, got {oldValue}"); }
/// <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); }
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 } } }
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); }
// 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); }
internal void EnsureSetItem(ComMethodDesc candidate) { Interlocked.CompareExchange(ref _setItem, candidate, null); }
/// <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(); } } }
/// <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); }
/// <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); }
/// <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); } }
private object ExchangeInstanceConditionally <TService>(ref object instance, Func <TService> factory) { Interlocked.CompareExchange(ref instance, factory(), null); return(instance); }
// 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); }
/// <summary> /// Sets the timer as triggered /// </summary> void Set() { Interlocked.CompareExchange(ref _triggered, 1, 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(); } } }
bool IWeakReferenceable.SetWeakRef(WeakRefTracker value) { return Interlocked.CompareExchange<WeakRefTracker>(ref _tracker, value, null) == null; }
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)); } }
// 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(); } } }
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); }
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); } } }
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(); }
internal void RemovePhysical(PhysicalConnection connection) { #pragma warning disable 0420 Interlocked.CompareExchange(ref physical, null, connection); #pragma warning restore 0420 }
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 } } }
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); }
internal bool EnterSession() { return(Interlocked.CompareExchange(ref _isInSession, 1, 0) == 0); }
/// <summary> /// Resets the trigger status /// </summary> void Reset() { Interlocked.CompareExchange(ref _triggered, 0, 1); }
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. } }