F# interactive, AppFabric cache and PowerShell (Part 2)

By Petr at July 15, 2010 03:51
Filed Under:

In previous post I wrote how to invoke AppFabric management PowerShell commands from F# interactive. Now we successfully created named cache in AppFabric distributed cache and I want to use AppFabric cache API to store and retrieve data from this cache. You can structure data stored in named cache using cache regions (which roughly correspond to tables in relational database). Data could be stored in the region using string keys which work as in usual hashtable.

But first of all you need to find out how to refer to AppFabric API assemblies in F# project. MSDN documentation tells the following: “On 64-bit operating systems, the AppFabric directory will not be directly visible. To work around this problem, replace the System32 directory name with the name SysNative. This results in navigating to the C:\Windows\SysNative\AppFabric directory in this step”. So I added a reference to these assemblies in my F# script file:

F#, using GeSHi 1.0.8.8
  1. #r @"C:\Windows\SysNative\AppFabric\Microsoft.ApplicationServer.Caching.Core.dll"
Parsed in 0.007 seconds at 11.99 KB/s

So far all looks OK, but when I selected this line and sent it to FSI window I’ve got this error message:

“error FS0084: Assembly reference 'C:\Windows\SysNative\AppFabric\Microsoft.ApplicationServer.Caching.Core.dll' was not found or is invalid”. I tried to search for this message but didn’t found any workaround. (It’s strange because this exact reference works perfectly when I added it to the project, but it still gives me an error in FSI window). To make it work in FSI I had to copy all needed AppFabric assemblies to the usual folder I created on my hard drive and refer to these copied assemblies from script file. It’s kind of ugly but it seems to work. So my references in script look like this:

F#, using GeSHi 1.0.8.8
  1. #r @"C:\Projects\Velocity4\Microsoft.ApplicationServer.Caching.Core.dll"
  2. #r @"C:\Projects\Velocity4\Microsoft.ApplicationServer.Caching.Client.dll"
  3. #r @"C:\Projects\Velocity4\Microsoft.ApplicationServer.Caching.Management.dll"
  4. #r @"C:\Projects\Velocity4\Microsoft.ApplicationServer.Caching.ManagementPS.dll"
  5. #r @"C:\Projects\Velocity4\Microsoft.ApplicationServer.Caching.Configuration.dll"

Now I could use cache API.First of all we need to create DataCacheFactory object and DataCache client. (By the way MSDN has pretty good documentation on Windows Server AppFabric Caching Concepts and Architecture)

F#, using GeSHi 1.0.8.8
  1. open System
  2. open Microsoft.ApplicationServer.Caching
  3. let createDataCacheFactory =
  4. let config = DataCacheFactoryConfiguration()
  5. config.LocalCacheProperties <- DataCacheLocalCacheProperties() // use local cache in the cache client
  6. config.Servers <- [DataCacheServerEndpoint(Environment.MachineName, 22233)]
  7. new DataCacheFactory(config)
  8. let createCacheClient cacheName =
  9. let factory = createDataCacheFactory
  10. cacheName |> factory.GetCache
Parsed in 0.016 seconds at 29.76 KB/s

Now we can use DataCache object to manipulate data in our cache (I will not describe or implement complete cache API here but rather illustrate main concepts):

F#, using GeSHi 1.0.8.8
  1. let putData (cache: DataCache) key value (region: string) =
  2. cache.Put(key, value, region)
  3. let getData (cache: DataCache) key (region: string) =
  4. cache.Get(key, region)
  5. let removeData (cache: DataCache) key (region: string) =
  6. cache.Remove(key, region)
  7. let createRegion (cache: DataCache) regionName =
  8. cache.CreateRegion regionName
  9. let removeRegion (cache: DataCache) regionName =
  10. cache.RemoveRegion regionName
Parsed in 0.016 seconds at 27.77 KB/s

 

So we can now create some simple test data and test our F# API wrapper:

F#, using GeSHi 1.0.8.8
  1. // Creating cache client for our named cache:
  2. let cacheClient = createCacheClient "MyCache"
  3. // Creating the region to store data
  4. createRegion cacheClient "TestRegion"
  5. // Creating simple test data
  6. let testData = seq {
  7. for i in 1 .. 10000 do
  8. yield (sprintf "key%d" i , sprintf "data%d" i) }
  9. // Populate our cache region
  10. testData |> Seq.iter (fun (fst, snd) -> putData cacheClient fst snd "TestRegion"|> ignore)
  11. // Retrieve and print all data:
  12. let getAllData =
  13. for i in 1 .. 10000 do
  14. let key = sprintf "key%i" i
  15. let d = getData cacheClient key "TestRegion"
  16. printfn "GotData: key:%s, value: %A" key d
  17. // We can play with different ways to get these data.
  18. open Microsoft.FSharp.Control;
  19. let getAllDataMap testData =
  20. testData |> Seq.map (fun (fst, _) -> getData cacheClient fst "TestRegion" )
  21. let getAllDataParallel testData =
  22. testData |> Seq.map (fun (fst, _) -> async { return getData cacheClient fst "TestRegion" })
  23. |> Async.Parallel
  24. |> Async.RunSynchronously
  25. // And remove them from cache finally:
  26. for i in 1 .. 10000 do
  27. let key = sprintf "key%i" i
  28. removeData cacheClient key "TestRegion" |> ignore
