packages feed

starling 0.0.2 → 0.1.0

raw patch · 4 files changed

+84/−12 lines, 4 filesdep +transformers

Dependencies added: transformers

Files

CHANGES view
@@ -1,3 +1,10 @@+0.1.0++ - Added increment/decrement commands+ - Added add and replace commands+ - Added 'update' operation which allows an atomic+   operation on a cached value+ 0.0.1   - Initial release
Network/Starling.hs view
@@ -39,14 +39,16 @@     , Key     , Value     , Result+    , ResultM     , ResponseStatus(..)     , set     , get     , delete-    -- , add-    -- , replace-    -- , increment-    -- , decrement+    , add+    , replace+    , update+    , increment+    , decrement     , flush     , stats     -- , oneStat -- doesn't seem to work for me@@ -71,13 +73,32 @@  import Data.ByteString.Lazy (ByteString) import qualified Data.ByteString.Lazy as BS+import qualified Data.Binary.Get as B -type Result a = IO (Either (ResponseStatus, ByteString) a)+import Data.Word +import Control.Monad.Trans (liftIO, MonadIO)++type Result a = ResultM IO a++-- | If an operation fails the result will return in 'Left'+-- with the failure code and a text description of the failure+type ResultM m a = m (Either (ResponseStatus, ByteString) a)+ -- | Set a value in the cache set :: Connection -> Key -> Value -> Result () set con key value = simpleRequest con (Core.set key value) (const ()) +-- | Set a vlue in the cache. Fails if a value is already defined+-- for the indicated key.+add :: Connection -> Key -> Value -> Result ()+add con key value = simpleRequest con (Core.add key value) (const ())++-- | Set a value in the cache. Fails if a value is not already defined+-- for the indicated key.+replace :: Connection -> Key -> Value -> Result ()+replace con key value = simpleRequest con (Core.replace key value) (const ())+ -- | Retrive a value from the cache get :: Connection -> Key -> Result ByteString get con key = simpleRequest con (Core.get key) rsBody@@ -86,6 +107,49 @@ delete :: Connection -> Key -> Result () delete con key = simpleRequest con (Core.delete key) (const ()) +-- | Update a value in the cache. This operation requires two round trips.+-- This operation can fail if the key is not present in the cache, or if+-- the value changes in the cache between the two calls.+-- So watch out! Even if the value exists the operation might+-- not go through in the face of concurrent access.+--+-- Testing indicates that if we fail because we could not gaurantee+-- atomicity the failure code will be 'KeyExists'.+update :: MonadIO m =>+          Connection -> Key -> (Value -> m (Maybe Value)) -> ResultM m ()+update con key f+    = do+  response <- liftIO $ synchRequest con (Core.get key)+  case rsStatus response of+    NoError -> do+        let oldVal = rsBody response+            cas = rsCas response+        res <- f oldVal+        let baseRequest = case res of+                            Nothing -> Core.delete key+                            Just newVal -> Core.replace key newVal+            request = addCAS cas $ baseRequest+        liftIO $ simpleRequest con request (const ())+    _ -> return . errorResult $ response++-- | Increment a value in the cache. The first 'Word64' argument is the+-- amount by which to increment and the second is the intial value to+-- use of the key does not yet have a value.+-- The return value is the updated value in the cache.+increment :: Connection -> Key -> Word64 -> Word64 -> Result Word64+increment con key amount init+    = simpleRequest con (Core.increment key amount init) $ \response ->+      B.runGet B.getWord64be (rsBody response)++-- | Decrement a value in the cache. The first 'Word64' argument is the+-- amount by which to decrement and the second is the intial value to+-- use of the key does not yet have a value.+-- The return value is the updated value in the cache.+decrement :: Connection -> Key -> Word64 -> Word64 -> Result Word64+decrement con key amount init+    = simpleRequest con (Core.decrement key amount init) $ \response ->+      B.runGet B.getWord64be (rsBody response)+ -- | Delete all entries in the cache flush :: Connection -> Result () flush con = simpleRequest con Core.flush (const ())@@ -111,8 +175,12 @@      if rsStatus resp == NoError       then return . Right . unpackStats $ resps       else return $ errorResult resp- where unpackStats = filter (\(x,y) -> not (BS.null x && BS.null y)) .-                     map (\response -> (rsKey response, rsBody response))++ where++   unpackStats+       = filter (\(x,y) -> not (BS.null x && BS.null y)) .+         map (\response -> (rsKey response, rsBody response))  -- | Returns a single stat. Example: 'stat con "pid"' will return -- the 
Network/Starling/Core.hs view
@@ -32,7 +32,6 @@     , Response(..)     , getResponse     , StarlingReadError(..)-    , StarlingReadError     , Serialize(..)     , Deserialize(..)     , Opaque@@ -54,8 +53,6 @@  import Data.ByteString.Lazy (ByteString) import qualified Data.ByteString.Lazy as BS--import Data.ByteString.Lazy.Char8()  import qualified Data.Binary.Builder as B import qualified Data.Binary.Get as B
starling.cabal view
@@ -1,5 +1,5 @@ name:            starling-version:         0.0.2+version:         0.1.0 stability:       Alpha  synopsis:        A memcached client@@ -20,7 +20,7 @@  cabal-version:   >= 1.6 -build-depends:   base==4.*, binary, bytestring+build-depends:   base == 4.*, binary, bytestring, transformers == 0.1.* build-type:      Simple  extra-source-files: CHANGES