@@ -25,38 +25,61 @@ module Share.Postgres.Causal.Queries
2525 hashCausal ,
2626 bestCommonAncestor ,
2727 isFastForward ,
28+
29+ -- * Sync
30+ expectCausalEntity ,
31+ expectNamespaceEntity ,
32+
33+ -- * For migrations, can probably remove this export later.
34+ saveSerializedCausal ,
35+ saveSerializedNamespace ,
2836 )
2937where
3038
3139import Control.Lens
40+ import Data.ByteString.Lazy.Char8 qualified as BL
3241import Data.Map qualified as Map
3342import Data.Set qualified as Set
43+ import Data.Vector qualified as Vector
3444import Share.Codebase.Types (CodebaseM )
3545import Share.Codebase.Types qualified as Codebase
3646import Share.IDs (UserId )
3747import Share.Postgres
3848import Share.Postgres.Causal.Types
3949import Share.Postgres.Definitions.Queries qualified as Defn
50+ import Share.Postgres.Definitions.Queries qualified as DefnQ
4051import Share.Postgres.Definitions.Types
4152import Share.Postgres.Hashes.Queries qualified as HashQ
4253import Share.Postgres.IDs
4354import Share.Postgres.Patches.Queries qualified as PatchQ
55+ import Share.Postgres.Serialization qualified as S
56+ import Share.Postgres.Sync.Conversions qualified as Cv
4457import Share.Prelude
4558import Share.Utils.Postgres (OrdBy , ordered )
4659import Share.Web.Errors (MissingExpectedEntity (MissingExpectedEntity ))
4760import U.Codebase.Branch hiding (NamespaceStats , nonEmptyChildren )
4861import U.Codebase.Branch qualified as V2 hiding (NamespaceStats )
4962import U.Codebase.Causal qualified as Causal
63+ import U.Codebase.Causal qualified as U
5064import U.Codebase.Reference
5165import U.Codebase.Referent
5266import U.Codebase.Referent qualified as Referent
67+ import U.Codebase.Sqlite.Branch.Format (LocalBranchBytes (.. ))
68+ import U.Codebase.Sqlite.Branch.Format qualified as BranchFormat
5369import U.Codebase.Sqlite.Branch.Full qualified as BranchFull
70+ import U.Codebase.Sqlite.LocalizeObject qualified as Localize
71+ import U.Codebase.Sqlite.TempEntity (TempEntity )
5472import Unison.Codebase.Path qualified as Path
5573import Unison.Hash (Hash )
5674import Unison.Hash32 (Hash32 )
75+ import Unison.Hash32 qualified as Hash32
5776import Unison.Hashing.V2 qualified as H
5877import Unison.NameSegment.Internal as NameSegment
5978import Unison.Reference qualified as Reference
79+ import Unison.Sync.Common qualified as SyncCommon
80+ import Unison.Sync.Types qualified as Sync
81+ import Unison.SyncV2.Types (CBORBytes (.. ))
82+ import Unison.SyncV2.Types qualified as SyncV2
6083import Unison.Util.Map qualified as Map
6184
6285expectCausalNamespace :: (HasCallStack , QueryM m ) => CausalId -> m (CausalNamespace m )
@@ -407,18 +430,22 @@ loadCausalNamespaceAtPath causalId path = do
407430-- | Given a namespace whose dependencies have all been pre-saved, save it to the database under the given hash.
408431savePgNamespace ::
409432 (HasCallStack ) =>
433+ -- | The pre-serialized namespace, if available. If Nothing it will be re-generated, which is slower.
434+ Maybe TempEntity ->
410435 -- Normally we'd prefer to always hash it ourselves, but there are some bad hashes in the wild
411436 -- that we need to support saving, if we're passed a hash to save a branch at we will save
412437 -- it at that hash regardless of what the _actual_ hash is.
413438 Maybe BranchHash ->
414439 PgNamespace ->
415440 CodebaseM e (BranchHashId , BranchHash )
416- savePgNamespace mayBh b@ (BranchFull. Branch {terms, types, patches, children}) = do
441+ savePgNamespace maySerialized mayBh b@ (BranchFull. Branch {terms, types, patches, children}) = do
417442 codebaseOwnerUserId <- asks Codebase. codebaseOwner
418443 bh <- whenNothing mayBh $ hashPgNamespace b
419444 bhId <- HashQ. ensureBranchHashId bh
420445 queryExpect1Col [sql | SELECT EXISTS (SELECT FROM namespaces WHERE namespace_hash_id = #{bhId}) |] >>= \ case
421- False -> doSave bhId
446+ False -> do
447+ doSave bhId
448+ doSaveSerialized bhId
422449 True -> pure ()
423450 execute_
424451 [sql | INSERT INTO namespace_ownership (namespace_hash_id, user_id)
@@ -427,6 +454,14 @@ savePgNamespace mayBh b@(BranchFull.Branch {terms, types, patches, children}) =
427454 |]
428455 pure (bhId, bh)
429456 where
457+ doSaveSerialized :: BranchHashId -> CodebaseM e ()
458+ doSaveSerialized bhId = do
459+ nsEntity <- case maySerialized of
460+ Just serialized -> pure serialized
461+ Nothing -> SyncCommon. entityToTempEntity id . Sync. N <$> expectNamespaceEntity bhId
462+ let serializedNamespace = SyncV2. serialiseCBORBytes nsEntity
463+ saveSerializedNamespace bhId serializedNamespace
464+
430465 doSave :: BranchHashId -> CodebaseM e ()
431466 doSave bhId = do
432467 -- Expand all term mappings into a list
@@ -608,6 +643,34 @@ savePgNamespace mayBh b@(BranchFull.Branch {terms, types, patches, children}) =
608643 -- Note: this must be run AFTER inserting the namespace and all its children.
609644 execute_ [sql | SELECT save_namespace(#{bhId}) |]
610645
646+ saveSerializedNamespace :: (QueryM m ) => BranchHashId -> CBORBytes TempEntity -> m ()
647+ saveSerializedNamespace bhId (CBORBytes bytes) = do
648+ bytesId <- DefnQ. ensureBytesIdsOf id (BL. toStrict bytes)
649+ execute_
650+ [sql |
651+ INSERT INTO serialized_namespaces (namespace_hash_id, bytes_id)
652+ VALUES (#{bhId}, #{bytesId})
653+ ON CONFLICT DO NOTHING
654+ |]
655+
656+ expectNamespaceEntity :: BranchHashId -> CodebaseM e (Sync. Namespace Text Hash32 )
657+ expectNamespaceEntity bhId = do
658+ v2Branch <- expectNamespace bhId
659+ second Hash32. fromHash <$> branchToEntity v2Branch
660+ where
661+ branchToEntity branch = do
662+ branchFull <- Cv. branchV2ToBF branch
663+ let (BranchFormat. LocalIds {branchTextLookup, branchDefnLookup, branchPatchLookup, branchChildLookup}, localBranch) = Localize. localizeBranchG branchFull
664+ let bytes = LocalBranchBytes $ S. encodeNamespace localBranch
665+ pure $
666+ Sync. Namespace
667+ { textLookup = Vector. toList branchTextLookup,
668+ defnLookup = Vector. toList branchDefnLookup,
669+ patchLookup = Vector. toList branchPatchLookup,
670+ childLookup = Vector. toList branchChildLookup,
671+ bytes = bytes
672+ }
673+
611674-- | Hash a namespace into a BranchHash
612675hashPgNamespace :: forall m . (QueryM m ) => PgNamespace -> m BranchHash
613676hashPgNamespace b = do
@@ -671,14 +734,23 @@ hashCausal branchHashId ancestorIds = do
671734 let hCausal = H. Causal {branchHash = unBranchHash branchHash, parents = ancestors}
672735 pure . CausalHash . H. contentHash $ hCausal
673736
674- saveCausal :: Maybe CausalHash -> BranchHashId -> Set CausalId -> CodebaseM e (CausalId , CausalHash )
675- saveCausal mayCh bhId ancestorIds = do
737+ saveCausal ::
738+ -- | The pre-serialized causal, if available. If Nothing it will be re-generated, which is slower.
739+ Maybe TempEntity ->
740+ Maybe CausalHash ->
741+ BranchHashId ->
742+ Set CausalId ->
743+ CodebaseM e (CausalId , CausalHash )
744+ saveCausal maySerializedCausal mayCh bhId ancestorIds = do
676745 ch <- maybe (hashCausal bhId ancestorIds) pure mayCh
677746 codebaseOwnerUserId <- asks Codebase. codebaseOwner
678747 cId <-
679748 query1Col [sql | SELECT id FROM causals WHERE hash = #{ch} |] >>= \ case
680749 Just cId -> pure cId
681- Nothing -> doSave ch
750+ Nothing -> do
751+ cId <- doSave ch
752+ doSaveSerialized cId
753+ pure cId
682754 execute_
683755 [sql |
684756 INSERT INTO causal_ownership (user_id, causal_id)
@@ -687,6 +759,14 @@ saveCausal mayCh bhId ancestorIds = do
687759 |]
688760 pure (cId, ch)
689761 where
762+ doSaveSerialized cId = do
763+ causalEntity <- case maySerializedCausal of
764+ Just serializedCausal -> pure serializedCausal
765+ Nothing -> do
766+ SyncCommon. entityToTempEntity id . Sync. C <$> expectCausalEntity cId
767+ let serializedCausal = SyncV2. serialiseCBORBytes causalEntity
768+ saveSerializedCausal cId serializedCausal
769+
690770 doSave ch = do
691771 cId <-
692772 queryExpect1Col
@@ -707,6 +787,26 @@ saveCausal mayCh bhId ancestorIds = do
707787 |]
708788 pure cId
709789
790+ saveSerializedCausal :: (QueryM m ) => CausalId -> CBORBytes TempEntity -> m ()
791+ saveSerializedCausal causalId (CBORBytes bytes) = do
792+ bytesId <- DefnQ. ensureBytesIdsOf id (BL. toStrict bytes)
793+ execute_
794+ [sql |
795+ INSERT INTO serialized_causals (causal_id, bytes_id)
796+ VALUES (#{causalId}, #{bytesId})
797+ ON CONFLICT DO NOTHING
798+ |]
799+
800+ expectCausalEntity :: (HasCallStack ) => CausalId -> CodebaseM e (Sync. Causal Hash32 )
801+ expectCausalEntity causalId = do
802+ U. Causal {valueHash, parents} <- expectCausalNamespace causalId
803+ pure $
804+ ( Sync. Causal
805+ { namespaceHash = Hash32. fromHash $ unBranchHash valueHash,
806+ parents = Set. map (Hash32. fromHash . unCausalHash) . Map. keysSet $ parents
807+ }
808+ )
809+
710810-- | Get the ref to the result of squashing if we've squashed that ref in the past.
711811-- Also adds the squash result to current codebase if we find it.
712812tryGetCachedSquashResult :: BranchHash -> CodebaseM e (Maybe CausalId )
@@ -744,7 +844,7 @@ saveSquashResult unsquashedBranchHash squashedCausalHashId = do
744844saveV2BranchShallow :: V2. Branch (CodebaseM e ) -> CodebaseM e (BranchHashId , BranchHash )
745845saveV2BranchShallow v2Branch = do
746846 pgNamespace <- expectV2BranchDependencies v2Branch
747- savePgNamespace Nothing pgNamespace
847+ savePgNamespace Nothing Nothing pgNamespace
748848 where
749849 expectV2BranchDependencies :: V2. Branch (CodebaseM e ) -> CodebaseM e PgNamespace
750850 expectV2BranchDependencies V2. Branch {terms, types, patches, children} = do
0 commit comments