Skip to content

Commit

Permalink
RavenDB-2945 Live test plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
ppekrol committed Nov 20, 2014
1 parent a75bcbc commit 94fcbc2
Show file tree
Hide file tree
Showing 10 changed files with 548 additions and 2 deletions.
104 changes: 104 additions & 0 deletions Bundles/Raven.Bundles.LiveTest/LiveTestDatabaseCleanerStartupTask.cs
@@ -0,0 +1,104 @@
// -----------------------------------------------------------------------
// <copyright file="LiveTestDatabaseCleanerStartupTask.cs" company="Hibernating Rhinos LTD">
// Copyright (c) Hibernating Rhinos LTD. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------
using System;
using System.Configuration;
using System.Linq;
using System.Threading;

using Raven.Abstractions;
using Raven.Abstractions.Data;
using Raven.Database.Extensions;
using Raven.Database.Plugins;
using Raven.Json.Linq;
using Raven.Server;

namespace Raven.Bundles.LiveTest
{
public class LiveTestDatabaseCleanerStartupTask : IServerStartupTask
{
private Timer checkTimer;

private RavenDbServer server;

private TimeSpan maxTimeDatabaseCanBeIdle;

public void Execute(RavenDbServer server)
{
this.server = server;

int val;
if (int.TryParse(ConfigurationManager.AppSettings["Raven/Bundles/LiveTest/Tenants/MaxIdleTimeForTenantDatabase"], out val) == false)
val = 900;

maxTimeDatabaseCanBeIdle = TimeSpan.FromSeconds(val); ;

checkTimer = new Timer(ExecuteCleanup, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(10));
}

public void Dispose()
{
if (checkTimer != null)
checkTimer.Dispose();
}

private void ExecuteCleanup(object state)
{
var databaseLandLord = server.Options.DatabaseLandlord;
var systemDatabase = databaseLandLord.SystemDatabase;
if (server.Disposed)
{
Dispose();
return;
}

int nextStart = 0;
var databaseDocuments = systemDatabase
.Documents
.GetDocumentsWithIdStartingWith(Constants.RavenDatabasesPrefix, null, null, 0, int.MaxValue, CancellationToken.None, ref nextStart);

var databaseIds = databaseDocuments
.Select(x => ((RavenJObject)x)["@metadata"])
.Where(x => x != null)
.Select(x => x.Value<string>("@id"))
.Where(x => x != null && x != Constants.SystemDatabase)
.ToList();

foreach (var databaseId in databaseIds)
{
var key = databaseId;
if (key.StartsWith(Constants.RavenDatabasesPrefix))
key = key.Substring(Constants.RavenDatabasesPrefix.Length);

var shouldCleanup = false;

DateTime value;
if (databaseLandLord.IsDatabaseLoaded(key) == false)
shouldCleanup = true;
else if (databaseLandLord.LastRecentlyUsed.TryGetValue(key, out value) && (SystemTime.UtcNow - value) > maxTimeDatabaseCanBeIdle)
shouldCleanup = true;

if (shouldCleanup == false)
continue;

var configuration = databaseLandLord.CreateTenantConfiguration(key, true);

databaseLandLord.Cleanup(key, maxTimeDatabaseCanBeIdle, database => false);

var docKey = Constants.RavenDatabasesPrefix + key;
systemDatabase.Documents.Delete(docKey, null, null);

if (configuration == null)
continue;

IOExtensions.DeleteDirectory(configuration.DataDirectory);
if (configuration.IndexStoragePath != null)
IOExtensions.DeleteDirectory(configuration.IndexStoragePath);
if (configuration.JournalsStoragePath != null)
IOExtensions.DeleteDirectory(configuration.JournalsStoragePath);
}
}
}
}
@@ -0,0 +1,75 @@
// -----------------------------------------------------------------------
// <copyright file="LiveTestDatabaseCreationTrigger.cs" company="Hibernating Rhinos LTD">
// Copyright (c) Hibernating Rhinos LTD. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------
using System;
using System.Configuration;