Parsed in 0.028 seconds at 41.63 KB/s

 

So now we can use PowerShell AppFabric management commands from F# and use cache API to put and get simple data. Next time I’m going to play with more advanced cache API (notifications etc.) and real database data.

F# interactive, AppFabric cache and PowerShell (Part 1)

By Petr at July 14, 2010 03:29
Filed Under:

Usually you can improve performance and scalability of distributed application using in-memory cache data. Windows Server AppFabric recently released by Microsoft includes distributed cache module formerly known under codename “Velocity”. It is a distributed in-memory application cache platform for developing scalable, available, and high-performance applications. AppFabric fuses memory across multiple computers to give a single unified cache view to applications. Applications can store any serializable CLR object without worrying about where the object gets stored. Scalability can be achieved by simply adding more computers on demand. The cache also allows for copies of data to be stored across the cluster, thus protecting data against failures. It runs as a service accessed over the network.

Installation and configuration went very smoothly, Microsoft documentation on setup and configuration is quite good.

I set up AppFabric on my laptop running 64-bit version of Windows 7 without any problems.

I planned to play with Cache API using F# interactive – a great tool available in Visual Studio 2010 allowing quickly prototype and test F# code.

Data stored in AppFabric cache are partitioned using named memory caches which could be created by PowerShell commands – PowerShell is the main tool for AppFabric administration tasks. Strangely enough PowerShell command is the only way to create new named cache on the server (there is no .NET API for this purpose) so I had to learn how to call PowerShell commands from F#. After some googling I found the great blog post by Stephen Kaufman “Calling PowerShell from .NET” which had exactly what I needed but he used C#. Both C# and F# are .NET languages so it shouldn’t be very hard to translate code from one to another. So I created a couple of functions to call PowerShell commands from F# and tried them in F# interactive.

 

F#, using GeSHi 1.0.8.8
  1. // We need to refer PowerShell API assembly
  2. #r @"C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0\System.Management.Automation.dll"
  3. open System.Management.Automation
  4. open System.Management.Automation.Runspaces
  5. let invokePsCacheCommand cmdName (parNameVal: (string * obj) list) =
  6. let state = InitialSessionState.CreateDefault()
  7. // Import PowerShell AppFabric modules
  8. [|"DistributedCacheAdministration"; "DistributedCacheConfiguration"|] |> state.ImportPSModule
  9. state.ThrowOnRunspaceOpenError <- true
  10. let rs = RunspaceFactory.CreateRunspace(state)
  11. rs.Open()
  12. // Create PowerShell command pipeline
  13. let pipe = rs.CreatePipeline()
  14. pipe.Commands.Add(Command("Use-CacheCluster"))
  15. let cmd = new Command(cmdName)
  16. // Add command parameters as name-value pairs
  17. parNameVal |> List.iter (fun (name, value) -> cmd.Parameters.Add(CommandParameter(name, value)))
  18. pipe.Commands.Add(cmd)
  19. // And invoke commands
  20. pipe.Invoke()
  21. let createCache cacheName =
  22. [("Name", cacheName);
  23. ("Expirable", box false)] |> invokePsCacheCommand "New-Cache"
  24. let removeCache cacheName =
  25. [("Name", cacheName)] |> invokePsCacheCommand "Remove-Cache"
  26. let exportCacheConfig fileName =
  27. [("File", fileName)] |> invokePsCacheCommand "Export-CacheClusterConfig"
Parsed in 0.026 seconds at 51.22 KB/s

 

Now I can try to create my first named cache from F# interactive:

 

createCache "MyCache"

 

I selected this string and hit Alt-Enter to execute it in F# Interactive window and immediately got a cryptic message: “The specified module 'DistributedCacheAdministration' was not loaded because no valid module file was found in any module directory.” After a short internet search I found this post by Ron Jacobs. It seems that I’ve got this error because I’m using 64-bit version of AppFabric but VisualStudio runs Fsi.exe as 32-bit process. Am I out of lack and cannot use F# interactive to run PowerShell commands? No. It seems that in quickly expanding F# community one can find the answer to almost any problem:) Here it is: “Making the FSharp interpreter (fsi) run in 64bit!” I made all woodoo magic procedures described in this article and finally got sweet picture in power shell command window:

 

FsiCache

 

In the next part I’ll describe how to use cache API to store and retrieve data using F#.