Revision 71dc39a1

b/src/Ganeti/Locking/Allocation.hs
38 38
  , opportunisticLockUnion
39 39
  ) where
40 40

  
41
import Control.Applicative (liftA2)
41 42
import Control.Arrow (second, (***))
42 43
import Control.Monad
43 44
import Data.Foldable (for_, find)
......
45 46
import qualified Data.Map as M
46 47
import Data.Maybe (fromMaybe)
47 48
import qualified Data.Set as S
49
import qualified Text.JSON as J
48 50

  
49 51
import Ganeti.BasicTypes
52
import Ganeti.JSON (toArray)
50 53
import Ganeti.Locking.Types
51 54

  
52 55
{-
......
315 318
                                       s
316 319
        in (s', if result == Ok S.empty then lock:success else success)
317 320
  in second S.fromList $ foldl maybeAllocate (state, []) reqs'
321

  
322
{-| Serializaiton of Lock Allocations
323

  
324
To serialize a lock allocation, we only remember which owner holds
325
which locks at which level (shared or exclusive). From this information,
326
everything else can be reconstructed, simply using updateLocks.
327
-}
328

  
329
instance J.JSON OwnerState where
330
  showJSON OwnShared = J.showJSON "shared"
331
  showJSON OwnExclusive = J.showJSON "exclusive"
332
  readJSON (J.JSString x) = let s = J.fromJSString x
333
                            in case s of
334
                              "shared" -> J.Ok OwnShared
335
                              "exclusive" -> J.Ok OwnExclusive
336
                              _ -> J.Error $ "Unknown owner type " ++ s
337
  readJSON _ = J.Error "Owner type not encoded as a string"
338

  
339
-- | Read a lock-ownerstate pair from JSON.
340
readLockOwnerstate :: (J.JSON a) => J.JSValue -> J.Result (a, OwnerState)
341
readLockOwnerstate (J.JSArray [x, y]) = liftA2 (,) (J.readJSON x) (J.readJSON y)
342
readLockOwnerstate x = fail $ "lock-ownerstate pairs are encoded as arrays"
343
                              ++ " of length 2, but found " ++ show x
344

  
345
-- | Read an owner-lock pair from JSON.
346
readOwnerLock :: (J.JSON a, J.JSON b)
347
              => J.JSValue -> J.Result (b, [(a, OwnerState)])
348
readOwnerLock (J.JSArray [x, J.JSArray ys]) =
349
  liftA2 (,) (J.readJSON x) (mapM readLockOwnerstate ys)
350
readOwnerLock x = fail $ "Expected pair of owner and list of owned locks,"
351
                         ++ " but found " ++ show x
352

  
353
-- | Transform a lock-ownerstate pair into a LockRequest.
354
toRequest :: (a, OwnerState) -> LockRequest a
355
toRequest (a, OwnExclusive) = requestExclusive a
356
toRequest (a, OwnShared) = requestShared a
357

  
358
-- | Obtain a LockAllocation from a given owner-locks list.
359
-- The obtained allocation is the one obtained if the respective owners
360
-- requested their locks sequentially.
361
allocationFromOwners :: (Lock a, Ord b, Show b)
362
                     => [(b, [(a, OwnerState)])]
363
                     -> J.Result (LockAllocation a b)
364
allocationFromOwners =
365
  let allocateOneOwner s (o, req) = do
366
        let (s', result) = updateLocks o (map toRequest req) s
367
        when (result /= Ok S.empty) . fail
368
          . (++) ("Inconsistent lock status for " ++ show o ++ ": ")
369
          $ case result of
370
            Bad err -> err
371
            Ok blocked -> "blocked on " ++ show (S.toList blocked)
372
        return s'
373
  in foldM allocateOneOwner emptyAllocation
374

  
375
instance (Lock a, J.JSON a, Ord b, J.JSON b, Show b)
376
           => J.JSON (LockAllocation a b) where
377
  showJSON = J.showJSON . M.toList . M.map M.toList . laOwned
378
  readJSON x = do
379
    xs <- toArray x
380
    owned <- mapM readOwnerLock xs
381
    allocationFromOwners owned

Also available in: Unified diff