Skip to content

Commit

Permalink
Applied (modified) patch from webpaul, supporting persistent caching …
Browse files Browse the repository at this point in the history
…of DSLs.

Updated Rhino ETL to avoid this caching.

git-svn-id: https://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/trunk@1645 079b0acf-d9fa-0310-9935-e5ade295c882
  • Loading branch information
ayenderahien committed Sep 13, 2008
1 parent d411a62 commit 2c7b0cd
Show file tree
Hide file tree
Showing 9 changed files with 530 additions and 180 deletions.
233 changes: 160 additions & 73 deletions Rhino.DSL.Tests/DslFactoryFixture/DslEngineFixture.cs
@@ -1,76 +1,163 @@
namespace Rhino.DSL.Tests.DslFactoryFixture
{
using System;
using System.IO;
using Boo.Lang.Compiler;
using MbUnit.Framework;
using Boo.Lang.Compiler.Ast;

[TestFixture]
public class DslEngineFixture
{
private MyDslEngine engine;

[SetUp]
public void SetUp()
{
engine = new MyDslEngine();
}

[Test]
public void When_DSL_engine_is_asked_to_create_a_DSL_it_will_compile_and_return_the_compiler_context()
{
string path = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"DslFactoryFixture\MyDsl.boo"));
CompilerContext compilerContext = engine.Compile(path);
Assert.AreEqual(0, compilerContext.Errors.Count);
Assert.IsNotNull(compilerContext.GeneratedAssembly);
}

[Test]
[ExpectedException(typeof(CompilerError))]
public void When_compilation_result_in_an_error_should_throw()
{
engine.Compile(Path.GetFullPath(@"somethingThatDoesNotExists.boo"));
}

[Test]
public void Dsl_engine_can_take_parameters()
{
DslFactory _Factory = new DslFactory();
_Factory.BaseDirectory = AppDomain.CurrentDomain.BaseDirectory;
_Factory.Register<MyClassWithParams>(new DslEngineWithParameters());
MyClassWithParams classWithParams = _Factory.Create<MyClassWithParams>("DslFactoryFixture\\ScriptWithParameter.boo");
Assert.AreEqual("World", classWithParams.Hello("World"));
}

}

public class MyDslEngine : DslEngine
{

}

public abstract class MyClassWithParams
{
public virtual string Hello(string input)
{
return input;
}
}

public class DslEngineWithParameters : DslEngine
{
protected override void CustomizeCompiler(BooCompiler compiler, CompilerPipeline pipeline, string[] urls)
{
ParameterDeclarationCollection parameters = new ParameterDeclarationCollection();
ParameterDeclaration newParameterDeclaration =
new ParameterDeclaration("input", new SimpleTypeReference("System.String"));
parameters.Add(newParameterDeclaration);

pipeline.Insert(1, new ImplicitBaseClassCompilerStep(typeof(MyClassWithParams),
"Hello",
parameters,
"System"));
}
}
using System;
using System.IO;
using Boo.Lang.Compiler;
using MbUnit.Framework;
using Boo.Lang.Compiler.Ast;

[TestFixture]
public class DslEngineFixture
{
private MyDslEngine engine;

[SetUp]
public void SetUp()
{
engine = new MyDslEngine();
}

[TearDown]
public void TearDown()
{
foreach (var file in Directory.GetFiles(Path.GetTempPath(), "*.boocache"))
{
File.Delete(file);
}
}

[Test]
public void When_DSL_engine_is_asked_to_create_a_DSL_it_will_compile_and_return_the_compiler_context()
{
string path = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"DslFactoryFixture\MyDsl.boo"));
CompilerContext compilerContext = engine.Compile(path);
Assert.AreEqual(0, compilerContext.Errors.Count);
Assert.IsNotNull(compilerContext.GeneratedAssembly);
}

[Test]
[ExpectedException(typeof(CompilerError))]
public void When_compilation_result_in_an_error_should_throw()
{
engine.Compile(Path.GetFullPath(@"somethingThatDoesNotExists.boo"));
}

[Test]
public void Dsl_engine_can_take_parameters()
{
var _Factory = new DslFactory
{
BaseDirectory = AppDomain.CurrentDomain.BaseDirectory
};
_Factory.Register<MyClassWithParams>(new DslEngineWithParameters());
var classWithParams = _Factory.Create<MyClassWithParams>("DslFactoryFixture\\ScriptWithParameter.boo");
Assert.AreEqual("World", classWithParams.Hello("World"));
}

[Test]
public void engine_reuses_first_compile()
{
string scriptPath = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"DslFactoryFixture\engine_reuses_first_compile.boo"));
File.WriteAllText(scriptPath, "print 0");

string lastCachedFilePath = null;

engine.CompilerContextCache.AssemblyLoaded += (filename, assembly, fromCache) => lastCachedFilePath = filename;
engine.Compile(scriptPath);
Assert.IsFalse(lastCachedFilePath == null);

