starling 0.0.2 → 0.1.0
raw patch · 4 files changed
+84/−12 lines, 4 filesdep +transformers
Dependencies added: transformers
Files
- CHANGES +7/−0
- Network/Starling.hs +75/−7
- Network/Starling/Core.hs +0/−3
- starling.cabal +2/−2
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