Skip to content

Commit

Permalink
Added a binary package as well
Browse files Browse the repository at this point in the history
  • Loading branch information
dennisdoomen committed May 27, 2018
1 parent 6f71321 commit 0a6c62e
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 46 deletions.
28 changes: 28 additions & 0 deletions Binaries.nuspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<package >
<metadata minClientVersion="3.3.0">
<id>FluidCaching</id>
<title>FluidCaching</title>
<version>1.2.1-supportpackagere0001</version>
<owners>Dennis Doomen</owners>
<authors>Dennis Doomen</authors>
<summary>
A multi-threaded high performance Least Recently Used cache with async/await support, compiled for .NET Standard 1.1.
</summary>
<description>
A multi-threaded high performance Least Recently Used cache with async/await support, compiled for .NET Standard 1.1.
Read https://www.continuousimprover.com/2016/02/a-least-recently-used-cache-that-you.html for some background information.
</description>
<language>en-US</language>
<licenseUrl>https://github.com/dennisdoomen/FluidCaching</licenseUrl>
<projectUrl>https://github.com/dennisdoomen/FluidCaching</projectUrl>
<tags>LRU Caching</tags>
<copyright>Copyright Dennis Doomen 2015-2018</copyright>
<releaseNotes>
See https://github.com/dennisdoomen/FluidCaching/releases
</releaseNotes>
</metadata>
<files>
<file src=".\Src\FluidCaching\bin\Release\netstandard1.1\*.*" exclude="**\*.json" target="lib\netstandard1.1" />
</files>
</package>
46 changes: 26 additions & 20 deletions Build/default.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ properties {
$RunTests = $false
}

task default -depends Clean, ExtractVersionsFromGit, ApplyPackageVersioning, RestoreNugetPackages, Compile, RunTests, BuildPackage, PublishToMyget
task default -depends Clean, ExtractVersionsFromGit, RestoreNugetPackages, Compile, RunTests, BuildPackage, PublishToMyget

