packages feed

perdure 0.2.0 → 0.2.1

raw patch · 15 files changed

+153/−39 lines, 15 filesdep −deepseqdep −deepseq-thdep −lrucachedep ~MonadRandomdep ~cognimeta-utilsdep ~perdurePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies removed: deepseq, deepseq-th, lrucache

Dependency ranges changed: MonadRandom, cognimeta-utils, perdure

API changes (from Hackage documentation)

- Database.Perdure.Internal: emptyCache :: Integer -> Cache
- Database.Perdure.Persistent: type Cache = LRU (Len Word64 Word64) Dynamic
+ Database.Perdure.Persistent: data Cache
- Database.Perdure.Internal: BasicRef :: {-# UNPACK #-} !Len Word64 Word64 -> {-# UNPACK #-} !Len w Word32 -> BasicRef w
+ Database.Perdure.Internal: BasicRef :: {-# UNPACK #-} !(Len Word64 Word64) -> {-# UNPACK #-} !(Len w Word32) -> BasicRef w
- Database.Perdure.Internal: DeserOut :: !a -> {-# UNPACK #-} !Len Bool Word -> DeserOut a
+ Database.Perdure.Internal: DeserOut :: !a -> {-# UNPACK #-} !(Len Bool Word) -> DeserOut a
- Database.Perdure.Internal: Refed :: !r a -> CRef r a
+ Database.Perdure.Internal: Refed :: !(r a) -> CRef r a
- Database.Perdure.Internal: SpaceBook :: !MapMultiset Address -> !SpaceTree -> SpaceBook
+ Database.Perdure.Internal: SpaceBook :: !(MapMultiset Address) -> !SpaceTree -> SpaceBook
- Database.Perdure.Internal: bookCount :: SpaceBook -> !MapMultiset Address
+ Database.Perdure.Internal: bookCount :: SpaceBook -> !(MapMultiset Address)
- Database.Perdure.Internal: deserPos :: DeserOut a -> {-# UNPACK #-} !Len Bool Word
+ Database.Perdure.Internal: deserPos :: DeserOut a -> {-# UNPACK #-} !(Len Bool Word)
- Database.Perdure.Internal: refSize :: BasicRef w -> {-# UNPACK #-} !Len w Word32
+ Database.Perdure.Internal: refSize :: BasicRef w -> {-# UNPACK #-} !(Len w Word32)
- Database.Perdure.Internal: refStart :: BasicRef w -> {-# UNPACK #-} !Len Word64 Word64
+ Database.Perdure.Internal: refStart :: BasicRef w -> {-# UNPACK #-} !(Len Word64 Word64)
- Database.Perdure.Persistent: CRefPersister' :: !RefPersister r -> !Persister (r a) -> Persister (CRef r a)
+ Database.Perdure.Persistent: CRefPersister' :: !(RefPersister r) -> !(Persister (r a)) -> Persister (CRef r a)
- Database.Perdure.Persistent: DRef :: !Persister a -> !DeserializerContext -> !WArrayRef BasicRef -> DRef a
+ Database.Perdure.Persistent: DRef :: !(Persister a) -> !DeserializerContext -> !(WArrayRef BasicRef) -> DRef a
- Database.Perdure.Persistent: EitherPersister :: !Persister a -> !Persister b -> Persister (Either a b)
+ Database.Perdure.Persistent: EitherPersister :: !(Persister a) -> !(Persister b) -> Persister (Either a b)
- Database.Perdure.Persistent: PairPersister :: !Persister a -> !Persister b -> Persister (a, b)
+ Database.Perdure.Persistent: PairPersister :: !(Persister a) -> !(Persister b) -> Persister (a, b)
- Database.Perdure.Persistent: PartialWordPersister :: !Len Bool Word -> Persister Word
+ Database.Perdure.Persistent: PartialWordPersister :: !(Len Bool Word) -> Persister Word
- Database.Perdure.Persistent: Refed :: !r a -> CRef r a
+ Database.Perdure.Persistent: Refed :: !(r a) -> CRef r a
- Database.Perdure.Persistent: SummationPersister :: !Persister i -> !forall z. (forall b. Persister b -> (b -> a) -> z) -> i -> z -> !forall z. (forall b. i -> Persister b -> (b -> a) -> b -> z) -> a -> z -> Persister a
+ Database.Perdure.Persistent: SummationPersister :: !(Persister i) -> !(forall z. (forall b. Persister b -> (b -> a) -> z) -> i -> z) -> !(forall z. (forall b. i -> Persister b -> (b -> a) -> b -> z) -> a -> z) -> Persister a
- Database.Perdure.Persistent: ViewPersister :: !InjectionA' a b -> Persister b -> Persister a
+ Database.Perdure.Persistent: ViewPersister :: !(InjectionA' a b) -> Persister b -> Persister a
- Database.Perdure.Persistent: Word32ArrayRef :: !r32 r -> WordArrayRef r32 r64
+ Database.Perdure.Persistent: Word32ArrayRef :: !(r32 r) -> WordArrayRef r32 r64
- Database.Perdure.Persistent: Word64ArrayRef :: !r64 r -> WordArrayRef r32 r64
+ Database.Perdure.Persistent: Word64ArrayRef :: !(r64 r) -> WordArrayRef r32 r64
- Database.Perdure.Persistent: WordNArrayRef :: !v -> !r (ValidatedElem v) -> !Endianness -> WordNArrayRef v
+ Database.Perdure.Persistent: WordNArrayRef :: !v -> !(r (ValidatedElem v)) -> !Endianness -> WordNArrayRef v

Files

exe-src/Database/Perdure/TestPersistent.hs view
@@ -63,10 +63,10 @@ writeReadTestFile a name = fmap fromRight $ runErrorT $ withFileStoreFile name $ (. (ReplicatedFile . pure)) $ \f -> do
   putCpuTime "Data creation" $ evaluate $ prnf persister a
   putCpuTime "Write time" $ (() <$) $
-    newCachedFile 1000 f >>=
+    newCachedFile 1000000 f >>=
     createPVar a (mega 100) . defaultRootLocation
   putCpuTime "Read time" $
-    newCachedFile 1000 f >>=
+    newCachedFile 1000000 f >>=
     fmap (fromMaybe $ error "Read error") . openPVar . defaultRootLocation >>= \v ->
     updatePVar v $ get >>= liftIO . evaluate . (a ==)
 
exe-src/Database/Perdure/TestState.hs view
@@ -48,7 +48,7 @@  testStatesF :: ReplicatedFile -> IO () testStatesF f =-    newCachedFile 1000 f >>=+    newCachedFile 1000000 f >>=     createPVar (EmptyRList :: RList Word32) (mega 100) . defaultRootLocation >>= \v ->     for_ [0 .. 19] $ \c -> do       print c@@ -93,7 +93,7 @@ testStatesDag _ =   quickCheckWith (Args Nothing 1 1 1 True) $ morallyDubiousIOProperty $ (>>= either fail return) $ runErrorT $ (True <$) $   withReplicatedFiles "testStatesDag" $ \f -> -  newCachedFile 1000 f >>=+  newCachedFile 1000000 f >>=   createPVar (Dag $ ref []) (mega 100) . defaultRootLocation >>= \v ->   for_ [(0 :: Int) .. 1999] $ \c -> do     print c
perdure.cabal view
@@ -1,5 +1,5 @@ Name: perdure-version: 0.2.0+version: 0.2.1 cabal-version: >= 1.8 build-type: Simple license: OtherLicense@@ -162,6 +162,8 @@     Database.Perdure.Allocator     Database.Perdure.AllocCopy     Database.Perdure.ArrayRef+    Database.Perdure.Cache+    Database.Perdure.Cache1     Database.Perdure.Count     Database.Perdure.CSerializer     Database.Perdure.CDeserializer@@ -187,10 +189,11 @@     Database.Perdure.WordArrayRef     Database.Perdure.WordNArrayRef     Database.Perdure.WValidator+  C-sources:   build-depends:     base >= 4.5.0.0 && < 5,     template-haskell >= 2.7.0.0,-    cognimeta-utils == 0.1.1,+    cognimeta-utils == 0.1.2,     QuickCheck >=2.4.0.1,     strict >= 0.3.2,     mtl >= 2.1.2,@@ -214,9 +217,7 @@     time >= 1.4.0.1,     unix >= 2.5.1.0,     data-binary-ieee754 >= 0.4.2.1,-    lrucache >= 1.1.1,-    deepseq >= 1.3.0.0,-    deepseq-th >= 0.1.0.3+    MonadRandom >= 0.1.8    ghc-options: -rtsopts -Wall -fno-warn-orphans -fcontext-stack=80 -O2 -funfolding-use-threshold=24 -pgmP cpphs -optP --cpp   extensions: @@ -236,15 +237,14 @@   build-depends:     base >= 4.5.0.0,     template-haskell >= 2.7.0.0,-    cognimeta-utils == 0.1.1,+    cognimeta-utils == 0.1.2,     mtl >= 2.1.2,-    deepseq,     QuickCheck >=2.4.0.1,-    perdure >= 0.2.0,+    perdure >= 0.2.1,     transformers >= 0.3.0.0,     bytestring >= 0.9.2.1,     containers >= 0.4.2.1,-    MonadRandom == 0.1.3+    MonadRandom >= 0.1.3   ghc-options: -rtsopts -Wall -fcontext-stack=80 -fno-warn-duplicate-exports -O2 -funfolding-use-threshold=24 -threaded  -- We are not using the unicode (TM) symbol because of http://trac.haskell.org/haddock/ticket/210
src/Database/Perdure.hs view
@@ -42,6 +42,7 @@ import Database.Perdure.Deref import Database.Perdure.Rev import Database.Perdure.SizeRef+import qualified Database.Perdure.Cache as Cache import Cgm.Control.Monad.State as M import Cgm.Data.Typeable import Control.Monad.Reader hiding (sequence)@@ -52,9 +53,11 @@ import Database.Perdure.ReplicatedFile(ReplicatedFile(..)) import Database.Perdure.LocalStoreFile(withFileStoreFile, withRawDeviceStoreFile, withRawDeviceStoreFiles, LocalStoreFile) --- | Wraps a ReplicatedFile with cache of a given size (number of dereferenced DRefs)+-- | Wraps a ReplicatedFile with a cache of a given size. The size is specified in bytes of serialized data, but the actual consumed+-- size may be a few times larger since the cache contains the deserialized data, which is often less compact than its serialized+-- representation. newCachedFile :: Integer -> ReplicatedFile -> IO CachedFile-newCachedFile sz f = CachedFile f <$> newMVar (emptyCache sz)+newCachedFile sz f = CachedFile f <$> newMVar (Cache.empty sz)  -- | At the moment this is the only way to create a rootLocation. -- The root of the database will be located in one of two reserved locations at the start of the specified files.
src/Database/Perdure/ArrayRef.hs view
@@ -25,4 +25,5 @@   writeArrayRef :: (Allocator l) => l -> PrimArray Pinned (ArrayRefElem r) -> IO (r (StoreRef ReplicatedFile))
   derefArrayRef :: (StoreFile f, Allocation fr) => f -> r (StoreRef f) -> IO (Maybe (ArrayRange (PrimArray fr (ArrayRefElem r))))
   arrayRefAddr ::  r BasicRef -> Len Word64 Word64
+  arrayRefSize ::  r BasicRef -> Len Word64 Word64
   
src/Database/Perdure/CSerializer.hs view
@@ -40,9 +40,10 @@ import Database.Perdure.ArrayRef
 import Database.Perdure.WordArrayRef()
 import Database.Perdure.WordNArrayRef()
+import qualified Database.Perdure.Cache as Cache
 import Cgm.Data.MapMultiset
-import qualified Data.Cache.LRU as LRU
 import Data.Dynamic
+import Control.Monad.Random
 
 
 -- Important : We must not read (deref) a ref that has just been written in the current writeState.
@@ -116,14 +117,15 @@ writeDRef p ma dc@(DeserializerContext _ c) l start end = 
   DRef p dc <$> maybe id (\a -> (>>= \w -> w <$ addToCache a w)) ma (allocCopyBits start end >>= writeArrayRef l) where
   addToCache a w = let addr = arrayRefAddr w in modifyMVar_ c $ 
-                                                return . {-(trace ("writing/adding to cache at" ++ show addr) $ -}LRU.insert addr (toDyn a)
+                                                evalRandIO . {-(trace ("writing/adding to cache at" ++ show addr) $ -}
+                                                Cache.insert addr (Cache.Entry (toDyn a) $ arrayRefSize w)
   
 -- | The passed Persister must hace no references
 {-# NOINLINE serializeToArray #-}
 serializeToArray :: AllocCopy w => Persister a -> a -> PrimArray Pinned w
 serializeToArray p a = unsafePerformIO $ do
   start <- stToIO mkABitSeq 
-  noCache <- newMVar $ LRU.fromList Nothing []
+  noCache <- newMVar $ Cache.empty 0
   cSer p (noCache, NoAllocator, Nothing :: CountDest MapMultiset) (const $ allocCopyBits start) a start
                              
 data NoAllocator = NoAllocator
+ src/Database/Perdure/Cache.hs view
@@ -0,0 +1,49 @@+{-+Copyright 2010-2012 Cognimeta Inc.++Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in+compliance with the License. You may obtain a copy of the License at++     http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software distributed under the License is+distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express+or implied. See the License for the specific language governing permissions and limitations under the License.+-}++module Database.Perdure.Cache (+  Cache(..),+  Entry(..),+  empty,+  lookup,+  insert,+  delete+  ) where++import Prelude ()+import Cgm.Prelude hiding (empty, lookup, insert, delete)+import qualified Database.Perdure.Cache1 as Cache+import Control.Monad.Random+import Data.Dynamic+import Cgm.Data.Len+import Data.Word+import Database.Perdure.Count(Address)++data Entry = Entry {entryValue :: Dynamic, entrySize :: Len Word64 Word64}+instance Cache.Entry Entry where entrySize (Entry _ s) = fromIntegral s++newtype Cache = Cache (Cache.Cache Address Entry)++-- | Create an empty cache of the specified size in bytes of serialized data. The actual consumed size may be a few times larger+-- since heap data is usually much less compact than its serialized representation.+empty :: Integer -> Cache+empty = Cache . Cache.empty . getLen . (id :: Id (Len Word64 Integer)) . coarsenLen . (id :: Id (Len Word8 Integer)) . unsafeLen++lookup :: Address -> Cache -> Maybe (Entry, Cache)+lookup k (Cache c) = fmap (second Cache) $ Cache.lookup k c+  +insert :: RandomGen g => Address -> Entry -> Cache -> Rand g Cache+insert k v (Cache c) = fmap Cache $ Cache.insert k v c++delete :: Address -> Cache -> Cache+delete k (Cache c) = Cache $ Cache.delete k c
+ src/Database/Perdure/Cache1.hs view
@@ -0,0 +1,61 @@+{-+Copyright 2010-2012 Cognimeta Inc.++Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in+compliance with the License. You may obtain a copy of the License at++     http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software distributed under the License is+distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express+or implied. See the License for the specific language governing permissions and limitations under the License.+-}++module Database.Perdure.Cache1 (+  Cache(..),+  Entry(..),+  empty,+  lookup,+  insert,+  delete+  ) where++import Prelude hiding (lookup)+import qualified Data.Map as Map+import Control.Monad.Random+import Control.Applicative hiding (empty)+import Control.Arrow+import Data.List(minimumBy)+import Data.Ord++data Cache k a = Cache {contents :: Map.Map k (a, Integer), step :: Integer, size :: Integer, free :: Integer}++class Entry a where entrySize :: a -> Integer++empty :: Integer -> Cache k a+empty sz = Cache Map.empty 0 sz sz++lookup :: Ord k => k -> Cache k a -> Maybe (a, Cache k a)+lookup k (Cache c p s f) = fmap (\(a1, _) -> (a1, Cache (Map.insert k (a1, p) c) (p + 1) s f)) $ Map.lookup k c+  +insert :: (RandomGen g, Ord k, Entry a) => k -> a -> Cache k a -> Rand g (Cache k a)+insert k v cache =+  let es = entrySize v+      insert' (Cache c p s f) = Cache (Map.insert k (v, p) c) (p + 1) s (f - es)+  in (if es <= size cache+      then fmap insert' $ requireFree es cache+      else return cache) where+    requireFree :: (RandomGen g, Ord k, Entry a) => Integer -> Cache k a -> Rand g (Cache k a)+    requireFree n ca = if free ca > n then return ca else flip deleteExisting ca <$> oldestOfSample ca+    oldestOfSample :: RandomGen g => Cache k a -> Rand g (k, a)+    oldestOfSample (Cache c _ _ _) =+      fmap ((fst &&& fst . snd) . minimumBy (comparing $ snd . snd)) $+      sequence $ replicate 10 $ fmap (flip Map.elemAt c) $ getRandomR (0, Map.size c - 1)+    +deleteExisting :: (Ord k, Entry a) => (k, a) -> Cache k a -> Cache k a+deleteExisting (k, a) (Cache c p s f) = Cache (Map.delete k c) p s $ f + entrySize a++delete :: (Ord k, Entry a) => k -> Cache k a -> Cache k a+delete k (Cache c p s f) =+  let (mv, c') = Map.updateLookupWithKey (const $ const Nothing) k c+  in Cache c' p s $ maybe id ((+) . entrySize . fst) mv f
src/Database/Perdure/Decrementer.hs view
@@ -25,7 +25,7 @@ import Cgm.Data.Multiset as MS
 import Database.Perdure.SpaceBook
 import Database.Perdure.Deref
-import qualified Data.Cache.LRU as LRU
+import qualified Database.Perdure.Cache as Cache
 import Database.Perdure.ArrayRef
 import Control.Concurrent.MVar
 import System.IO.Unsafe
@@ -47,7 +47,7 @@ 
 {-# NOINLINE unsafeClearCache #-}
 unsafeClearCache :: MVar Cache -> Len Word64 Word64 -> ()
-unsafeClearCache c addr = unsafePerformIO $ modifyMVar_  c $ return . fst . LRU.delete addr
+unsafeClearCache c addr = unsafePerformIO $ modifyMVar_  c $ return . Cache.delete addr
 
 decrRef :: forall w. LgMultiple Word64 w => 
            BasicRef w -> (SpaceBook -> SpaceBook) -> SpaceBook -> SpaceBook
src/Database/Perdure/Deref.hs view
@@ -32,8 +32,9 @@ import Data.Word
 import Control.Concurrent.MVar
 import Control.Exception.Base
-import qualified Data.Cache.LRU as LRU
+import qualified Database.Perdure.Cache as Cache
 import Data.Dynamic
+import Control.Monad.Random
 
 class Deref r where
   derefIO :: r a -> IO a
@@ -47,14 +48,16 @@ 
 instance Deref DRef where 
   derefIO (DRef p dc@(DeserializerContext f cv) aRef) = 
-    let addr = arrayRefAddr aRef 
-        r = {-(trace ("(looking up cache at" ++ show addr ++ " wanting an " ++ show (typeOf r))-} modifyMVar cv (return . LRU.lookup addr) >>= 
-            maybe 
-            ((>>= \a -> evaluate a >> (a <$ modifyMVar_ cv (return . {-(trace ("adding to cache at" ++ show addr) $-} LRU.insert addr (toDyn a)))) $
-             fmap (maybe (error "Read error") $ deserializeFromFullArray (cDeser p dc) . (id :: Id (ArrayRange (PrimArray Free Word)))) $
-             derefArrayRef f aRef)
-            (return . fromMaybe (error $ "Wrong type in cache cell " ++ show addr) . fromDynamic)
-    in r
+    let addr = arrayRefAddr aRef
+    in {-trace ("(looking up cache at" ++ show addr ++ " wanting an " ++ show (typeOf r))-}
+     modifyMVar cv (\c -> return $ (maybe (c, Nothing) $ \(e, c') -> (c', Just $ Cache.entryValue e)) $ Cache.lookup addr c) >>= 
+     maybe 
+     ((>>= \a -> evaluate a >>
+                 (a <$ modifyMVar_ cv (evalRandIO . {-trace ("adding to cache at" ++ show addr) $-}
+                                       Cache.insert addr (Cache.Entry (toDyn a) $ arrayRefSize aRef)))) $
+      fmap (maybe (error "Read error") $ deserializeFromFullArray (cDeser p dc) . (id :: Id (ArrayRange (PrimArray Free Word)))) $
+      derefArrayRef f aRef)
+     (return . fromMaybe (error $ "Wrong type in cache cell " ++ show addr) . fromDynamic)
     
 instance Show a => Show (DRef a) where show = show . deref
 instance Eq a => Eq (DRef a) where (==) = derefEq
src/Database/Perdure/Digest.hs view
@@ -30,6 +30,7 @@ import qualified Data.ByteString as B
 import qualified Crypto.Hash.MD5 as MD5
 import qualified Crypto.Hash.Skein512 as Skein512
+--import qualified Database.Perdure.Skein512 as Skein512
 import Cgm.Data.Structured
 
 -- Recovers a hash function on words from a hash function on a specific byte encoding the words
src/Database/Perdure/Persistent.hs view
@@ -79,13 +79,13 @@ import Database.Perdure.WValidator import Database.Perdure.StoreFile import Database.Perdure.ReplicatedFile+import Database.Perdure.Cache(Cache) import Cgm.System.Endian import Data.Char import Data.Binary.IEEE754 import Cgm.Data.List import Data.Bits import Database.Perdure.CRef-import Data.Cache.LRU import Data.Dynamic import Control.Concurrent.MVar @@ -94,8 +94,6 @@ data WordArrayRef r32 r64 (r :: * -> *) = Word32ArrayRef !(r32 r) | Word64ArrayRef !(r64 r)  type WArrayRef = WordArrayRef (WordNArrayRef W32Validator) (WordNArrayRef W64Validator)--type Cache = LRU (Len Word64 Word64) Dynamic  data DeserializerContext = forall f. (StoreFile f, StoreRef f ~ BasicRef) => DeserializerContext {dcFile :: f, dcCache :: MVar Cache} 
src/Database/Perdure/State.hs view
@@ -28,7 +28,6 @@   --asyncCollectState,
   collectState,
   collectStateM,
-  emptyCache,
   module Database.Perdure.Space,
   module Database.Perdure.Persistent,
   CachedFile(..),
@@ -60,7 +59,6 @@ import Database.Perdure.Deref
 import Database.Perdure.SpaceBook
 import Cgm.Data.Typeable
-import qualified Data.Cache.LRU as LRU
 import Cgm.Data.Maybe
 import Database.Perdure.WriteBits
 import Database.Perdure.AllocCopy
@@ -134,11 +132,6 @@ readState l@(RootLocation f rootAddrs) = 
   fmap (\r -> let rs = rootScan $ toOnlyRev r in PState l (bookSpace $ incr persister rs $ deref $ rootCS rs) r) . 
   maybeMaximumBy (comparing $ rootId . toOnlyRev) . catMaybes <$> sequence (readRoot f <$> rootAddrs)
-
--- | Create an empty cache of the specified size (number of dereferenced DRefs).
--- Note that eventually we would like a cache with a size measured in bytes, for a better prediction of memory consumption.
-emptyCache :: Integer -> Cache
-emptyCache sz = LRU.fromList (Just sz) []
 
 -- | We reserve the option of growing roots to 1MB, so use this as a minimum distance between the various RootAddress in RootLocation
 rootAllocSize :: Len Word64 Word32
src/Database/Perdure/WordArrayRef.hs view
@@ -36,6 +36,8 @@   derefArrayRef f (Word64ArrayRef r) = fmap deserInput <$> derefPinnedArrayRef f r
   arrayRefAddr (Word32ArrayRef r) = arrayRefAddr r
   arrayRefAddr (Word64ArrayRef r) = arrayRefAddr r
+  arrayRefSize (Word32ArrayRef r) = arrayRefSize r
+  arrayRefSize (Word64ArrayRef r) = arrayRefSize r
 
 derefPinnedArrayRef :: (ArrayRef r, StoreFile f) => f -> r (StoreRef f) -> IO (Maybe (ArrayRange (PrimArray Pinned (ArrayRefElem r))))
 derefPinnedArrayRef = derefArrayRef
src/Database/Perdure/WordNArrayRef.hs view
@@ -39,4 +39,5 @@     return $ WordNArrayRef v r platformWordEndianness
   derefArrayRef f (WordNArrayRef v r e) = fmap primArrayMatchAllocation <$> await1 (storeFileRead f r e v)
   arrayRefAddr (WordNArrayRef _ r _) = refStart r
+  arrayRefSize (WordNArrayRef _ r _) = coarsenLen $ fmap fromIntegral $ refSize r