using Raven.Abstractions.Data;
using Raven.Database.Config;
using Raven.Database.Extensions;
using Raven.Database.Plugins;
using Raven.Json.Linq;

namespace Raven.Bundles.LiveTest
{
public class LiveTestDatabaseDocumentPutTrigger : AbstractPutTrigger
{
private const int QuotasHardLimitInKb = 512 * 1024;

private const int QuotasSoftMarginInKb = (int)(0.75 * QuotasHardLimitInKb);

public override void OnPut(string key, RavenJObject document, RavenJObject metadata, TransactionInformation transactionInformation)
{
if (string.IsNullOrEmpty(Database.Name) == false && Database.Name != Constants.SystemDatabase)
return;

if (key.StartsWith(Constants.RavenDatabasesPrefix, StringComparison.OrdinalIgnoreCase) == false)
return;

RavenJObject settings;
RavenJToken value;
if (document.TryGetValue("Settings", out value) == false)
document["Settings"] = settings = new RavenJObject();
else
settings = (RavenJObject)value;

EnsureQuotasBundleActivated(settings);
EnsureVoronIsSetAsStorageEngineAndIsRunningInMemory(settings);
}

private static void EnsureVoronIsSetAsStorageEngineAndIsRunningInMemory(RavenJObject settings)
{
settings["Raven/StorageEngine"] = InMemoryRavenConfiguration.VoronTypeName;
settings["Raven/RunInMemory"] = true;
}

private static void EnsureQuotasBundleActivated(RavenJObject settings)
{
RavenJToken value;
if (settings.TryGetValue(Constants.ActiveBundles, out value) == false)
settings[Constants.ActiveBundles] = value = new RavenJValue(string.Empty);

var activeBundles = value.Value<string>();
var bundles = activeBundles.GetSemicolonSeparatedValues();

if (bundles.Contains("Quotas") == false)
bundles.Add("Quotas");

int hardLimitInKb;
if (int.TryParse(ConfigurationManager.AppSettings["Raven/Bundles/LiveTest/Quotas/Size/HardLimitInKB"], out hardLimitInKb) == false)
hardLimitInKb = QuotasHardLimitInKb;

int softMarginInKb;
if (int.TryParse(ConfigurationManager.AppSettings["Raven/Bundles/LiveTest/Quotas/Size/SoftLimitInKB"], out softMarginInKb) == false)
softMarginInKb = QuotasSoftMarginInKb;

settings[Constants.ActiveBundles] = string.Join(";", bundles);
settings[Constants.SizeHardLimitInKB] = hardLimitInKb;
settings[Constants.SizeSoftLimitInKB] = softMarginInKb;
settings[Constants.DocsHardLimit] = null;
settings[Constants.DocsSoftLimit] = null;
}
}
}
79 changes: 79 additions & 0 deletions Bundles/Raven.Bundles.LiveTest/Raven.Bundles.LiveTest.csproj
@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{108260D1-12ED-4EC5-8C6B-1DED1D73271F}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Raven.Bundles.LiveTest</RootNamespace>
<AssemblyName>Raven.Bundles.LiveTest</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>..\..\Raven.Database\RavenDB.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\CommonAssemblyInfo.cs">
<Link>Properties\CommonAssemblyInfo.cs</Link>
</Compile>
<Compile Include="LiveTestDatabaseCleanerStartupTask.cs" />
<Compile Include="LiveTestDatabaseDocumentPutTrigger.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Raven.Abstractions\Raven.Abstractions.csproj">
<Project>{41ac479e-1eb2-4d23-aaf2-e4c8df1bc2ba}</Project>
<Name>Raven.Abstractions</Name>
</ProjectReference>
<ProjectReference Include="..\..\Raven.Database\Raven.Database.csproj">
<Project>{212823cd-25e1-41ac-92d1-d6df4d53fc85}</Project>
<Name>Raven.Database</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<ItemGroup>
<None Include="..\..\Raven.Database\RavenDB.snk">
<Link>RavenDB.snk</Link>
</None>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
4 changes: 4 additions & 0 deletions Raven.Abstractions/Data/Constants.cs
Expand Up @@ -178,5 +178,9 @@ static Constants()
public const string IncrementalBackupRecurringAlertTimeout = "Raven/IncrementalBackup/RecurringAlertTimeoutDays";
public const string IncrementalBackupState = "IncrementalBackupState.Document";