task DetermineMsBuildPath -depends RestoreNugetPackages {
Write-Host "Adding msbuild to the environment path"
Expand Down Expand Up @@ -45,9 +45,7 @@ task ExtractVersionsFromGit {
if ($LASTEXITCODE -eq 0) {
$version = (ConvertFrom-Json ($json -join "`n"));

TeamCity-SetBuildNumber $version.FullSemVer;

$script:AssemblyVersion = $version.ClassicVersion;
$script:AssemblyVersion = $version.AssemblySemVer;
$script:InfoVersion = $version.InformationalVersion;
$script:NuGetVersion = $version.NuGetVersion;
}
Expand All @@ -56,32 +54,39 @@ task ExtractVersionsFromGit {
}
}

task ApplyPackageVersioning -depends ExtractVersionsFromGit {
TeamCity-Block "Updating package version to $script:NuGetVersion" {

$fullName = "$SrcDirectory\.nuspec"

Set-ItemProperty -Path $fullName -Name IsReadOnly -Value $false

$content = Get-Content $fullName
$content = $content -replace '<version>.+</version>', ('<version>' + "$script:NuGetVersion" + '</version>')
Set-Content -Path $fullName $content
}
}

task RestoreNugetPackages {

& $Nuget restore "$BaseDirectory\FluidCaching.sln"
& $Nuget install "$BaseDirectory\Build\packages.config" -OutputDirectory "$BaseDirectory\Packages" -ConfigFile "$BaseDirectory\NuGet.Config"
}

task Compile -depends DetermineMsBuildPath {
task Compile -depends DetermineMsBuildPath, ApplyAssemblyVersioning {
TeamCity-Block "Compiling" {

exec { msbuild /v:m /p:Platform="Any CPU" $SlnFile /p:Configuration=Release /p:SourceAnalysisTreatErrorsAsWarnings=false /t:Rebuild $logger}
}
}

task ApplyAssemblyVersioning -depends ExtractVersionsFromGit {
Get-ChildItem -Path "$SrcDirectory/FluidCaching" -Filter "AssemblyInfo.cs" -Recurse -Force | foreach-object {

$content = Get-Content $_.FullName

if ($script:AssemblyVersion) {
Write-Output "Updating " $_.FullName "with version" $script:AssemblyVersion
$content = $content -replace 'AssemblyVersion\("(.+)"\)', ('AssemblyVersion("' + $script:AssemblyVersion + '")')
$content = $content -replace 'AssemblyFileVersion\("(.+)"\)', ('AssemblyFileVersion("' + $script:AssemblyVersion + '")')
}

if ($script:InfoVersion) {
Write-Output "Updating " $_.FullName "with information version" $script:InfoVersion
$content = $content -replace 'AssemblyInformationalVersion\("(.+)"\)', ('AssemblyInformationalVersion("' + $script:InfoVersion + '")')
}

Set-Content -Path $_.FullName $content
}
}

task RunTests -depends Compile -Description "Running all unit tests." {
$xunitRunner = "$BaseDirectory\Packages\xunit.runner.console.2.2.0\tools\xunit.console.exe"

Expand All @@ -93,15 +98,16 @@ task RunTests -depends Compile -Description "Running all unit tests." {
}


task BuildPackage {
task BuildPackage -depends ExtractVersionsFromGit {
TeamCity-Block "Building NuGet Package" {
if (!(Test-Path "$ArtifactsDirectory\")) {
New-Item $ArtifactsDirectory -ItemType Directory
}

& "$ArtifactsDirectory\MergeCSharpFiles.exe" "$SrcDirectory\FluidCaching" *.cs "$ArtifactsDirectory\FluidCaching.cs"

& $Nuget pack "$SrcDirectory\.nuspec" -OutputDirectory "$ArtifactsDirectory\"
& $Nuget pack "$BaseDirectory\Sources.nuspec" -OutputDirectory "$ArtifactsDirectory\" -Version $script:NuGetVersion
& $Nuget pack "$BaseDirectory\Binaries.nuspec" -OutputDirectory "$ArtifactsDirectory\" -Version $script:NuGetVersion
}
}

Expand Down
3 changes: 2 additions & 1 deletion FluidCaching.sln
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleApp", "Samples\Examp
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionFolder", "SolutionFolder", "{1E887ABD-9AD9-4B80-957B-7F8D875E0003}"
ProjectSection(SolutionItems) = preProject
Src\.nuspec = Src\.nuspec
Binaries.nuspec = Binaries.nuspec
Sources.nuspec = Sources.nuspec
EndProjectSection
EndProject
Global
Expand Down
20 changes: 13 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
* The build status is [![Build status](https://ci.appveyor.com/api/projects/status/098rwks5ye15l00q?svg=true)](https://ci.appveyor.com/project/dennisdoomen/fluidcaching)
[![Build status](https://ci.appveyor.com/api/projects/status/098rwks5ye15l00q?svg=true)](https://ci.appveyor.com/project/dennisdoomen/fluidcaching)

## Fluid Caching

_A least recently used cache that you can use without worrying_
> A least recently used cache that you can use without worrying
## What's this?
At the beginning of this year, I reported on my endeavors to use RavenDB as a projection store for an event sourced system. One of the things I tried to speed up RavenDB's projection speed was to use the [Least Recently Used cache](http://www.codeproject.com/Articles/23396/A-High-Performance-Multi-Threaded-LRU-Cache) developed by [Brian Agnes](http://www.codeproject.com/script/Membership/View.aspx?mid=3034272) a couple of years ago. This cache gave us a nice speed increase, but the original author appears to be unreachable and seemingly abandoned the project. So I started looking for a way to distribute the code in a way that makes it painless to consume it in other projects. With this in mind, I decided to initiate a new open-source project Fluid Caching. As of August 10th, version 1.0.0 is officially available as a [source-only package on NuGet](https://www.nuget.org/packages/FluidCaching.Sources/1.0.0).
A while ago, I [ran a test](https://www.continuousimprover.com/2016/01/evaluating-ravendb-as-embedded-database.html) to use RavenDB as a projection store for an event sourced system. One of the things I tried to speed up RavenDB's projection speed was to use the [Least Recently Used cache](http://www.codeproject.com/Articles/23396/A-High-Performance-Multi-Threaded-LRU-Cache) developed by [Brian Agnes](http://www.codeproject.com/script/Membership/View.aspx?mid=3034272) a couple of years ago. This cache gave us a nice speed increase, but the original author appears to be unreachable and seemingly abandoned the project. So I started looking for a way to distribute the code in a way that makes it painless to consume it in other projects. With this in mind, I decided to initiate a new open-source project Fluid Caching.

The cache in itself did meet our requirements quite well. It supported putting a limit on its capacity. It allows you to specify the minimum amount of time objects must be kept in the cache (even if that would exceed the capacity), as well as a maximum amount of time. It's completely safe to use in multi-threaded scenarios and is using an algorithm that keeps the performance under control, regardless of the number of items in the cache. It also supports multiple indexes based on different keys on top of the same cache, and is pretty flexible in how you get keys from objects. All credits for the initial implementation go to Brian, and I welcome you to read his original article from 2009 on some of the design choices.

## What does it look like
## How do I use it?

Considering a User class, in its simplest form, you can use the cache like this:
Considering a `User` class, in its simplest form, you can use the cache like this:

```csharp
var cache = new FluidCache<User>(1000, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(10)), () => DateTime.Now);
Expand All @@ -29,8 +29,14 @@ The lambda you pass in will be used to extract the key from the User object. Not
User user = await indexById.GetItem("dennisd", id => Task.FromResult(new User { Id = id }));
```

## Why am I doing this
Good question. It's 2016, so some of the custom thread synchronization primitives are part of the .NET framework these days. Next to that, we all write asynchronous code and thus have a need for support for async/await. These days, being able to compile the code against any modern .NET version, even a Portable Class Library or .NET Core, isn't a luxury either. Other features I'm adding include thread-safe factory methods and some telemetry for tuning the cache to your needs. In terms of code distribution, my preferred method for a library like this would be a source-only NuGet package so that you don't have to bother the consumers of your packages with another dependency. Also, the code quality itself needs some [Object Calisthenics](http://www.continuousimprover.com/2015/10/9-simple-practices-for-writing-better.html) love as well as some sprinkles of my Coding Guidelines. And finally, you can't ship a library without at least a decent amount properly scoped unit tests and a [fully automated build pipeline](http://www.continuousimprover.com/2015/03/bringing-power-of-powershell-to-your.html).
## Where do I get it?
It's available in three different forms.
* A NuGet package called [FluidCaching.Sources](https://www.nuget.org/packages/FluidCaching.Sources/) that just adds the source code to your project without any binary dependencies. compatible with both projects using the `packages.config` as well as those that use the newer `<PackageReference>` technique.
* A NuGet package called [FluidCaching](https://www.nuget.org/packages/FluidCaching.Sources/) that adds a .NET Standard 1.1 binary dependency.
* A [single source file](https://github.com/dennisdoomen/FluidCaching/releases/latest) that you can directly add to your project.

## Another caching library!? Why?
Good question. It's 2016, so some of the custom thread synchronization primitives are part of the .NET framework these days. Next to that, we all write asynchronous code and thus have a need for support for async/await. These days, being able to compile the code against any modern .NET version, even a .NET Standard or .NET Core project, isn't a luxury either. Other features I'm adding include thread-safe factory methods and some telemetry for tuning the cache to your needs. In terms of code distribution, my preferred method for a library like this would be a source-only NuGet package so that you don't have to bother the consumers of your packages with another dependency. Also, the code quality itself needs some [Object Calisthenics](https://www.continuousimprover.com/2015/10/9-simple-practices-for-writing-better.html) love as well as some sprinkles of my [Coding Guidelines](http://csharpcodingguidelines.com). And finally, you can't ship a library without at least a decent amount of properly scoped unit tests and a [fully automated build pipeline](https://www.continuousimprover.com/2015/03/bringing-power-of-powershell-to-your.html).

## So how does it work
As I mentioned before, I highly recommend the original article if you want to understand some of the design decisions, but let me share some of the inner workings right now. The `FluidCache` class is the centerpiece of the solution. It's more of a factory for other objects than a cache per see. Instead, all items in the cache are owned by the `LifeSpanManager`. Its responsibility is to track when item has been 'touched' and use that to calculate when it is eligible for garbage collection while accounting for the provided minimum age.
Expand Down
10 changes: 1 addition & 9 deletions Src/FluidCaching/FluidCaching.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,7 @@
<AssemblyName>FluidCaching</AssemblyName>
<PackageId>FluidCaching</PackageId>
<NetStandardImplicitPackageVersion>1.6.0</NetStandardImplicitPackageVersion>
<GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
<GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
<GenerateNeutralResourcesLanguageAttribute>false</GenerateNeutralResourcesLanguageAttribute>
<GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DefineConstants>TRACE;DEBUG;NETSTANDARD1_1;PUBLIC_FLUID_CACHING</DefineConstants>
Expand Down
17 changes: 8 additions & 9 deletions Src/FluidCaching/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Resources;
using System.Resources;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
Expand All @@ -7,13 +7,12 @@
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("FluidCaching")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyDescription("A multi-threaded high performance Least Recently Used cache with async/await support, compiled for .NET Standard 1.1")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyCompany("Dennis Doomen")]
[assembly: AssemblyProduct("FluidCaching")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: AssemblyCopyright("Copyright 2015-2018")]
[assembly: AssemblyTrademark("Dennis Doomen")]
[assembly: NeutralResourcesLanguage("en")]

// Version information for an assembly consists of the following four values:
Expand All @@ -25,7 +24,7 @@
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyVersion("1.2.1.0")]
[assembly: AssemblyFileVersion("1.2.1.0")]
[assembly: AssemblyInformationalVersion("1.2.1-SupportPackageReference.1+1.Branch.SupportPackageReference.Sha.871cb81490c4d621eca2b535f300c58634c980b5")]
[assembly: InternalsVisibleTo("FluidCaching.Specs")]

0 comments on commit 0a6c62e

Please sign in to comment.