Commits

Bryan O'Sullivan committed fa2df44

MOAR DOX.

  • Participants
  • Parent commits e127309

Comments (0)

Files changed (14)

 synopsis:            Haskell Client for Riak
 description:
   A Haskell client library for the Riak decentralized data
-  store.
+  store, designed for efficiency, ease of use, and flexibility.  Uses
+  the Riak protocol buffers API for speed.
+  .
+  This library is organized to allow a tradeoff between power
+  and ease of use.  If you would like a different degree of
+  automation with storage and conflict resolution, you may want to
+  use one of the following modules (ranked from easiest to most
+  tricky to use):
+  .
+  [Network.Riak] JSON for storage, automatic conflict resolution.
+  This is the easiest module to work with.
+  .
+  [Network.Riak.JSON] JSON for storage, manual conflict resolution.
+  .
+  [Network.Riak.Value.Monoid] More complex (but still automatic)
+  storage, automatic conflict resolution.
+  .
+  [Network.Riak.Value] More complex (but still automatic) storage,
+  manual conflict resolution.
+  .
+  [Network.Riak.Basic] manual storage, manual conflict resolution.
+  This is the most demanding module to work with, as you must encode
+  and decode data yourself, and handle all conflict resolution
+  yourself.
+
 homepage:            http://github.com/mailrank/riak-haskell-client
 license:             OtherLicense
 license-file:        LICENSE
     Network.Riak.Value.Monoid
     Network.Riak.Protocol.ServerInfo
     Network.Riak.Protocol.BucketProps
-    Network.Riak.Protocol.Content
     Network.Riak.Protocol.DeleteRequest
     Network.Riak.Protocol.ErrorResponse
     Network.Riak.Protocol.GetBucketRequest
     Network.Riak.Protocol.GetClientIDResponse
     Network.Riak.Protocol.GetRequest
     Network.Riak.Protocol.GetResponse
-    Network.Riak.Protocol.Link
     Network.Riak.Protocol.ListBucketsResponse
     Network.Riak.Protocol.ListKeysRequest
     Network.Riak.Protocol.ListKeysResponse
 
   other-modules:       
     Network.Riak.Monoid
+    Network.Riak.Protocol.Link
     Network.Riak.Connection.Internal
+    Network.Riak.Protocol.Content
     Network.Riak.Tag
     Network.Riak.Types.Internal
     Network.Riak.Protocol
   if flag(developer)
     ghc-options: -Werror
     ghc-prof-options: -auto-all
-    cpp-options: -DASSERTS
+    cpp-options: -DASSERTS -DDEBUG
 
   ghc-options: -Wall -fno-warn-orphans
 

File src/Network/Riak.hs

