Example #1
0
        private Task <DocumentDatabase> CreateDatabase(StringSegment databaseName)
        {
            var config = CreateDatabaseConfiguration(databaseName);

            if (config == null)
            {
                return(null);
            }

            var hasAcquired = false;

            try
            {
                if (!ResourceSemaphore.Wait(ConcurrentResourceLoadTimeout))
                {
                    throw new ConcurrentLoadTimeoutException(
                              "Too much databases loading concurrently, timed out waiting for them to load.");
                }

                hasAcquired = true;

                var task     = new Task <DocumentDatabase>(() => CreateDocumentsStorage(databaseName, config));
                var database = ResourcesStoresCache.GetOrAdd(databaseName, task);
                if (database == task)
                {
                    task.Start();
                }

                if (database.IsFaulted && database.Exception != null)
                {
                    // if we are here, there is an error, and if there is an error, we need to clear it from the
                    // resource store cache so we can try to reload it.
                    // Note that we return the faulted task anyway, because we need the user to look at the error
                    if (database.Exception.Data.Contains("Raven/KeepInResourceStore") == false)
                    {
                        Task <DocumentDatabase> val;
                        ResourcesStoresCache.TryRemove(databaseName, out val);
                    }
                }

                database.ContinueWith(_ => ServerStore.TrackChange("Loaded", Constants.Database.Prefix + databaseName));

                return(database);
            }
            finally
            {
                if (hasAcquired)
                {
                    ResourceSemaphore.Release();
                }
            }
        }
Example #2
0
        public override bool TryGetOrCreateResourceStore(string resourceName, out Task <DocumentDatabase> resourceTask)
        {
            if (Locks.Contains(DisposingLock))
            {
                throw new ObjectDisposedException("DatabaseLandlord", "Server is shutting down, can't access any databases");
            }

            if (Locks.Contains(resourceName))
            {
                throw new InvalidOperationException("Database '" + resourceName + "' is currently locked and cannot be accessed.");
            }

            ManualResetEvent cleanupLock;

            if (Cleanups.TryGetValue(resourceName, out cleanupLock) && cleanupLock.WaitOne(MaxSecondsForTaskToWaitForDatabaseToLoad * 1000) == false)
            {
                throw new InvalidOperationException(string.Format("Database '{0}' is currently being restarted and cannot be accessed. We already waited {1} seconds.", resourceName, MaxSecondsForTaskToWaitForDatabaseToLoad));
            }

            if (ResourcesStoresCache.TryGetValue(resourceName, out resourceTask))
            {
                if (resourceTask.IsFaulted || resourceTask.IsCanceled)
                {
                    ResourcesStoresCache.TryRemove(resourceName, out resourceTask);
                    DateTime time;
                    LastRecentlyUsed.TryRemove(resourceName, out time);
                    // and now we will try creating it again
                }
                else
                {
                    return(true);
                }
            }

            var config = CreateTenantConfiguration(resourceName);

            if (config == null)
            {
                return(false);
            }


            if (!ResourceSemaphore.Wait(ConcurrentResourceLoadTimeout))
            {
                throw new ConcurrentLoadTimeoutException("Too much databases loading concurrently, timed out waiting for them to load.");
            }


            var didReleaseDuringWait = 0;
            var createdNewTask       = false;

            resourceTask = ResourcesStoresCache.GetOrAdd(resourceName, __ =>
            {
                createdNewTask = true;
                return(Task.Factory.StartNew(() =>
                {
                    var transportState = ResourseTransportStates.GetOrAdd(resourceName, s => new TransportState());

                    AssertLicenseParameters(config);
                    var documentDatabase = new DocumentDatabase(config, systemDatabase, transportState);

                    documentDatabase.SpinBackgroundWorkers(false);
                    documentDatabase.Disposing += DocumentDatabaseDisposingStarted;
                    documentDatabase.DisposingEnded += DocumentDatabaseDisposingEnded;
                    documentDatabase.StorageInaccessible += UnloadDatabaseOnStorageInaccessible;
                    // register only DB that has incremental backup set.
                    documentDatabase.OnBackupComplete += OnDatabaseBackupCompleted;

                    // if we have a very long init process, make sure that we reset the last idle time for this db.
                    LastRecentlyUsed.AddOrUpdate(resourceName, SystemTime.UtcNow, (_, time) => SystemTime.UtcNow);
                    documentDatabase.RequestManager = SystemDatabase.RequestManager;
                    documentDatabase.ClusterManager = SystemDatabase.ClusterManager;
                    return documentDatabase;
                }).ContinueWith(task =>
                {
                    if (task.Status == TaskStatus.RanToCompletion)
                    {
                        OnDatabaseLoaded(resourceName);
                    }

                    if (task.Status == TaskStatus.Faulted) // this observes the task exception
                    {
                        Logger.WarnException("Failed to create database " + resourceName, task.Exception);
                    }

                    ResourceSemaphore.Release();

                    return task;
                }).Unwrap());
            });

            if (createdNewTask == false)
            {
                ResourceSemaphore.Release();
            }


            if (resourceTask.IsFaulted && resourceTask.Exception != null)
            {
                // if we are here, there is an error, and if there is an error, we need to clear it from the
                // resource store cache so we can try to reload it.
                // Note that we return the faulted task anyway, because we need the user to look at the error
                if (resourceTask.Exception.Data.Contains("Raven/KeepInResourceStore") == false)
                {
                    Task <DocumentDatabase> val;
                    ResourcesStoresCache.TryRemove(resourceName, out val);
                }
            }

            return(true);
        }
