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