@@ -14,6 +14,7 @@ import (
1414 "slices"
1515 "sort"
1616 "strings"
17+ "sync"
1718 "time"
1819
1920 "go.kenn.io/agentsview/internal/artifact"
@@ -354,6 +355,13 @@ func (s *Sync) Push(
354355 if err != nil {
355356 return result , err
356357 }
358+ ctx , err = s .preloadPGSessionOwners (ctx , s .pushIdentityOwnerCandidateIDs (
359+ sessionByID , artifactImportedSessions , localArtifactOrigin ,
360+ markerID , legacyMarkerMachines ,
361+ ))
362+ if err != nil {
363+ return result , err
364+ }
357365 for id , sess := range sessionByID {
358366 _ , artifactImported := artifactImportedSessions [sess .ID ]
359367 identity , err := s .resolvePushedSessionIdentity (
@@ -1855,6 +1863,31 @@ func (s *Sync) markRelationshipConflicts(
18551863 return nil
18561864}
18571865
1866+ func initialPushedSessionIdentity (
1867+ sess db.Session ,
1868+ fallbackMachine string ,
1869+ localArtifactOrigin string ,
1870+ artifactImported bool ,
1871+ markerID string ,
1872+ ) (pushedSessionIdentity , bool ) {
1873+ identity := pushedSessionIdentity {
1874+ ID : sess .ID ,
1875+ Machine : pushedSessionMachine (sess , fallbackMachine ),
1876+ }
1877+ if id , machine , ownerMarker , ok := artifactPushIdentity (
1878+ sess , localArtifactOrigin , artifactImported ,
1879+ ); ok {
1880+ identity .ID = id
1881+ identity .Machine = machine
1882+ identity .OwnerMarker = ownerMarker
1883+ identity .LegacyOwnerMarkers = []string {markerID }
1884+ identity .ArtifactReplica = artifactImported
1885+ identity .AliasIDs = artifactPushAliasIDs (sess , id , machine )
1886+ return identity , true
1887+ }
1888+ return identity , false
1889+ }
1890+
18581891// resolvePushedSessionIdentity decides the PG id a local session is stored
18591892// under. A session this sync owns -- by matching push marker, or an adoptable
18601893// legacy/ownerless row (see sameSessionOwner) -- is updated in place: an
@@ -1873,22 +1906,9 @@ func (s *Sync) resolvePushedSessionIdentity(
18731906 markerID string ,
18741907 legacyMarkerMachines []string ,
18751908) (pushedSessionIdentity , error ) {
1876- identity := pushedSessionIdentity {
1877- ID : sess .ID ,
1878- Machine : pushedSessionMachine (sess , s .machine ),
1879- }
1880- artifactIdentity := false
1881- if id , machine , ownerMarker , ok := artifactPushIdentity (
1882- sess , localArtifactOrigin , artifactImported ,
1883- ); ok {
1884- artifactIdentity = true
1885- identity .ID = id
1886- identity .Machine = machine
1887- identity .OwnerMarker = ownerMarker
1888- identity .LegacyOwnerMarkers = []string {markerID }
1889- identity .ArtifactReplica = artifactImported
1890- identity .AliasIDs = artifactPushAliasIDs (sess , id , machine )
1891- }
1909+ identity , artifactIdentity := initialPushedSessionIdentity (
1910+ sess , s .machine , localArtifactOrigin , artifactImported , markerID ,
1911+ )
18921912 canonicalID := identity .ID
18931913 id , err := s .resolveOwnedPushIdentityID (
18941914 ctx , identity .ID , identity , markerID , legacyMarkerMachines ,
@@ -1920,6 +1940,42 @@ func (s *Sync) resolvePushedSessionIdentity(
19201940 return identity , nil
19211941}
19221942
1943+ func (s * Sync ) pushIdentityOwnerCandidateIDs (
1944+ sessionByID map [string ]db.Session ,
1945+ artifactImportedSessions map [string ]struct {},
1946+ localArtifactOrigin string ,
1947+ markerID string ,
1948+ legacyMarkerMachines []string ,
1949+ ) []string {
1950+ ids := make (map [string ]struct {}, len (sessionByID )* 3 )
1951+ for _ , sess := range sessionByID {
1952+ _ , artifactImported := artifactImportedSessions [sess .ID ]
1953+ identity , _ := initialPushedSessionIdentity (
1954+ sess , s .machine , localArtifactOrigin , artifactImported , markerID ,
1955+ )
1956+ ids [identity .ID ] = struct {}{}
1957+ for _ , machine := range pushIDMachinePrefixes (
1958+ identity .Machine , legacyMarkerMachines ,
1959+ ) {
1960+ candidateID := prefixedSessionID (machine , identity .ID )
1961+ if candidateID != identity .ID {
1962+ ids [candidateID ] = struct {}{}
1963+ }
1964+ }
1965+ for _ , aliasID := range uniqueNonEmptyStrings (identity .AliasIDs ) {
1966+ ids [aliasID ] = struct {}{}
1967+ }
1968+ }
1969+ result := make ([]string , 0 , len (ids ))
1970+ for id := range ids {
1971+ if id != "" {
1972+ result = append (result , id )
1973+ }
1974+ }
1975+ sort .Strings (result )
1976+ return result
1977+ }
1978+
19231979// artifactLegacyDuplicateCandidate recognizes the narrow upgrade state where
19241980// an importer already created the stable artifact id while this origin still
19251981// owns its pre-artifact bare row. Both rows must already have the exact owners
@@ -2076,13 +2132,85 @@ func pushIDMachinePrefixes(machine string, legacyMarkerMachines []string) []stri
20762132 return prefixes
20772133}
20782134
2135+ type pgSessionOwnerRecord struct {
2136+ machine string
2137+ ownerMarker string
2138+ exists bool
2139+ }
2140+
2141+ type pgSessionOwnerCache struct {
2142+ mu sync.Mutex
2143+ entries map [string ]pgSessionOwnerRecord
2144+ }
2145+
2146+ type pgSessionOwnerCacheContextKey struct {}
2147+
2148+ func (c * pgSessionOwnerCache ) get (id string ) (pgSessionOwnerRecord , bool ) {
2149+ c .mu .Lock ()
2150+ defer c .mu .Unlock ()
2151+ record , ok := c .entries [id ]
2152+ return record , ok
2153+ }
2154+
2155+ func (c * pgSessionOwnerCache ) put (id string , record pgSessionOwnerRecord ) {
2156+ c .mu .Lock ()
2157+ defer c .mu .Unlock ()
2158+ c .entries [id ] = record
2159+ }
2160+
2161+ // preloadPGSessionOwners resolves a candidate set in one PG round trip and
2162+ // records both hits and misses. pgSessionOwner reuses this cache and memoizes
2163+ // any relationship targets discovered later in the same push.
2164+ func (s * Sync ) preloadPGSessionOwners (
2165+ ctx context.Context , ids []string ,
2166+ ) (context.Context , error ) {
2167+ unique := uniqueNonEmptyStrings (ids )
2168+ cache := & pgSessionOwnerCache {
2169+ entries : make (map [string ]pgSessionOwnerRecord , len (unique )),
2170+ }
2171+ for _ , id := range unique {
2172+ cache .entries [id ] = pgSessionOwnerRecord {}
2173+ }
2174+ if len (unique ) == 0 {
2175+ return context .WithValue (ctx , pgSessionOwnerCacheContextKey {}, cache ), nil
2176+ }
2177+ rows , err := s .pg .QueryContext (ctx , `
2178+ SELECT id, machine, owner_marker
2179+ FROM sessions
2180+ WHERE id = ANY($1)` , unique )
2181+ if err != nil {
2182+ return ctx , fmt .Errorf ("preloading pg session owners: %w" , err )
2183+ }
2184+ defer rows .Close ()
2185+ for rows .Next () {
2186+ var id , machine string
2187+ var ownerMarker sql.NullString
2188+ if err := rows .Scan (& id , & machine , & ownerMarker ); err != nil {
2189+ return ctx , fmt .Errorf ("scanning pg session owner: %w" , err )
2190+ }
2191+ cache .entries [id ] = pgSessionOwnerRecord {
2192+ machine : machine , ownerMarker : ownerMarker .String , exists : true ,
2193+ }
2194+ }
2195+ if err := rows .Err (); err != nil {
2196+ return ctx , fmt .Errorf ("iterating pg session owners: %w" , err )
2197+ }
2198+ return context .WithValue (ctx , pgSessionOwnerCacheContextKey {}, cache ), nil
2199+ }
2200+
20792201// pgSessionOwner returns the machine and owner_marker of a PG session row, and
20802202// whether it exists. owner_marker is empty for legacy rows pushed before the
20812203// marker model.
20822204func (s * Sync ) pgSessionOwner (
20832205 ctx context.Context ,
20842206 id string ,
20852207) (string , string , bool , error ) {
2208+ cache , _ := ctx .Value (pgSessionOwnerCacheContextKey {}).(* pgSessionOwnerCache )
2209+ if cache != nil {
2210+ if record , ok := cache .get (id ); ok {
2211+ return record .machine , record .ownerMarker , record .exists , nil
2212+ }
2213+ }
20862214 var machine string
20872215 var ownerMarker sql.NullString
20882216 err := s .pg .QueryRowContext (ctx ,
@@ -2091,13 +2219,21 @@ func (s *Sync) pgSessionOwner(
20912219 ).Scan (& machine , & ownerMarker )
20922220 if err != nil {
20932221 if errors .Is (err , sql .ErrNoRows ) {
2222+ if cache != nil {
2223+ cache .put (id , pgSessionOwnerRecord {})
2224+ }
20942225 return "" , "" , false , nil
20952226 }
20962227 return "" , "" , false , fmt .Errorf (
20972228 "reading pg session owner for %s: %w" ,
20982229 id , err ,
20992230 )
21002231 }
2232+ if cache != nil {
2233+ cache .put (id , pgSessionOwnerRecord {
2234+ machine : machine , ownerMarker : ownerMarker .String , exists : true ,
2235+ })
2236+ }
21012237 return machine , ownerMarker .String , true , nil
21022238}
21032239
0 commit comments