Example #3
0
        public bool TryGetOrCreateResourceStore(string tenantId, out Task <RavenFileSystem> fileSystem)
        {
            if (Locks.Contains(DisposingLock))
            {
                throw new ObjectDisposedException("FileSystem", "Server is shutting down, can't access any file systems");
            }

            if (Locks.Contains(tenantId))
            {
                throw new InvalidOperationException("FileSystem '" + tenantId + "' is currently locked and cannot be accessed");
            }

            ManualResetEvent cleanupLock;

            if (Cleanups.TryGetValue(tenantId, out cleanupLock) && cleanupLock.WaitOne(MaxSecondsForTaskToWaitForDatabaseToLoad * 1000) == false)
            {
                throw new InvalidOperationException(string.Format("File system '{0}' is currently being restarted and cannot be accessed. We already waited {1} seconds.", tenantId, MaxSecondsForTaskToWaitForDatabaseToLoad));
            }

            if (ResourcesStoresCache.TryGetValue(tenantId, out fileSystem))
            {
                if (fileSystem.IsFaulted || fileSystem.IsCanceled)
                {
                    ResourcesStoresCache.TryRemove(tenantId, out fileSystem);
                    DateTime time;
                    LastRecentlyUsed.TryRemove(tenantId, out time);
                    // and now we will try creating it again
                }
                else
                {
                    return(true);
                }
            }

            var config = CreateTenantConfiguration(tenantId);

            if (config == null)
            {
                return(false);
            }

            var hasAcquired = false;

            try
            {
                if (!ResourceSemaphore.Wait(ConcurrentResourceLoadTimeout))
                {
                    throw new ConcurrentLoadTimeoutException("Too much filesystems loading concurrently, timed out waiting for them to load.");
                }

                hasAcquired = true;
                fileSystem  = ResourcesStoresCache.GetOrAdd(tenantId, __ => Task.Factory.StartNew(() =>
                {
                    var transportState = ResourseTransportStates.GetOrAdd(tenantId, s => new TransportState());

                    AssertLicenseParameters(config);
                    var fs = new RavenFileSystem(config, tenantId, transportState);
                    fs.Initialize();

                    // if we have a very long init process, make sure that we reset the last idle time for this db.
                    LastRecentlyUsed.AddOrUpdate(tenantId, SystemTime.UtcNow, (_, time) => SystemTime.UtcNow);
                    return(fs);
                }).ContinueWith(task =>
                {
                    if (task.Status == TaskStatus.Faulted) // this observes the task exception
                    {
                        Logger.WarnException("Failed to create filesystem " + tenantId, task.Exception);
                    }
                    return(task);
                }).Unwrap());
                return(true);
            }
            finally
            {
                if (hasAcquired)
                {
                    ResourceSemaphore.Release();
                }
            }
        }