public void Cleanup(string db, bool skipIfActive, Func <TResource, bool> shouldSkip = null) { using (ResourcesStoresCache.WithAllLocks()) { DateTime time; Task <TResource> databaseTask; if (ResourcesStoresCache.TryGetValue(db, out databaseTask) == false) { LastRecentlyUsed.TryRemove(db, out time); return; } if (databaseTask.Status == TaskStatus.Faulted || databaseTask.Status == TaskStatus.Canceled) { LastRecentlyUsed.TryRemove(db, out time); ResourcesStoresCache.TryRemove(db, out databaseTask); return; } if (databaseTask.Status != TaskStatus.RanToCompletion) { return; // still starting up } var database = databaseTask.Result; if ((skipIfActive && (SystemTime.UtcNow - LastWork(database)).TotalMinutes < 10) || (shouldSkip != null && shouldSkip(database))) { // this document might not be actively working with user, but it is actively doing indexes, we will // wait with unloading this database until it hasn't done indexing for a while. // This prevent us from shutting down big databases that have been left alone to do indexing work. return; } try { database.Dispose(); } catch (Exception e) { Logger.ErrorException("Could not cleanup tenant database: " + db, e); return; } LastRecentlyUsed.TryRemove(db, out time); ResourcesStoresCache.TryRemove(db, out databaseTask); var onDatabaseCleanupOccured = CleanupOccured; if (onDatabaseCleanupOccured != null) { onDatabaseCleanupOccured(db); } } }
protected void CleanupDatabase(string db, bool skipIfActive) { using (ResourcesStoresCache.WithAllLocks()) { DateTime time; Task <DocumentDatabase> databaseTask; if (ResourcesStoresCache.TryGetValue(db, out databaseTask) == false) { databaseLastRecentlyUsed.TryRemove(db, out time); return; } if (databaseTask.Status == TaskStatus.Faulted || databaseTask.Status == TaskStatus.Canceled) { databaseLastRecentlyUsed.TryRemove(db, out time); ResourcesStoresCache.TryRemove(db, out databaseTask); return; } if (databaseTask.Status != TaskStatus.RanToCompletion) { return; // still starting up } var database = databaseTask.Result; if (skipIfActive && (SystemTime.UtcNow - database.WorkContext.LastWorkTime).TotalMinutes < 5) { // this document might not be actively working with user, but it is actively doing indexes, we will // wait with unloading this database until it hasn't done indexing for a while. // This prevent us from shutting down big databases that have been left alone to do indexing work. return; } try { database.Dispose(); } catch (Exception e) { logger.ErrorException("Could not cleanup tenant database: " + db, e); return; } databaseLastRecentlyUsed.TryRemove(db, out time); ResourcesStoresCache.TryRemove(db, out databaseTask); } }
private DatabaseConnectionState GetOrAddConnectionState(string name, string watchCommand, string unwatchCommand, string value) { var counter = _counters.GetOrAdd(name, s => { async Task OnDisconnect() { try { if (Connected) { await Send(unwatchCommand, value).ConfigureAwait(false); } } catch (WebSocketException) { // if we are not connected then we unsubscribed already // because connections drops with all subscriptions } DatabaseConnectionState state; if (_counters.TryRemove(s, out state)) { state.Dispose(); } } async Task <bool> OnConnect() { try { if (Connected) { await Send(watchCommand, value).ConfigureAwait(false); return(true); } } catch (WebSocketException) { // if we are not connected then we will subscribe again after connection be established } return(false); } return(new DatabaseConnectionState(this, OnConnect, OnDisconnect)); }); return(counter); }
private DatabaseConnectionState GetOrAddConnectionState(string name, string watchCommand, string unwatchCommand, string value) { bool newValue = false; var counter = _counters.GetOrAdd(name, s => { async Task OnDisconnect() { try { if (Connected) { await Send(unwatchCommand, value).ConfigureAwait(false); } } catch (WebSocketException) { // if we are not connected then we unsubscribed already // because connections drops with all subscriptions } if (_counters.TryRemove(s, out var state)) { state.Dispose(); } } async Task OnConnect() { await Send(watchCommand, value).ConfigureAwait(false); } newValue = true; return(new DatabaseConnectionState(OnConnect, OnDisconnect)); }); // try to reconnect if (newValue && Volatile.Read(ref _immediateConnection) != 0) { counter.Set(counter.OnConnect()); } return(counter); }
private void ExecuteTimer(object state) { var span = state.ToString(); Tuple <Timer, ConcurrentSet <IRepeatedAction> > tuple; if (timers.TryGetValue(span, out tuple) == false) { return; } foreach (var repeatedAction in tuple.Item2) { if (repeatedAction.IsValid == false) { tuple.Item2.TryRemove(repeatedAction); } try { repeatedAction.Execute(); } catch (Exception e) { logger.ErrorException("Could not execute repeated task", e); } } if (tuple.Item2.Count != 0) { return; } if (timers.TryRemove(span, out tuple) == false) { return; } tuple.Item1.Dispose(); }
public void Cleanup(string resource, TimeSpan?skipIfActiveInDuration, Func <TResource, bool> shouldSkip = null, DocumentChangeTypes notificationType = DocumentChangeTypes.None) { if (Cleanups.TryAdd(resource, new ManualResetEvent(false)) == false) { return; } try { using (ResourcesStoresCache.WithAllLocks()) { DateTime time; Task <TResource> resourceTask; if (ResourcesStoresCache.TryGetValue(resource, out resourceTask) == false) { LastRecentlyUsed.TryRemove(resource, out time); return; } if (resourceTask.Status == TaskStatus.Faulted || resourceTask.Status == TaskStatus.Canceled) { LastRecentlyUsed.TryRemove(resource, out time); ResourcesStoresCache.TryRemove(resource, out resourceTask); return; } if (resourceTask.Status != TaskStatus.RanToCompletion) { return; // still starting up } var database = resourceTask.Result; if ((skipIfActiveInDuration != null && (SystemTime.UtcNow - LastWork(database)) < skipIfActiveInDuration) || (shouldSkip != null && shouldSkip(database))) { // this document might not be actively working with user, but it is actively doing indexes, we will // wait with unloading this database until it hasn't done indexing for a while. // This prevent us from shutting down big databases that have been left alone to do indexing work. return; } try { database.Dispose(); } catch (Exception e) { Logger.ErrorException("Could not cleanup tenant database: " + resource, e); return; } LastRecentlyUsed.TryRemove(resource, out time); ResourcesStoresCache.TryRemove(resource, out resourceTask); if (notificationType == DocumentChangeTypes.Delete) { TransportState transportState; ResourseTransportStates.TryRemove(resource, out transportState); if (transportState != null) { transportState.Dispose(); } } var onResourceCleanupOccured = CleanupOccured; if (onResourceCleanupOccured != null) { onResourceCleanupOccured(resource); } } } finally { ManualResetEvent cleanupLock; if (Cleanups.TryRemove(resource, out cleanupLock)) { cleanupLock.Set(); } } }