// General

public const string RavenDatabasesPrefix = "Raven/Databases/";
}
}
85 changes: 85 additions & 0 deletions Raven.Tests.Bundles/LiveTest/PutTriggerTests.cs
@@ -0,0 +1,85 @@
// -----------------------------------------------------------------------
// <copyright file="PutTriggerTests.cs" company="Hibernating Rhinos LTD">
// Copyright (c) Hibernating Rhinos LTD. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------
using System.ComponentModel.Composition.Hosting;
using System.Configuration;

using Raven.Abstractions.Data;
using Raven.Bundles.LiveTest;
using Raven.Client.Connection;
using Raven.Database.Config;
using Raven.Database.Extensions;
using Raven.Json.Linq;
using Raven.Tests.Common;

using Xunit;

namespace Raven.Tests.Bundles.LiveTest
{
public class PutTriggerTests : RavenTest
{
protected override void ModifyConfiguration(InMemoryRavenConfiguration configuration)
{
configuration.Catalog.Catalogs.Add(new AssemblyCatalog(typeof(LiveTestDatabaseDocumentPutTrigger).Assembly));
}

[Fact]
public void PutTriggerShouldEnableQuotasAndVoron()
{
using (var store = NewDocumentStore())
{
store
.DatabaseCommands
.GlobalAdmin
.CreateDatabase(new DatabaseDocument
{
Id = "Northwind",
Settings =
{
{ "Raven/ActiveBundles", "Replication" },
{ "Raven/DataDir", NewDataPath() }
}
});

var document = store.DatabaseCommands.Get("Raven/Databases/Northwind");
Assert.NotNull(document);

var databaseDocument = document.DataAsJson.Deserialize<DatabaseDocument>(store.Conventions);
AsserDatabaseDocument(databaseDocument);

databaseDocument.Settings[Constants.SizeHardLimitInKB] = "123";
databaseDocument.Settings[Constants.SizeSoftLimitInKB] = "321";
databaseDocument.Settings[Constants.DocsHardLimit] = "456";
databaseDocument.Settings[Constants.DocsSoftLimit] = "654";
databaseDocument.Settings["Raven/RunInMemory"] = "false";
databaseDocument.Settings["Raven/StorageEngine"] = "esent";

store.DatabaseCommands.Put("Raven/Databases/Northwind", null, RavenJObject.FromObject(databaseDocument), document.Metadata);

document = store.DatabaseCommands.Get("Raven/Databases/Northwind");
Assert.NotNull(document);

databaseDocument = document.DataAsJson.Deserialize<DatabaseDocument>(store.Conventions);
AsserDatabaseDocument(databaseDocument);
}
}

private static void AsserDatabaseDocument(DatabaseDocument databaseDocument)
{
var activeBundles = databaseDocument.Settings[Constants.ActiveBundles].GetSemicolonSeparatedValues();

Assert.Contains("Replication", activeBundles);

Assert.Contains("Quotas", activeBundles);
Assert.Equal(ConfigurationManager.AppSettings["Raven/Bundles/LiveTest/Quotas/Size/HardLimitInKB"], databaseDocument.Settings[Constants.SizeHardLimitInKB]);
Assert.Equal(ConfigurationManager.AppSettings["Raven/Bundles/LiveTest/Quotas/Size/SoftLimitInKB"], databaseDocument.Settings[Constants.SizeSoftLimitInKB]);
Assert.Null(databaseDocument.Settings[Constants.DocsHardLimit]);
Assert.Null(databaseDocument.Settings[Constants.DocsSoftLimit]);

Assert.True(bool.Parse(databaseDocument.Settings["Raven/RunInMemory"]));
Assert.Equal(InMemoryRavenConfiguration.VoronTypeName, databaseDocument.Settings["Raven/StorageEngine"]);
}
}
}

0 comments on commit 94fcbc2

Please sign in to comment.