Sunday, April 11, 2010

A Distributed Hash Table (DHT) in F#: Using Higher Order Functions for the Service Operation Calls

In my last post, I provided a start to a distributed hash table in F# using WCF.  One of the major limitations of that example was that only two nodes could ever be on the node network at a given time.  Over the last week, I added the functionality to allow additional nodes to dynamically join the node network.  Among other things, this involved adding a few additional operations to the service.  These additions quickly showed that the original implementation of calls to the service was not maintainable (not to mention a serious violation of the Single Responsibility Principle (SRP)).  To resolve this, the channel factory and service operation calls have been split into separate modules.

At first, I had each service operation call in a separate function that was called from the RunCommand function.  I then realized that higher order functions would make this so much easier!  The final result is shown below:

ChordServerProxy.fs
module ChordServerProxy

open System
open System.ServiceModel
open System.Runtime.Serialization
open ChordCommon
open ChordServerFacade
open ChordContracts

type IChordServerProxy = interface   
    abstract CallServer : server:string -> operationContract:CommandType -> inputArguments:string[] -> obj option
end

type ChordServerProxy() = 
    interface IChordServerProxy with
        member this.CallServer server operationContract inputArguments =
            let binding = new NetTcpBinding()
            let service = new ChannelFactory<IChordServer>(binding, server)  
            try                    
                try
                    let proxy = service.CreateChannel()
                    RunCommand proxy operationContract inputArguments
                with
                | ex -> 
                    None
            finally
                match service.State with
                | serviceState when serviceState <> CommunicationState.Faulted -> 
                    try
                        service.Close |> ignore
                    with
                    | ex ->
                        service.Abort |> ignore
                | _ -> service.Abort |> ignore 
ChordServerFacade.fs
module ChordServerFacade

open System
open System.ServiceModel
open ChordContracts
open ChordCommon

let Execute command proxy inputArguments : obj option =
    match command proxy inputArguments with
    | null -> None
    | value -> Some(value)

let RunCommand proxy operationContract inputArguments : obj option =
    let command =
        match operationContract with
        | CommandType.Put -> fun (proxy:IChordServer) (inputArguments:string[]) -> 
                                (proxy.PutValueByKey inputArguments.[1] inputArguments.[2])
        | CommandType.Get -> fun (proxy:IChordServer) (inputArguments:string[]) -> 
                                (proxy.GetValueByKey inputArguments.[1])
        | CommandType.Join -> fun (proxy:IChordServer) (inputArguments:string[]) -> 
                                (proxy.RequestJoinChordNodeNetwork inputArguments.[0] :> obj)
        | CommandType.UpdateSuccessorNode -> 
                              fun (proxy:IChordServer) (inputArguments:string[]) -> 
                                (proxy.UpdateSuccessorNode inputArguments.[0] :> obj)
        | CommandType.GetSuccessorNode -> fun (proxy:IChordServer) (inputArguments:string[]) -> 
                                (proxy.GetSuccessorNode () :> obj)
    Execute command proxy inputArguments

As always, you can get the complete source code from http://github.com/dmohl/Polyphony.


No comments:

Post a Comment