+-- |
+-- Module:      Network.Riak
+-- Copyright:   (c) 2011 MailRank, Inc.
+-- License:     Apache
+-- Maintainer:  Bryan O'Sullivan <bos@mailrank.com>
+-- Stability:   experimental
+-- Portability: portable
+--
+-- A client for the Riak decentralized data store.
+--
+-- The functions in this module use JSON as the storage
+-- representation, and automatically perform conflict resolution
+-- during storage and retrieval.
+--
+-- This library is organized to allow a tradeoff between power
+-- and ease of use.  If you would like a different degree of
+-- automation with storage and conflict resolution, you may want to
+-- use one of the following modules (ranked from easiest to most
+-- tricky to use):
+--
+-- [Network.Riak.JSON.Monoid] JSON for storage, automatic conflict
+-- resolution.  (This module actually re-exports its definitions.)
+-- This is the easiest module to work with.
+--
+-- [Network.Riak.JSON] JSON for storage, manual conflict resolution.
+--
+-- [Network.Riak.Value.Monoid] More complex (but still automatic)
+-- storage, automatic conflict resolution.
+--
+-- [Network.Riak.Value] More complex (but still automatic) storage,
+-- manual conflict resolution.
+--
+-- [Network.Riak.Basic] manual storage, manual conflict resolution.
+-- This is the most demanding module to work with, as you must encode
+-- and decode data yourself, and handle all conflict resolution
+-- yourself.
+
 module Network.Riak
     (
     -- * Client configuration and identification

File src/Network/Riak/Basic.hs

 {-# LANGUAGE OverloadedStrings, RecordWildCards #-}
 
+-- |
+-- Module:      Network.Riak.Basic
+-- Copyright:   (c) 2011 MailRank, Inc.
+-- License:     Apache
+-- Maintainer:  Bryan O'Sullivan <bos@mailrank.com>
+-- Stability:   experimental
+-- Portability: portable
+--
+-- Basic support for the Riak decentralized data store.
+--
+-- When storing and retrieving data, the functions in this module do
+-- not perform any encoding or decoding of data, nor do they resolve
+-- conflicts.
+
 module Network.Riak.Basic
     (
     -- * Client configuration and identification
 import qualified Network.Riak.Response as Resp
 import qualified Network.Riak.Types.Internal as T
 
+-- | Check to see if the connection to the server is alive.
 ping :: Connection -> IO ()
 ping conn = exchange_ conn Req.ping
 
+-- | Find out from the server what client ID this connection is using.
 getClientID :: Connection -> IO ClientID
 getClientID conn = Resp.getClientID <$> exchange conn Req.getClientID
 
+-- | Retrieve information about the server.
 getServerInfo :: Connection -> IO ServerInfo
 getServerInfo conn = exchange conn Req.getServerInfo
 
+-- | Retrieve up a value.  This may return multiple conflicting
+-- siblings.  Choosing among them is your responsibility.
 get :: Connection -> T.Bucket -> T.Key -> R
     -> IO (Maybe (Seq.Seq Content, VClock))
 get conn bucket key r = Resp.get <$> exchangeMaybe conn (Req.get bucket key r)
 
+-- | Store a single value.  This may return multiple conflicting
+-- siblings.  Choosing among them, and storing a new value, is your
+-- responsibility.
 put :: Connection -> T.Bucket -> T.Key -> Maybe T.VClock
     -> Content -> W -> DW
     -> IO (Seq.Seq Content, VClock)
 put conn bucket key mvclock cont w dw =
   Resp.put <$> exchange conn (Req.put bucket key mvclock cont w dw True)
 
+-- | Store a single value, without the possibility of conflict
+-- resolution.
 put_ :: Connection -> T.Bucket -> T.Key -> Maybe T.VClock
      -> Content -> W -> DW
      -> IO ()
 put_ conn bucket key mvclock cont w dw =
   exchange_ conn (Req.put bucket key mvclock cont w dw False)
 
+-- | Delete a value.
 delete :: Connection -> T.Bucket -> T.Key -> RW -> IO ()
 delete conn bucket key rw = exchange_ conn $ Req.delete bucket key rw
 
+-- List the buckets in the cluster.
+--
+-- /Note/: this operation is expensive.  Do not use it in production.
 listBuckets :: Connection -> IO (Seq.Seq T.Bucket)
 listBuckets conn = Resp.listBuckets <$> exchange conn Req.listBuckets
 
+-- Fold over the buckets in the cluster.
+--
+-- /Note/: this operation is expensive.  Do not use it in production.
 foldKeys :: Connection -> T.Bucket -> (a -> Key -> IO a) -> a -> IO a
 foldKeys conn bucket f z0 = do
   sendRequest conn $ Req.listKeys bucket
           else loop z1
   loop z0
 
+-- | Retrieve the properties of a bucket.
 getBucket :: Connection -> T.Bucket -> IO BucketProps
 getBucket conn bucket = Resp.getBucket <$> exchange conn (Req.getBucket bucket)
 
+-- | Store new properties for a bucket.
 setBucket :: Connection -> T.Bucket -> BucketProps -> IO ()
 setBucket conn bucket props = exchange_ conn $ Req.setBucket bucket props
 
+-- | Launch a 'MapReduce' job.
 mapReduce :: Connection -> Job -> IO MapReduce
 mapReduce conn = exchange conn . Req.mapReduce

File src/Network/Riak/Connection.hs

+-- |
+-- Module:      Network.Riak.Connection
+-- Copyright:   (c) 2011 MailRank, Inc.
+-- License:     Apache
+-- Maintainer:  Bryan O'Sullivan <bos@mailrank.com>
+-- Stability:   experimental
+-- Portability: portable
+--
+-- Low-level network connection management.
+
 module Network.Riak.Connection
     (
     -- * Connection management

File src/Network/Riak/Connection/Internal.hs

 {-# LANGUAGE CPP, OverloadedStrings, RecordWildCards, ScopedTypeVariables #-}
 
+-- |
+-- Module:      Network.Riak.Connection.Internal
+-- Copyright:   (c) 2011 MailRank, Inc.
+-- License:     Apache
+-- Maintainer:  Bryan O'Sullivan <bos@mailrank.com>
+-- Stability:   experimental
+-- Portability: portable
+--
+-- Low-level network connection management.
+
 module Network.Riak.Connection.Internal
     (
     -- * Connection management
 import qualified Network.Socket.ByteString as B
 import qualified Network.Socket.ByteString.Lazy as L
 
+-- | Default client configuration.  Talks to localhost, port 8087,
+-- with a randomly chosen client ID.
 defaultClient :: Client
 defaultClient = Client {
                   host = "127.0.0.1"
     return client { clientID = i }
   | otherwise = return client
 
+-- | Connect to a server.
 connect :: Client -> IO Connection
 connect cli0 = do
   client@Client{..} <- addClientID cli0
     setClientID conn clientID
     return conn
 
+-- | Disconnect from a server.
 disconnect :: Connection -> IO ()
 disconnect Connection{..} = onIOException "disconnect" $ do
   debug "disconnect" $ "server " ++ host connClient ++ ":" ++ port connClient ++
         moduleError "getResponse" $ "received unexpected response: expected " ++
                                     show expected ++ ", received " ++ show tag
 
+-- | Send a request to the server, and receive its response.
 exchange :: Exchange req resp => Connection -> req -> IO resp
 exchange conn@Connection{..} req = do
   debug "exchange" $ ">>> " ++ showM req
     sendRequest conn req
     recvResponse conn
 
+-- | Send a request to the server, and receive its response (which may
+-- be empty).
 exchangeMaybe :: Exchange req resp => Connection -> req -> IO (Maybe resp)
 exchangeMaybe conn@Connection{..} req = do
   debug "exchangeMaybe" $ ">>> " ++ showM req
     sendRequest conn req
     recvMaybeResponse conn
 
+-- | Send a request to the server, and receive its response, but do
+-- not decode it.
 exchange_ :: Request req => Connection -> req -> IO ()
 exchange_ conn req = do
   debug "exchange_" $ ">>> " ++ showM req
     L.sendAll connSock . runPut . mapM_ putRequest $ reqs
   replicateM numReqs $ readChan ch
 
+-- | Send a series of requests to the server, back to back, and
+-- receive a response for each request sent.  The sending and
+-- receiving will be overlapped if possible, to improve concurrency
+-- and reduce latency.
 pipeline :: (Exchange req resp) => Connection -> [req] -> IO [resp]
 pipeline = pipe recvResponse
 
+-- | Send a series of requests to the server, back to back, and
+-- receive a response for each request sent (the responses may be
+-- empty).  The sending and receiving will be overlapped if possible,
+-- to improve concurrency and reduce latency.
 pipelineMaybe :: (Exchange req resp) => Connection -> [req] -> IO [Maybe resp]
 pipelineMaybe = pipe recvMaybeResponse
 
+-- | Send a series of requests to the server, back to back, and
+-- receive (but do not decode) a response for each request sent.  The
+-- sending and receiving will be overlapped if possible, to improve
+-- concurrency and reduce latency.
 pipeline_ :: (Request req) => Connection -> [req] -> IO ()
 pipeline_ conn@Connection{..} reqs = do
   done <- newEmptyMVar

File src/Network/Riak/Content.hs

 {-# LANGUAGE OverloadedStrings #-}
 
+-- |
+-- Module:      Network.Riak.Content
+-- Copyright:   (c) 2011 MailRank, Inc.
+-- License:     Apache
+-- Maintainer:  Bryan O'Sullivan <bos@mailrank.com>
+-- Stability:   experimental
+-- Portability: portable
+--
+-- Low-level content and link types and functions.
+
 module Network.Riak.Content
     (
+    -- * Types
       Content(..)
     , Link.Link(..)
+    -- * Functions
     , empty
     , binary
     , json
     , link
     ) where
 
+import Data.Aeson.Encode (encode)
+import Data.Aeson.Types (ToJSON)
+import Network.Riak.Protocol.Content (Content(..))
+import Network.Riak.Types.Internal (Bucket, Key, Tag)
 import qualified Data.ByteString.Lazy.Char8 as L
 import qualified Data.Sequence as Seq
-import Network.Riak.Protocol.Content (Content(..))
 import qualified Network.Riak.Protocol.Link as Link
-import Network.Riak.Types.Internal
-import Data.Aeson.Encode
-import Data.Aeson.Types
 
+-- | Create a link.
 link :: Bucket -> Key -> Tag -> Link.Link
 link bucket key tag = Link.Link (Just bucket) (Just key) (Just tag)
 {-# INLINE link #-}
 
+-- | An empty piece of content.
 empty :: Content
 empty = Content { value = L.empty
                 , content_type = Nothing
                 , usermeta = Seq.empty
                 }
 
+-- | Content encoded as @application/octet-stream@.
 binary :: L.ByteString -> Content
 binary bs = empty { value = bs
                   , content_type = Just "application/octet-stream"
                   }
 
+-- | Content encoded as @application/json@.
 json :: ToJSON a => a -> Content
 json j = empty { value = encode j
                , content_type = Just "application/json"

File src/Network/Riak/Debug.hs

 {-# LANGUAGE CPP, ScopedTypeVariables #-}
 
+-- |
+-- Module:      Network.Riak.Debug
+-- Copyright:   (c) 2011 MailRank, Inc.
+-- License:     Apache
+-- Maintainer:  Bryan O'Sullivan <bos@mailrank.com>
+-- Stability:   experimental
+-- Portability: portable
+--
+-- Support for debug logging.  The code in this package only works if
+-- the package was built with the @-fdebug@ flag.  Otherwise, they are
+-- all no-ops.
+
 module Network.Riak.Debug
     (
       level
 import System.IO (Handle, hPutStrLn, stderr)
 import System.IO.Unsafe (unsafePerformIO)
 
+-- | The current debugging level.  This is established once by reading
+-- the @RIAK_DEBUG@ environment variable.
 level :: Int
 #ifdef DEBUG
 level = unsafePerformIO $ do
 {-# NOINLINE handle #-}
 #endif
 
+-- | Set the 'Handle' to log to ('stderr' is the default).
 setHandle :: Handle -> IO ()
 #ifdef DEBUG
 setHandle = writeIORef handle
 {-# INLINE debug #-}
 #endif
 
+-- | Show a 'Tagged' value.  Show the entire value if the debug level
+-- is above 1, just the tag otherwise.
 showM :: (Show a, Tagged a) => a -> String
 showM m | level > 1 = show m
         | otherwise = show (messageTag m)

File src/Network/Riak/JSON.hs

 {-# LANGUAGE DeriveDataTypeable, GeneralizedNewtypeDeriving #-}
 
+-- |
+-- Module:      Network.Riak.JSON
+-- Copyright:   (c) 2011 MailRank, Inc.
+-- License:     Apache
+-- Maintainer:  Bryan O'Sullivan <bos@mailrank.com>
+-- Stability:   experimental
+-- Portability: portable
+--
+-- This module allows storage and retrieval of JSON-encoded data.
+--
+-- The functions in this module do not perform any conflict resolution.
+
 module Network.Riak.JSON
     (
       JSON

File src/Network/Riak/JSON/Monoid.hs

+-- |
+-- Module:      Network.Riak.JSON.Monoid
+-- Copyright:   (c) 2011 MailRank, Inc.
+-- License:     Apache
+-- Maintainer:  Bryan O'Sullivan <bos@mailrank.com>
+-- Stability:   experimental
+-- Portability: portable
+--
+-- This module allows storage and retrieval of JSON-encoded data.
+--
+-- Functions automatically resolve conflicts using 'Monoid' instances.
+-- For instance, if a 'get' returns three siblings, a winner will be
+-- chosen using 'mconcat'.  If a 'put' results in a conflict, a winner
+-- will be chosen using 'mconcat', and the winner will be 'put'; this
+-- will be repeated until no conflict occurs.
+
 module Network.Riak.JSON.Monoid
     (
       get
 {-# INLINE get #-}
 
 -- | Retrieve multiple values.  If conflicting values are returned for
--- a value, the 'Monoid' is used to choose a winner.
+-- a key, the 'Monoid' is used to choose a winner.
 getMany :: (FromJSON c, ToJSON c, Monoid c)
            => Connection -> Bucket -> [Key] -> R -> IO [Maybe (c, VClock)]
 getMany = M.getMany J.getMany
 {-# INLINE getMany #-}
 
--- | Store a single value.  This function does not return until any
--- vector clock conflicts are resolved.
+-- | Store a single value, automatically resolving any vector clock
+-- conflicts that arise.  A single invocation of this function may
+-- involve several roundtrips to the server to resolve conflicts.
+--
+-- If a conflict arises, a winner will be chosen using 'mconcat', and
+-- the winner will be stored; this will be repeated until no conflict
+-- occurs.
+--
+-- The final value to be stored at the end of any conflict resolution
+-- is returned.
 put :: (FromJSON c, ToJSON c, Monoid c) =>
        Connection -> Bucket -> Key -> Maybe VClock -> c -> W -> DW
     -> IO (c, VClock)
 put = M.put J.put
 {-# INLINE put #-}
 
--- | Store multiple values.  This function does not return until any
--- vector clock conflicts are resolved.
+-- | Store multiple values, resolving any vector clock conflicts that
+-- arise.  A single invocation of this function may involve several
+-- roundtrips to the server to resolve conflicts.
+--
+-- If any conflicts arise, a winner will be chosen in each case using
+-- 'mconcat', and the winners will be stored; this will be repeated
+-- until no conflicts occur.
+--
+-- For each original value to be stored, the final value that was
+-- stored at the end of any conflict resolution is returned.
 putMany :: (FromJSON c, ToJSON c, Monoid c) =>
            Connection -> Bucket -> [(Key, Maybe VClock, c)] -> W -> DW
         -> IO [(c, VClock)]

File src/Network/Riak/Tag.hs

 {-# LANGUAGE MultiParamTypeClasses #-}
 
+-- |
+-- Module:      Network.Riak.Content
+-- Copyright:   (c) 2011 MailRank, Inc.
+-- License:     Apache
+-- Maintainer:  Bryan O'Sullivan <bos@mailrank.com>
+-- Stability:   experimental
+-- Portability: portable
+--
+-- im in ur msg system taggin ur msg types
+
 module Network.Riak.Tag
     (
       putTag

File src/Network/Riak/Types.hs

+-- |
+-- Module:      Network.Riak.Types
+-- Copyright:   (c) 2011 MailRank, Inc.
+-- License:     Apache
+-- Maintainer:  Bryan O'Sullivan <bos@mailrank.com>
+-- Stability:   experimental
+-- Portability: portable
+--
+-- Basic types.
+
 module Network.Riak.Types
     (
     -- * Client management

File src/Network/Riak/Types/Internal.hs

 {-# LANGUAGE DeriveDataTypeable, FunctionalDependencies, MultiParamTypeClasses,
     RecordWildCards #-}
 
+-- |
+-- Module:      Network.Riak.Types.Internal
+-- Copyright:   (c) 2011 MailRank, Inc.
+-- License:     Apache
+-- Maintainer:  Bryan O'Sullivan <bos@mailrank.com>
+-- Stability:   experimental
+-- Portability: portable
+--
+-- Basic types.
+
 module Network.Riak.Types.Internal
     (
     -- * Client management
                 | MapReduceResponse
                   deriving (Eq, Show, Enum, Typeable)
 
--- | All messages are tagged.
+-- | Messages are tagged.
 class Tagged msg where
-    messageTag :: msg -> MessageTag
+    messageTag :: msg -> MessageTag -- ^ Retrieve a message's tag.
 
 instance Tagged MessageTag where
     messageTag m = m
 -- to a read or write request before it is considered successful. This
 -- is defined as a bucket property or as one of the relevant
 -- parameters to a single request ('R','W','DW','RW').
-data Quorum = Default   -- ^ Use the default settings for the bucket.
+data Quorum = Default   -- ^ Use the default quorum settings for the bucket.
             | One       -- ^ Success after one server has responded.
-            | Quorum    -- ^ Success after a quorum of servers have responded.
+            | Quorum    -- ^ Success after a quorum of servers has responded.
             | All       -- ^ Success after all servers have responded.
               deriving (Bounded, Eq, Enum, Ord, Show, Typeable)
 

File src/Network/Riak/Value.hs

 {-# LANGUAGE OverloadedStrings, RecordWildCards #-}
 
+-- |
+-- Module:      Network.Riak.Value
+-- Copyright:   (c) 2011 MailRank, Inc.
+-- License:     Apache
+-- Maintainer:  Bryan O'Sullivan <bos@mailrank.com>
+-- Stability:   experimental
+-- Portability: portable
+--
+-- This module allows storage and retrieval of data using the
+-- 'IsContent' typeclass.  This provides access to more of Riak's
+-- storage features than JSON, e.g. links.
+--
+-- The functions in this module do not perform any conflict resolution.
+
 module Network.Riak.Value
     (
       IsContent(..)

File src/Network/Riak/Value/Monoid.hs

+-- |
+-- Module:      Network.Riak.Value.Monoid
+-- Copyright:   (c) 2011 MailRank, Inc.
+-- License:     Apache
+-- Maintainer:  Bryan O'Sullivan <bos@mailrank.com>
+-- Stability:   experimental
+-- Portability: portable
+--
+-- This module allows storage and retrieval of data encoded using the
+-- 'V.IsContent' typeclass.  This provides access to more of Riak's
+-- storage features than JSON, e.g. links.
+--
+-- Functions automatically resolve conflicts using 'Monoid' instances.
+-- For instance, if a 'get' returns three siblings, a winner will be
+-- chosen using 'mconcat'.  If a 'put' results in a conflict, a winner
+-- will be chosen using 'mconcat', and the winner will be 'put'; this
+-- will be repeated until no conflict occurs.
+
 module Network.Riak.Value.Monoid
     (
       V.IsContent(..)
 import qualified Network.Riak.Monoid as M
 import qualified Network.Riak.Value as V
 
+-- | Retrieve a single value.  If conflicting values are returned, the
+-- 'Monoid' is used to choose a winner.
 get :: (Monoid c, V.IsContent c) =>
        Connection -> Bucket -> Key -> R -> IO (Maybe (c, VClock))
 get = M.get V.get
 {-# INLINE get #-}
 
+-- | Retrieve multiple values.  If conflicting values are returned for
+-- a key, the 'Monoid' is used to choose a winner.
 getMany :: (Monoid c, V.IsContent c) => Connection -> Bucket -> [Key] -> R
         -> IO [Maybe (c, VClock)]
 getMany = M.getMany V.getMany
 {-# INLINE getMany #-}
 
+-- | Store a single value, automatically resolving any vector clock
+-- conflicts that arise.  A single invocation of this function may
+-- involve several roundtrips to the server to resolve conflicts.
+--
+-- If a conflict arises, a winner will be chosen using 'mconcat', and
+-- the winner will be stored; this will be repeated until no conflict
+-- occurs.
+--
+-- The final value to be stored at the end of any conflict resolution
+-- is returned.
 put :: (Monoid c, V.IsContent c) =>
        Connection -> Bucket -> Key -> Maybe VClock -> c -> W -> DW
     -> IO (c, VClock)
 put = M.put V.put 
 {-# INLINE put #-}
 
+-- | Store multiple values, resolving any vector clock conflicts that
+-- arise.  A single invocation of this function may involve several
+-- roundtrips to the server to resolve conflicts.
+--
+-- If any conflicts arise, a winner will be chosen in each case using
+-- 'mconcat', and the winners will be stored; this will be repeated
+-- until no conflicts occur.
+--
+-- For each original value to be stored, the final value that was
+-- stored at the end of any conflict resolution is returned.
 putMany :: (Monoid c, V.IsContent c) =>
            Connection -> Bucket -> [(Key, Maybe VClock, c)] -> W -> DW
         -> IO [(c, VClock)]