lastCachedFilePath = null;

engine.Compile(scriptPath);
Assert.IsTrue(lastCachedFilePath == null);

}

[Test]
public void engine_recompiles_on_script_change()
{
string scriptPath = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"DslFactoryFixture\engine_recompiles_on_script_change.boo"));
string lastCachedFilePath = null;

engine.CompilerContextCache.AssemblyLoaded += (filename, assembly, fromCache) => lastCachedFilePath = filename;

File.WriteAllText(scriptPath, "print 1");
engine.Compile(scriptPath);
Assert.IsFalse(lastCachedFilePath == null);
lastCachedFilePath = null;
File.WriteAllText(scriptPath, "print 2");
engine.Compile(scriptPath);
Assert.IsFalse(lastCachedFilePath == null);
}

[Test]
public void engine_recompiles_on_script_add()
{
string scriptPath1 = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"DslFactoryFixture\engine_recompiles_on_script_add1.boo"));
File.WriteAllText(scriptPath1, "def doit1():\n print 1");

string scriptPath2 = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"DslFactoryFixture\engine_recompiles_on_script_add2.boo"));
File.WriteAllText(scriptPath2, "def doit2():\n print 2");

string lastCachedFilePath = null;

engine.CompilerContextCache.AssemblyLoaded += (filename, assembly, fromCache) => lastCachedFilePath = filename;

engine.Compile(scriptPath1);
Assert.IsFalse(lastCachedFilePath == null);
lastCachedFilePath = null;
engine.Compile(scriptPath1, scriptPath2);
Assert.IsFalse(lastCachedFilePath == null);
}

[Test]
public void engine_recompiles_on_script_remove()
{
string scriptPath1 = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"DslFactoryFixture\engine_recompiles_on_script_remove1.boo"));
File.WriteAllText(scriptPath1, "def doit1():\n print 1");

string scriptPath2 = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"DslFactoryFixture\engine_recompiles_on_script_remove2.boo"));
File.WriteAllText(scriptPath2, "def doit2():\n print 2");

string lastCachedFilePath = null;

engine.CompilerContextCache.AssemblyLoaded += (filename, assembly, fromCache) => lastCachedFilePath = filename;

engine.Compile(scriptPath1, scriptPath2);
Assert.IsFalse(lastCachedFilePath == null);

lastCachedFilePath = null;
engine.Compile(scriptPath1);
Assert.IsFalse(lastCachedFilePath == null);
}
}

public class MyDslEngine : DslEngine
{

}

public abstract class MyClassWithParams
{
public virtual string Hello(string input)
{
return input;
}
}

public class DslEngineWithParameters : DslEngine
{
protected override void CustomizeCompiler(BooCompiler compiler, CompilerPipeline pipeline, string[] urls)
{
var parameters = new ParameterDeclarationCollection();
var newParameterDeclaration =
new ParameterDeclaration("input", new SimpleTypeReference("System.String"));
parameters.Add(newParameterDeclaration);

pipeline.Insert(1, new ImplicitBaseClassCompilerStep(typeof(MyClassWithParams),
"Hello",
parameters,
"System"));
}
}
}
66 changes: 66 additions & 0 deletions Rhino.DSL/AbstractLockable.cs
@@ -0,0 +1,66 @@
namespace Rhino.DSL
{
using System.Threading;

///<summary>
/// Provide local read / writer copy semantics
///</summary>
public abstract class AbstractLockable
{
private readonly ReaderWriterLock readerWriterLock = new ReaderWriterLock();

/// <summary>
/// Execute the action under a write lock
/// </summary>
/// <param name="cacheAction">The cache action.</param>
public void WriteLock(CacheAction cacheAction)
{
if(readerWriterLock.IsWriterLockHeld)
{
cacheAction();
return;
}
bool readerLockHeld = readerWriterLock.IsReaderLockHeld;
LockCookie writerLock = new LockCookie();
if (readerLockHeld)
{
writerLock = readerWriterLock.UpgradeToWriterLock(Timeout.Infinite);
}
else
readerWriterLock.AcquireWriterLock(Timeout.Infinite);
try
{
cacheAction();
}
finally
{
if (readerLockHeld)
readerWriterLock.DowngradeFromWriterLock(ref writerLock);
else
readerWriterLock.ReleaseWriterLock();
}
}

/// <summary>
/// Execute the action under a read lock
/// </summary>
/// <param name="cacheAction">The cache action.</param>
public void ReadLock(CacheAction cacheAction)
{
if(readerWriterLock.IsReaderLockHeld)
{
cacheAction();
return;
}
readerWriterLock.AcquireReaderLock(Timeout.Infinite);
try
{
cacheAction();
}
finally
{
readerWriterLock.ReleaseReaderLock();
}
}
}
}

0 comments on commit 2c7b0cd

Please sign in to comment.