Add simple load balancer.

Ilya V. Portnov [2010-04-23 06:42:48]
Add simple load balancer.
Filename
Network/YAML/Balancer.hs
Network/YAML/Caller.hs
Network/YAML/Server.hs
Test.hs
TestCall.hs
diff --git a/Network/YAML/Balancer.hs b/Network/YAML/Balancer.hs
new file mode 100644
index 0000000..86d4fd0
--- /dev/null
+++ b/Network/YAML/Balancer.hs
@@ -0,0 +1,16 @@
+
+module Network.YAML.Balancer where
+
+import System.Random
+import qualified Data.ByteString.Char8 as BS
+
+type Server = (BS.ByteString, Int)
+
+selectRandom :: [(BS.ByteString, Server, Int)] -> BS.ByteString -> IO Server
+selectRandom lst service = do
+  let lst' = concatMap (\(name,srv,p) -> replicate p (name, srv)) lst
+      lst'' = map snd $ filter (\(name,srv) -> name==service) lst'
+      n = length lst''
+  k <- randomRIO (0, n-1)
+  return $ lst'' !! k
+
diff --git a/Network/YAML/Caller.hs b/Network/YAML/Caller.hs
index 3f037c5..e21ba80 100644
--- a/Network/YAML/Caller.hs
+++ b/Network/YAML/Caller.hs
@@ -54,6 +54,7 @@ callF :: (IsYamlObject a, IsYamlObject b)
       -> IO ()
 callF getServer service name (args, var) = do
   srv <- getServer service
+--   putStrLn $ "Calling to " ++ show srv
   r <- call srv name args
   putMVar var r

diff --git a/Network/YAML/Server.hs b/Network/YAML/Server.hs
index 9a3f289..0907254 100644
--- a/Network/YAML/Server.hs
+++ b/Network/YAML/Server.hs
@@ -13,6 +13,17 @@ import Data.Object.Yaml
 import Network.YAML.Base
 import Network.YAML.Instances

+forkA :: [IO a] -> IO [a]
+forkA lst = do
+    let n = length lst
+    vars <- replicateM n newEmptyMVar
+    mapM (forkIO . run) $ zip lst vars
+    mapM takeMVar vars
+  where
+    run (x,v) = do
+      r <- x
+      putMVar v r
+
 readHandle :: Handle -> [BS.ByteString] -> IO [BS.ByteString]
 readHandle h acc = do
     line <- BS.hGetLine h
diff --git a/Test.hs b/Test.hs
index 4ce1668..1421dbd 100644
--- a/Test.hs
+++ b/Test.hs
@@ -3,10 +3,12 @@
 import Data.Object.Yaml
 import Data.Convertible.Base
 import qualified Data.Map as M
+import Control.Concurrent

 import Network.YAML.Dispatcher
 import Network.YAML.Base
 import Network.YAML.Instances
+import Network.YAML.Server (forkA)

 import TestTypes

@@ -21,5 +23,7 @@ rules = mkRules [("double", yamlMethod double),

 main = do
   putStrLn "Listening..."
-  dispatcher 5000 rules
+  forkA [dispatcher 5000 rules,
+         dispatcher 5001 rules,
+         dispatcher 5002 rules]
   return ()
diff --git a/TestCall.hs b/TestCall.hs
index 380243a..b21aeda 100644
--- a/TestCall.hs
+++ b/TestCall.hs
@@ -6,11 +6,15 @@ import Data.Convertible.Base
 import Network.YAML.Base
 import Network.YAML.Instances
 import Network.YAML.Caller
+import Network.YAML.Balancer

 import TestTypes

-getService "test" = return ("127.0.0.1", 5000)
-getService _ = fail "Unknown service"
+rules = [("test", ("127.0.0.1", 5000), 1),
+         ("test", ("127.0.0.1", 5001), 1),
+         ("test", ("127.0.0.1", 5002), 1)]
+
+getService = selectRandom rules

 p = Point 2.0 3.0
ViewGit