@@ -28,7 +28,7 @@ module Database.LSMTree.Internal (
2828 , TableClosedError (.. )
2929 , TableCorruptedError (.. )
3030 , TableTooLargeError (.. )
31- , TableNotCompatibleError (.. )
31+ , TableUnionNotCompatibleError (.. )
3232 , SnapshotExistsError (.. )
3333 , SnapshotDoesNotExistError (.. )
3434 , SnapshotCorruptedError (.. )
@@ -1534,27 +1534,30 @@ duplicate t@Table{..} = do
15341534 tableArenaManager
15351535 content
15361536
1537-
15381537{- ------------------------------------------------------------------------------
15391538 Table union
15401539-------------------------------------------------------------------------------}
15411540
1542- -- | An operation was called with two tables that are not compatible.
1543- data TableNotCompatibleError
1544- = -- | An operation was called with two tables that are not of the same type.
1545- --
1546- -- TODO: This error is no longer used by 'unions'.
1547- ErrTableTypeMismatch
1548- -- | Vector index of table @t1@ involved in the mismatch
1549- Int
1550- -- | Vector index of table @t2@ involved in the mismatch
1551- Int
1552- | -- | An operation was called with two tables that are not in the same session.
1553- ErrTableSessionMismatch
1554- -- | Vector index of table @t1@ involved in the mismatch
1555- Int
1556- -- | Vector index of table @t2@ involved in the mismatch
1557- Int
1541+ -- | A table union was constructed with two tables that are not compatible.
1542+ data TableUnionNotCompatibleError
1543+ = ErrTableUnionHandleTypeMismatch
1544+ -- | The index of the first table.
1545+ ! Int
1546+ -- | The type of the filesystem handle of the first table.
1547+ ! TypeRep
1548+ -- | The index of the second table.
1549+ ! Int
1550+ -- | The type of the filesystem handle of the second table.
1551+ ! TypeRep
1552+ | ErrTableUnionSessionMismatch
1553+ -- | The index of the first table.
1554+ ! Int
1555+ -- | The session directory of the first table.
1556+ ! FsErrorPath
1557+ -- | The index of the second table.
1558+ ! Int
1559+ -- | The session directory of the second table.
1560+ ! FsErrorPath
15581561 deriving stock (Show , Eq )
15591562 deriving anyclass (Exception )
15601563
@@ -1565,10 +1568,7 @@ unions ::
15651568 => NonEmpty (Table m h )
15661569 -> m (Table m h )
15671570unions ts = do
1568- sesh <-
1569- matchSessions ts >>= \ case
1570- Left (i, j) -> throwIO $ ErrTableSessionMismatch i j
1571- Right sesh -> pure sesh
1571+ sesh <- ensureSessionsMatch ts
15721572
15731573 traceWith (sessionTracer sesh) $ TraceUnions (NE. map tableId ts)
15741574
@@ -1706,37 +1706,34 @@ writeBufferToNewRun SessionEnv {
17061706 tableWriteBuffer
17071707 tableWriteBufferBlobs
17081708
1709- -- | Check that all tables in the session match. If so, return the matched
1710- -- session. If there is a mismatch, return the list indices of the mismatching
1711- -- tables.
1712- --
1713- -- TODO: compare LockFileHandle instead of SessionRoot (?). We can write an Eq
1714- -- instance for LockFileHandle based on pointer equality, just like base does
1715- -- for Handle.
1716- matchSessions ::
1709+ {-# SPECIALISE ensureSessionsMatch ::
1710+ NonEmpty (Table IO h)
1711+ -> IO (Session IO h) #-}
1712+ -- | Check if all tables have the same session.
1713+ -- If so, return the session.
1714+ -- Otherwise, throw a 'TableUnionNotCompatibleError'.
1715+ ensureSessionsMatch ::
17171716 (MonadSTM m , MonadThrow m )
17181717 => NonEmpty (Table m h )
1719- -> m (Either (Int , Int ) (Session m h ))
1720- matchSessions = \ (t :| ts) ->
1721- withSessionRoot t $ \ root -> do
1722- eith <- go root 1 ts
1723- pure $ case eith of
1724- Left i -> Left (0 , i)
1725- Right () -> Right (tableSession t)
1726- where
1718+ -> m (Session m h )
1719+ ensureSessionsMatch (t :| ts) = do
1720+ let sesh = tableSession t
1721+ withOpenSession sesh $ \ seshEnv -> do
1722+ let root = FS. mkFsErrorPath (sessionHasFS seshEnv) (getSessionRoot (sessionRoot seshEnv))
17271723 -- Check that the session roots for all tables are the same. There can only
17281724 -- be one *open/active* session per directory because of cooperative file
17291725 -- locks, so each unique *open* session has a unique session root. We check
17301726 -- that all the table's sessions are open at the same time while comparing
17311727 -- the session roots.
1732- go _ _ [] = pure (Right () )
1733- go root ! i (t': ts') =
1734- withSessionRoot t' $ \ root' ->
1735- if root == root'
1736- then go root (i+ 1 ) ts'
1737- else pure (Left i)
1738-
1739- withSessionRoot t k = withOpenSession (tableSession t) $ k . sessionRoot
1728+ for_ (zip [1 .. ] ts) $ \ (i, t') -> do
1729+ let sesh' = tableSession t'
1730+ withOpenSession sesh' $ \ seshEnv' -> do
1731+ let root' = FS. mkFsErrorPath (sessionHasFS seshEnv') (getSessionRoot (sessionRoot seshEnv'))
1732+ -- TODO: compare LockFileHandle instead of SessionRoot (?).
1733+ -- We can write an Eq instance for LockFileHandle based on pointer equality,
1734+ -- just like base does for Handle.
1735+ unless (root == root') $ throwIO $ ErrTableUnionSessionMismatch 0 root i root'
1736+ pure sesh
17401737
17411738{- ------------------------------------------------------------------------------
17421739 Table union: debt and credit
0 commit comments