diff --git a/go.mod b/go.mod index e60ea9c..67bfaf7 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/ardanlabs/conf/v3 v3.1.7 github.com/cenkalti/backoff/v4 v4.2.1 github.com/hashicorp/go-retryablehttp v0.7.5 - github.com/neo4j/neo4j-go-driver/v5 v5.15.0 + github.com/neo4j/neo4j-go-driver/v5 v5.16.0 github.com/rs/zerolog v1.31.0 github.com/stretchr/testify v1.8.4 golang.org/x/time v0.5.0 diff --git a/go.sum b/go.sum index 7d24ee8..81adf21 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/neo4j/neo4j-go-driver/v5 v5.15.0 h1:oqJZB1p2DE153RjfFbVGQiSDXqMCMEQnrZW+ZI86o58= -github.com/neo4j/neo4j-go-driver/v5 v5.15.0/go.mod h1:Vff8OwT7QpLm7L2yYr85XNWe9Rbqlbeb9asNXJTHO4k= +github.com/neo4j/neo4j-go-driver/v5 v5.16.0 h1:m3ZTjqulwob5HBysu5QdSvFB1+6x8xC9I3hC7yzcN6A= +github.com/neo4j/neo4j-go-driver/v5 v5.16.0/go.mod h1:Vff8OwT7QpLm7L2yYr85XNWe9Rbqlbeb9asNXJTHO4k= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= diff --git a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/auth/auth.go b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/auth/auth.go index aff2bd1..4c0b1ae 100644 --- a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/auth/auth.go +++ b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/auth/auth.go @@ -19,12 +19,14 @@ package auth import ( "context" + "reflect" + "time" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/db" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/auth" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/collections" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/racing" - "reflect" - "time" + itime "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/time" ) // TokenManager is an interface for components that can provide auth tokens. @@ -63,7 +65,6 @@ type neo4jAuthTokenManager struct { token *auth.Token expiration *time.Time mutex racing.Mutex - now *func() time.Time handledSecurityCodes collections.Set[string] } @@ -73,7 +74,7 @@ func (m *neo4jAuthTokenManager) GetAuthToken(ctx context.Context) (auth.Token, e "could not acquire lock in time when getting token in neo4jAuthTokenManager") } defer m.mutex.Unlock() - if m.token == nil || m.expiration != nil && (*m.now)().After(*m.expiration) { + if m.token == nil || m.expiration != nil && itime.Now().After(*m.expiration) { token, expiration, err := m.provider(ctx) if err != nil { return auth.Token{}, err @@ -111,11 +112,9 @@ func (m *neo4jAuthTokenManager) HandleSecurityException(ctx context.Context, tok // The provider function must only ever return auth information belonging to the same identity. // Switching identities is undefined behavior. func BasicTokenManager(provider authTokenProvider) TokenManager { - now := time.Now return &neo4jAuthTokenManager{ provider: wrapWithNilExpiration(provider), mutex: racing.NewMutex(), - now: &now, handledSecurityCodes: collections.NewSet([]string{ "Neo.ClientError.Security.Unauthorized", }), @@ -135,11 +134,9 @@ func BasicTokenManager(provider authTokenProvider) TokenManager { // The provider function must only ever return auth information belonging to the same identity. // Switching identities is undefined behavior. func BearerTokenManager(provider authTokenWithExpirationProvider) TokenManager { - now := time.Now return &neo4jAuthTokenManager{ provider: provider, mutex: racing.NewMutex(), - now: &now, handledSecurityCodes: collections.NewSet([]string{ "Neo.ClientError.Security.TokenExpired", "Neo.ClientError.Security.Unauthorized", diff --git a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/config.go b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/config.go index 51b3f0c..f438d0f 100644 --- a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/config.go +++ b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/config.go @@ -19,6 +19,7 @@ package neo4j import ( "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/pool" "github.com/neo4j/neo4j-go-driver/v5/neo4j/notifications" "math" "net/url" @@ -41,6 +42,7 @@ func defaultConfig() *Config { MaxConnectionPoolSize: 100, MaxConnectionLifetime: 1 * time.Hour, ConnectionAcquisitionTimeout: 1 * time.Minute, + ConnectionLivenessCheckTimeout: pool.DefaultConnectionLivenessCheckTimeout, SocketConnectTimeout: 5 * time.Second, SocketKeepalive: true, RootCAs: nil, @@ -77,6 +79,11 @@ func validateAndNormaliseConfig(config *Config) error { config.ConnectionAcquisitionTimeout = -1 } + // Connection Liveness Check Timeout + if config.ConnectionLivenessCheckTimeout < 0 { + return &UsageError{Message: "Connection liveness check timeout cannot be smaller than 0"} + } + // Socket Connect Timeout if config.SocketConnectTimeout < 0 { config.SocketConnectTimeout = 0 diff --git a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/config/driver.go b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/config/driver.go index 3ca5851..4cdf470 100644 --- a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/config/driver.go +++ b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/config/driver.go @@ -103,6 +103,21 @@ type Config struct { // // default: 1 * time.Minute ConnectionAcquisitionTimeout time.Duration + // ConnectionLivenessCheckTimeout sets the timeout duration for idle connections in the pool. + // Connections idle longer than this timeout will be tested for liveliness before reuse. A low timeout value + // can increase network requests when acquiring a connection, impacting performance. Conversely, a high + // timeout may result in using connections that are no longer active, causing exceptions in your application. + // These exceptions typically resolve with a retry or using a driver API with automatic + // retries, assuming the database is operational. + // + // The parameter balances the likelihood of encountering connection issues against performance. + // Typically, adjustment of this parameter is not necessary. + // + // By default, no liveliness check is performed. A value of 0 ensures connections are always tested for + // validity, and negative values are not permitted. + // + // default: pool.DefaultConnectionLivenessCheckTimeout + ConnectionLivenessCheckTimeout time.Duration // Connect timeout that will be set on underlying sockets. Values less than // or equal to 0 results in no timeout being applied. // diff --git a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/driver_with_context.go b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/driver_with_context.go index 31cf7cb..f97fdd0 100644 --- a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/driver_with_context.go +++ b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/driver_with_context.go @@ -1,3 +1,5 @@ +// Package neo4j provides required functionality to connect and execute statements against a Neo4j Database. + /* * Copyright (c) "Neo4j" * Neo4j Sweden AB [https://neo4j.com] @@ -15,25 +17,22 @@ * limitations under the License. */ -// Package neo4j provides required functionality to connect and execute statements against a Neo4j Database. package neo4j import ( "context" "fmt" "github.com/neo4j/neo4j-go-driver/v5/neo4j/auth" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/connector" idb "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/db" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/errorutil" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/pool" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/racing" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/router" "github.com/neo4j/neo4j-go-driver/v5/neo4j/log" "net/url" "strings" "sync" - "time" - - "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/connector" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/pool" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/router" ) // AccessMode defines modes that routing driver decides to which cluster member @@ -145,7 +144,7 @@ func NewDriverWithContext(target string, auth auth.TokenManager, configurers ... return nil, err } - d := driverWithContext{target: parsed, mut: racing.NewMutex(), now: time.Now, auth: auth} + d := driverWithContext{target: parsed, mut: racing.NewMutex(), auth: auth} routing := true d.connector.Network = "tcp" @@ -220,10 +219,9 @@ func NewDriverWithContext(target string, auth auth.TokenManager, configurers ... d.connector.Log = d.log d.connector.RoutingContext = routingContext d.connector.Config = d.config - d.connector.Now = &d.now // Let the pool use the same log ID as the driver to simplify log reading. - d.pool = pool.New(d.config, d.connector.Connect, d.log, d.logId, &d.now) + d.pool = pool.New(d.config, d.connector.Connect, d.log, d.logId) if !routing { d.router = &directRouter{address: address} @@ -241,7 +239,15 @@ func NewDriverWithContext(target string, auth auth.TokenManager, configurers ... } } // Let the router use the same log ID as the driver to simplify log reading. - d.router = router.New(address, routersResolver, routingContext, d.pool, d.log, d.logId, &d.now) + d.router = router.New( + address, + routersResolver, + routingContext, + d.pool, + d.config.ConnectionLivenessCheckTimeout, + d.log, + d.logId, + ) } d.pool.SetRouter(d.router) @@ -324,7 +330,6 @@ type driverWithContext struct { // this is *not* used by default by user-created session (see NewSession) executeQueryBookmarkManager BookmarkManager auth auth.TokenManager - now func() time.Time } func (d *driverWithContext) Target() url.URL { @@ -360,7 +365,7 @@ func (d *driverWithContext) NewSession(ctx context.Context, config SessionConfig return &erroredSessionWithContext{ err: &UsageError{Message: "Trying to create session on closed driver"}} } - return newSessionWithContext(d.config, config, d.router, d.pool, d.log, reAuthToken, &d.now) + return newSessionWithContext(d.config, config, d.router, d.pool, d.log, reAuthToken) } func (d *driverWithContext) VerifyConnectivity(ctx context.Context) error { @@ -535,7 +540,7 @@ func ExecuteQuery[T any]( if err != nil { return *new(T), err } - result, err := txFunction(ctx, executeQueryCallback(ctx, query, parameters, newResultTransformer)) + result, err := txFunction(ctx, executeQueryCallback(ctx, query, parameters, newResultTransformer), configuration.TransactionConfigurers...) if err != nil { return *new(T), err } @@ -660,13 +665,21 @@ func ExecuteQueryWithBoltLogger(boltLogger log.BoltLogger) ExecuteQueryConfigura } } +// ExecuteQueryWithTransactionConfig configures DriverWithContext.ExecuteQuery with additional transaction configuration. +func ExecuteQueryWithTransactionConfig(configurers ...func(*TransactionConfig)) ExecuteQueryConfigurationOption { + return func(configuration *ExecuteQueryConfiguration) { + configuration.TransactionConfigurers = configurers + } +} + // ExecuteQueryConfiguration holds all the possible configuration settings for DriverWithContext.ExecuteQuery type ExecuteQueryConfiguration struct { - Routing RoutingControl - ImpersonatedUser string - Database string - BookmarkManager BookmarkManager - BoltLogger log.BoltLogger + Routing RoutingControl + ImpersonatedUser string + Database string + BookmarkManager BookmarkManager + BoltLogger log.BoltLogger + TransactionConfigurers []func(*TransactionConfig) } // RoutingControl specifies how the query executed by DriverWithContext.ExecuteQuery is to be routed diff --git a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/driver_with_context_testkit.go b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/driver_with_context_testkit.go index 298ff17..5e645bc 100644 --- a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/driver_with_context_testkit.go +++ b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/driver_with_context_testkit.go @@ -1,4 +1,4 @@ -//go:build internal_testkit +//go:build internal_testkit && internal_time_mock /* * Copyright (c) "Neo4j" @@ -25,22 +25,12 @@ import ( idb "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/db" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/errorutil" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/router" + itime "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/time" "github.com/neo4j/neo4j-go-driver/v5/neo4j/log" - "time" ) type RoutingTable = idb.RoutingTable -func SetTimer(d DriverWithContext, timer func() time.Time) { - driver := d.(*driverWithContext) - driver.now = timer -} - -func ResetTime(d DriverWithContext) { - driver := d.(*driverWithContext) - driver.now = time.Now -} - func ForceRoutingTableUpdate(d DriverWithContext, database string, bookmarks []string, logger log.BoltLogger) error { driver := d.(*driverWithContext) ctx := context.Background() @@ -70,3 +60,8 @@ func GetRoutingTable(d DriverWithContext, database string) (*RoutingTable, error table := router.GetTable(database) return table, nil } + +var Now = itime.Now +var FreezeTime = itime.FreezeTime +var TickTime = itime.TickTime +var UnfreezeTime = itime.UnfreezeTime diff --git a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/bolt/bolt3.go b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/bolt/bolt3.go index a83951e..0ff8e77 100644 --- a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/bolt/bolt3.go +++ b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/bolt/bolt3.go @@ -26,6 +26,7 @@ import ( idb "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/db" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/errorutil" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/telemetry" + itime "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/time" "net" "reflect" "time" @@ -95,18 +96,16 @@ type bolt3 struct { authManager auth.TokenManager resetAuth bool errorListener ConnectionErrorListener - now *func() time.Time } func NewBolt3( serverName string, conn net.Conn, errorListener ConnectionErrorListener, - timer *func() time.Time, logger log.Logger, boltLog log.BoltLogger, ) *bolt3 { - now := (*timer)() + now := itime.Now() b := &bolt3{ state: bolt3_unauthorized, conn: conn, @@ -123,7 +122,6 @@ func NewBolt3( idleDate: now, log: logger, errorListener: errorListener, - now: timer, } b.out = &outgoing{ chunker: newChunker(), @@ -166,7 +164,7 @@ func (b *bolt3) receiveMsg(ctx context.Context) any { b.state = bolt3_dead return nil } - b.idleDate = (*b.now)() + b.idleDate = itime.Now() return msg } diff --git a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/bolt/bolt4.go b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/bolt/bolt4.go index 48b1949..f5a77bd 100644 --- a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/bolt/bolt4.go +++ b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/bolt/bolt4.go @@ -21,18 +21,19 @@ import ( "context" "errors" "fmt" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/auth" - iauth "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/auth" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/collections" - idb "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/db" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/errorutil" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/telemetry" "net" "reflect" "time" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/auth" "github.com/neo4j/neo4j-go-driver/v5/neo4j/db" + iauth "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/auth" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/collections" + idb "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/db" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/errorutil" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/packstream" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/telemetry" + itime "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/time" "github.com/neo4j/neo4j-go-driver/v5/neo4j/log" ) @@ -111,18 +112,16 @@ type bolt4 struct { authManager auth.TokenManager resetAuth bool errorListener ConnectionErrorListener - now *func() time.Time } func NewBolt4( serverName string, conn net.Conn, errorListener ConnectionErrorListener, - timer *func() time.Time, logger log.Logger, boltLog log.BoltLogger, ) *bolt4 { - now := (*timer)() + now := itime.Now() b := &bolt4{ state: bolt4_unauthorized, conn: conn, @@ -133,7 +132,6 @@ func NewBolt4( streams: openstreams{}, lastQid: -1, errorListener: errorListener, - now: timer, } b.queue = newMessageQueue( conn, @@ -1135,7 +1133,7 @@ func (b *bolt4) expectedSuccessHandler(onSuccess func(*success)) responseHandler } func (b *bolt4) onNextMessage() { - b.idleDate = (*b.now)() + b.idleDate = itime.Now() } func (b *bolt4) onFailure(ctx context.Context, failure *db.Neo4jError) { diff --git a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/bolt/bolt5.go b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/bolt/bolt5.go index 67b170a..db054a0 100644 --- a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/bolt/bolt5.go +++ b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/bolt/bolt5.go @@ -21,18 +21,19 @@ import ( "context" "errors" "fmt" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/auth" - iauth "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/auth" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/boltagent" - idb "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/db" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/errorutil" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/telemetry" "net" "reflect" "time" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/auth" "github.com/neo4j/neo4j-go-driver/v5/neo4j/db" + iauth "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/auth" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/boltagent" + idb "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/db" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/errorutil" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/packstream" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/telemetry" + itime "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/time" "github.com/neo4j/neo4j-go-driver/v5/neo4j/log" ) @@ -113,7 +114,6 @@ type bolt5 struct { authManager auth.TokenManager resetAuth bool errorListener ConnectionErrorListener - now *func() time.Time telemetryEnabled bool } @@ -121,11 +121,10 @@ func NewBolt5( serverName string, conn net.Conn, errorListener ConnectionErrorListener, - timer *func() time.Time, logger log.Logger, boltLog log.BoltLogger, ) *bolt5 { - now := (*timer)() + now := itime.Now() b := &bolt5{ state: bolt5Unauthorized, conn: conn, @@ -136,7 +135,6 @@ func NewBolt5( streams: openstreams{}, lastQid: -1, errorListener: errorListener, - now: timer, } b.queue = newMessageQueue( conn, @@ -1132,7 +1130,7 @@ func (b *bolt5) onCommitSuccess(commitSuccess *success) { } func (b *bolt5) onNextMessage() { - b.idleDate = (*b.now)() + b.idleDate = itime.Now() } func (b *bolt5) onFailure(ctx context.Context, failure *db.Neo4jError) { diff --git a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/bolt/bolt_logging.go b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/bolt/bolt_logging.go index aceb787..701dd22 100644 --- a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/bolt/bolt_logging.go +++ b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/bolt/bolt_logging.go @@ -25,26 +25,27 @@ import ( type loggableDictionary map[string]any -func (d loggableDictionary) String() string { - if credentials, ok := d["credentials"]; ok { - d["credentials"] = "" - defer func() { - d["credentials"] = credentials - }() +func copyAndSanitizeDictionary[T any | string](in map[string]T) map[string]T { + out := make(map[string]T, len(in)) + for k, v := range in { + if k == "credentials" { + var redacted any = "" + out[k] = redacted.(T) + } else { + out[k] = v + } } - return serializeTrace(d) + return out +} + +func (d loggableDictionary) String() string { + return serializeTrace(copyAndSanitizeDictionary(d)) } type loggableStringDictionary map[string]string func (sd loggableStringDictionary) String() string { - if credentials, ok := sd["credentials"]; ok { - sd["credentials"] = "" - defer func() { - sd["credentials"] = credentials - }() - } - return serializeTrace(sd) + return serializeTrace(copyAndSanitizeDictionary(sd)) } type loggableList []any diff --git a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/bolt/connect.go b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/bolt/connect.go index d48bb1a..9036d11 100644 --- a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/bolt/connect.go +++ b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/bolt/connect.go @@ -21,12 +21,11 @@ package bolt import ( "context" "fmt" + "net" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/db" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/errorutil" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/racing" - "net" - "time" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/log" ) @@ -56,7 +55,7 @@ func Connect(ctx context.Context, logger log.Logger, boltLogger log.BoltLogger, notificationConfig db.NotificationConfig, - timer *func() time.Time) (db.Connection, error) { +) (db.Connection, error) { // Perform Bolt handshake to negotiate version // Send handshake to server handshake := []byte{ @@ -93,11 +92,11 @@ func Connect(ctx context.Context, var boltConn db.Connection switch major { case 3: - boltConn = NewBolt3(serverName, conn, errorListener, timer, logger, boltLogger) + boltConn = NewBolt3(serverName, conn, errorListener, logger, boltLogger) case 4: - boltConn = NewBolt4(serverName, conn, errorListener, timer, logger, boltLogger) + boltConn = NewBolt4(serverName, conn, errorListener, logger, boltLogger) case 5: - boltConn = NewBolt5(serverName, conn, errorListener, timer, logger, boltLogger) + boltConn = NewBolt5(serverName, conn, errorListener, logger, boltLogger) case 0: return nil, fmt.Errorf("server did not accept any of the requested Bolt versions (%#v)", versions) default: diff --git a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/connector/connector.go b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/connector/connector.go index 8e86d87..2477adc 100644 --- a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/connector/connector.go +++ b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/connector/connector.go @@ -22,14 +22,14 @@ import ( "context" "crypto/tls" "errors" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/db" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/errorutil" "io" "net" "time" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/bolt" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/db" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/errorutil" "github.com/neo4j/neo4j-go-driver/v5/neo4j/log" ) @@ -41,7 +41,6 @@ type Connector struct { Network string Config *config.Config SupplyConnection func(context.Context, string) (net.Conn, error) - Now *func() time.Time } func (c Connector) Connect( @@ -87,7 +86,6 @@ func (c Connector) Connect( c.Log, boltLogger, notificationConfig, - c.Now, ) if err != nil { return nil, err @@ -122,7 +120,6 @@ func (c Connector) Connect( c.Log, boltLogger, notificationConfig, - c.Now, ) if err != nil { return nil, err diff --git a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/metadata/metadata.go b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/metadata/metadata.go index b81901d..f26a751 100644 --- a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/metadata/metadata.go +++ b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/metadata/metadata.go @@ -17,4 +17,4 @@ package metadata -const DriverVersion = "5.15.0" +const DriverVersion = "5.16.0" diff --git a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/pool/pool.go b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/pool/pool.go index fe9f947..339465c 100644 --- a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/pool/pool.go +++ b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/pool/pool.go @@ -23,22 +23,23 @@ package pool import ( "container/list" "context" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/db" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/bolt" - idb "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/db" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/errorutil" "math" "sort" "sync" "time" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/db" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/bolt" + idb "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/db" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/errorutil" + itime "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/time" "github.com/neo4j/neo4j-go-driver/v5/neo4j/log" ) -// DefaultLivenessCheckThreshold disables the liveness check of connections -// Liveness checks are performed before a connection is deemed idle enough to be reset -const DefaultLivenessCheckThreshold = math.MaxInt64 +// DefaultConnectionLivenessCheckTimeout disables the liveness check of connections. +// Liveness checks are performed before a connection is deemed idle enough to be reset. +const DefaultConnectionLivenessCheckTimeout = math.MaxInt64 type Connect func(context.Context, string, *idb.ReAuthToken, bolt.ConnectionErrorListener, log.BoltLogger) (idb.Connection, error) @@ -60,7 +61,6 @@ type Pool struct { serversMut sync.Mutex queueMut sync.Mutex queue list.List - now *func() time.Time closed bool log log.Logger logId string @@ -71,7 +71,7 @@ type serverPenalty struct { penalty uint32 } -func New(config *config.Config, connect Connect, logger log.Logger, logId string, now *func() time.Time) *Pool { +func New(config *config.Config, connect Connect, logger log.Logger, logId string) *Pool { // Means infinite life, simplifies checking later on p := &Pool{ @@ -81,7 +81,6 @@ func New(config *config.Config, connect Connect, logger log.Logger, logId string servers: make(map[string]*server), serversMut: sync.Mutex{}, queueMut: sync.Mutex{}, - now: now, logId: logId, log: logger, } @@ -137,7 +136,7 @@ func (p *Pool) getServers() map[string]*server { func (p *Pool) CleanUp(ctx context.Context) { p.serversMut.Lock() defer p.serversMut.Unlock() - now := (*p.now)() + now := itime.Now() for n, s := range p.servers { s.removeIdleOlderThan(ctx, now, p.config.MaxConnectionLifetime) if s.size() == 0 && !s.hasFailedConnect(now) { @@ -146,17 +145,13 @@ func (p *Pool) CleanUp(ctx context.Context) { } } -func (p *Pool) Now() time.Time { - return (*p.now)() -} - func (p *Pool) getPenaltiesForServers(ctx context.Context, serverNames []string) []serverPenalty { p.serversMut.Lock() defer p.serversMut.Unlock() // Retrieve penalty for each server penalties := make([]serverPenalty, len(serverNames)) - now := (*p.now)() + now := itime.Now() for i, n := range serverNames { s := p.servers[n] penalties[i].name = n @@ -171,38 +166,28 @@ func (p *Pool) getPenaltiesForServers(ctx context.Context, serverNames []string) return penalties } -func (p *Pool) tryAnyIdle(ctx context.Context, serverNames []string, idlenessThreshold time.Duration, auth *idb.ReAuthToken, logger log.BoltLogger) (idb.Connection, error) { +func (p *Pool) anyHasCapacity(serverNames []string) bool { p.serversMut.Lock() - var unlock = new(sync.Once) - defer unlock.Do(p.serversMut.Unlock) -serverLoop: + defer p.serversMut.Unlock() for _, serverName := range serverNames { - for { - srv := p.servers[serverName] - if srv != nil { - conn := srv.getIdle() - if conn == nil { - continue serverLoop - } - unlock.Do(p.serversMut.Unlock) - healthy, err := srv.healthCheck(ctx, conn, idlenessThreshold, auth, logger) - if healthy { - return conn, nil - } - p.unreg(ctx, serverName, conn, p.Now()) - if err != nil { - p.log.Debugf(log.Pool, p.logId, "Health check failed for %s: %s", serverName, err) - return nil, err - } - p.serversMut.Lock() - *unlock = sync.Once{} + srv := p.servers[serverName] + if srv != nil { + if srv.numIdle() > 0 || srv.size() < p.config.MaxConnectionPoolSize { + return true } } } - return nil, nil + return false } -func (p *Pool) Borrow(ctx context.Context, getServerNames func() []string, wait bool, boltLogger log.BoltLogger, idlenessThreshold time.Duration, auth *idb.ReAuthToken) (idb.Connection, error) { +func (p *Pool) Borrow( + ctx context.Context, + getServerNames func() []string, + wait bool, + boltLogger log.BoltLogger, + idlenessTimeout time.Duration, + auth *idb.ReAuthToken, +) (idb.Connection, error) { for { if p.closed { return nil, &errorutil.PoolClosed{} @@ -223,7 +208,7 @@ func (p *Pool) Borrow(ctx context.Context, getServerNames func() []string, wait var conn idb.Connection for _, s := range penalties { - conn, err = p.tryBorrow(ctx, s.name, boltLogger, idlenessThreshold, auth) + conn, err = p.tryBorrow(ctx, s.name, boltLogger, idlenessTimeout, auth) if conn != nil { return conn, nil } @@ -249,17 +234,13 @@ func (p *Pool) Borrow(ctx context.Context, getServerNames func() []string, wait // Wait for a matching connection to be returned from another thread. p.queueMut.Lock() - // Ok, now that we own the queue we can add the item there but between getting the lock - // and above check for an existing connection another thread might have returned a connection - // so check again to avoid potentially starving this thread. - conn, err = p.tryAnyIdle(ctx, serverNames, idlenessThreshold, auth, boltLogger) - if err != nil { - p.queueMut.Unlock() - return nil, err - } - if conn != nil { + // By owning the queue lock, we are guaranteed that every call to Return from now on, until we release the + // lock, will notify us (or another waiter). To avoid starving this thread, we have to check once more whether + // any call to Return between checking for capacity above and acquiring the lock happened. In that case, we + // are no longer guaranteed to be notified, so we have to start over. + if p.anyHasCapacity(serverNames) { p.queueMut.Unlock() - return conn, nil + continue } // Add a waiting request to the queue and unlock the queue to let other threads that return // their connections access the queue. @@ -277,6 +258,17 @@ func (p *Pool) Borrow(ctx context.Context, getServerNames func() []string, wait case <-ctx.Done(): p.queueMut.Lock() p.queue.Remove(e) + if len(q.wakeup) == 1 { + // We got notified, but are no longer interested. + // Ask the next waiter. + if e := p.queue.Front(); e != nil { + queuedRequest := e.Value.(*qitem) + p.queue.Remove(e) + queuedRequest.wakeup <- true + } + p.queueMut.Unlock() + continue + } p.queueMut.Unlock() p.log.Warnf(log.Pool, p.logId, "Borrow time-out") return nil, &errorutil.PoolTimeout{Err: ctx.Err(), Servers: serverNames} @@ -284,10 +276,13 @@ func (p *Pool) Borrow(ctx context.Context, getServerNames func() []string, wait } } -func (p *Pool) tryBorrow(ctx context.Context, serverName string, boltLogger log.BoltLogger, idlenessThreshold time.Duration, auth *idb.ReAuthToken) (idb.Connection, error) { - // For now, lock complete servers map to avoid over connecting but with the downside - // that long connect times will block connects to other servers as well. To fix this - // we would need to add a pending connect to the server and lock per server. +func (p *Pool) tryBorrow( + ctx context.Context, + serverName string, + boltLogger log.BoltLogger, + idlenessTimeout time.Duration, + auth *idb.ReAuthToken, +) (idb.Connection, error) { p.serversMut.Lock() var unlock = new(sync.Once) defer unlock.Do(p.serversMut.Unlock) @@ -304,11 +299,11 @@ func (p *Pool) tryBorrow(ctx context.Context, serverName string, boltLogger log. break } unlock.Do(p.serversMut.Unlock) - healthy, err := srv.healthCheck(ctx, connection, idlenessThreshold, auth, boltLogger) + healthy, err := srv.healthCheck(ctx, connection, idlenessTimeout, auth, boltLogger) if healthy { return connection, nil } - p.unreg(ctx, serverName, connection, p.Now()) + p.unreg(ctx, serverName, connection, itime.Now()) if err != nil { p.log.Debugf(log.Pool, p.logId, "Health check failed for %s: %s", serverName, err) return nil, err @@ -337,7 +332,7 @@ func (p *Pool) tryBorrow(ctx context.Context, serverName string, boltLogger log. p.log.Warnf(log.Pool, p.logId, "Failed to connect to %s: %s", serverName, err) // FeatureNotSupportedError is not the server fault, don't penalize it if _, ok := err.(*db.FeatureNotSupportedError); !ok { - srv.notifyFailedConnect((*p.now)()) + srv.notifyFailedConnect(itime.Now()) } return nil, err } @@ -351,10 +346,10 @@ func (p *Pool) tryBorrow(ctx context.Context, serverName string, boltLogger log. func (p *Pool) unreg(ctx context.Context, serverName string, c idb.Connection, now time.Time) { p.serversMut.Lock() defer p.serversMut.Unlock() - p.unregUnlocked(ctx, serverName, c, now) + p.unregLocked(ctx, serverName, c, now) } -func (p *Pool) unregUnlocked(ctx context.Context, serverName string, c idb.Connection, now time.Time) { +func (p *Pool) unregLocked(ctx context.Context, serverName string, c idb.Connection, now time.Time) { defer func() { // Close connection in another thread to avoid potential long blocking operation during close. go c.Close(ctx) @@ -397,7 +392,7 @@ func (p *Pool) Return(ctx context.Context, c idb.Connection) { // If the connection is dead, remove all other idle connections on the same server that older // or of the same age as the dead connection, otherwise perform normal cleanup of old connections maxAge := p.config.MaxConnectionLifetime - now := (*p.now)() + now := itime.Now() age := now.Sub(c.Birthdate()) if !isAlive { // Since this connection has died all other connections that connected before this one @@ -441,7 +436,8 @@ func (p *Pool) Return(ctx context.Context, c idb.Connection) { // Check if there is anyone in the queue waiting for a connection to this server. p.queueMut.Lock() - for e := p.queue.Front(); e != nil; e = e.Next() { + + if e := p.queue.Front(); e != nil { queuedRequest := e.Value.(*qitem) p.queue.Remove(e) queuedRequest.wakeup <- true diff --git a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/pool/server.go b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/pool/server.go index 5ae1402..3b0b605 100644 --- a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/pool/server.go +++ b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/pool/server.go @@ -20,10 +20,12 @@ package pool import ( "container/list" "context" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/db" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/log" "sync/atomic" "time" + + "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/db" + itime "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/time" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/log" ) // Represents a server with a number of connections that either is in use (borrowed) or @@ -66,22 +68,22 @@ func (s *server) getIdle() db.Connection { func (s *server) healthCheck( ctx context.Context, connection db.Connection, - idlenessThreshold time.Duration, + idlenessTimeout time.Duration, auth *db.ReAuthToken, boltLogger log.BoltLogger) (healthy bool, _ error) { connection.SetBoltLogger(boltLogger) - if time.Since(connection.IdleDate()) > idlenessThreshold { + if itime.Since(connection.IdleDate()) > idlenessTimeout { connection.ForceReset(ctx) if !connection.IsAlive() { - return false, nil + return false, ctx.Err() } } if err := connection.ReAuth(ctx, auth); err != nil { return false, err } if !connection.IsAlive() { - return false, nil + return false, ctx.Err() } // Update round-robin counter every time we give away a connection and keep track // of our own round-robin index diff --git a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/retry/state.go b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/retry/state.go index 3f6e091..1fd5c45 100644 --- a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/retry/state.go +++ b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/retry/state.go @@ -22,11 +22,12 @@ import ( "context" "errors" "fmt" - idb "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/db" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/errorutil" "time" "github.com/neo4j/neo4j-go-driver/v5/neo4j/db" + idb "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/db" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/errorutil" + itime "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/time" "github.com/neo4j/neo4j-go-driver/v5/neo4j/log" ) @@ -36,7 +37,6 @@ type State struct { Log log.Logger LogName string LogId string - Now *func() time.Time Sleep func(time.Duration) Throttle Throttler MaxDeadConnections int @@ -68,7 +68,7 @@ func (s *State) OnFailure(_ context.Context, err error, conn idb.Connection, isC func (s *State) Continue() bool { if s.start.IsZero() { - s.start = (*s.Now)() + s.start = itime.Now() } if len(s.Errs) == 0 { @@ -80,7 +80,7 @@ func (s *State) Continue() bool { return false } - if (*s.Now)().Sub(s.start) > s.MaxTransactionRetryTime { + if itime.Since(s.start) > s.MaxTransactionRetryTime { s.Errs = []error{&errorutil.TransactionExecutionLimit{ Cause: fmt.Sprintf("timeout (exceeded max retry time: %s)", s.MaxTransactionRetryTime.String()), Errors: s.Errs, diff --git a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/router/readtable.go b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/router/readtable.go index bf6785c..8efa1c1 100644 --- a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/router/readtable.go +++ b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/router/readtable.go @@ -19,9 +19,10 @@ package router import ( "context" + "time" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/db" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/errorutil" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/pool" "github.com/neo4j/neo4j-go-driver/v5/neo4j/log" ) @@ -32,6 +33,7 @@ func readTable( connectionPool Pool, routers []string, routerContext map[string]string, + idlenessTimeout time.Duration, bookmarks []string, database, impersonatedUser string, @@ -46,7 +48,7 @@ func readTable( // another db. for _, router := range routers { var conn db.Connection - if conn, err = connectionPool.Borrow(ctx, getStaticServer(router), true, boltLogger, pool.DefaultLivenessCheckThreshold, auth); err != nil { + if conn, err = connectionPool.Borrow(ctx, getStaticServer(router), true, boltLogger, idlenessTimeout, auth); err != nil { // Check if failed due to context timing out if ctx.Err() != nil { return nil, wrapError(router, ctx.Err()) diff --git a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/router/router.go b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/router/router.go index fcddeda..a257221 100644 --- a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/router/router.go +++ b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/router/router.go @@ -27,6 +27,7 @@ import ( "sync" "time" + itime "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/time" "github.com/neo4j/neo4j-go-driver/v5/neo4j/log" ) @@ -40,41 +41,41 @@ type databaseRouter struct { // Router is thread safe type Router struct { - routerContext map[string]string - pool Pool - dbRouters map[string]*databaseRouter - updating map[string][]chan struct{} - dbRoutersMut sync.Mutex - now *func() time.Time - sleep func(time.Duration) - rootRouter string - getRouters func() []string - log log.Logger - logId string + routerContext map[string]string + pool Pool + idlenessTimeout time.Duration + dbRouters map[string]*databaseRouter + updating map[string][]chan struct{} + dbRoutersMut sync.Mutex + sleep func(time.Duration) + rootRouter string + getRouters func() []string + log log.Logger + logId string } type Pool interface { // Borrow acquires a connection from the provided list of servers // If all connections are busy and the pool is full, calls to Borrow may wait for a connection to become idle - // If a connection has been idle for longer than idlenessThreshold, it will be reset + // If a connection has been idle for longer than idlenessTimeout, it will be reset // to check if it's still alive. - Borrow(ctx context.Context, getServers func() []string, wait bool, boltLogger log.BoltLogger, idlenessThreshold time.Duration, auth *idb.ReAuthToken) (idb.Connection, error) + Borrow(ctx context.Context, getServers func() []string, wait bool, boltLogger log.BoltLogger, idlenessTimeout time.Duration, auth *idb.ReAuthToken) (idb.Connection, error) Return(ctx context.Context, c idb.Connection) } -func New(rootRouter string, getRouters func() []string, routerContext map[string]string, pool Pool, logger log.Logger, logId string, timer *func() time.Time) *Router { +func New(rootRouter string, getRouters func() []string, routerContext map[string]string, pool Pool, idlenessTimeout time.Duration, logger log.Logger, logId string) *Router { r := &Router{ - rootRouter: rootRouter, - getRouters: getRouters, - routerContext: routerContext, - pool: pool, - dbRouters: make(map[string]*databaseRouter), - updating: make(map[string][]chan struct{}), - dbRoutersMut: sync.Mutex{}, - now: timer, - sleep: time.Sleep, - log: logger, - logId: logId, + rootRouter: rootRouter, + getRouters: getRouters, + routerContext: routerContext, + pool: pool, + idlenessTimeout: idlenessTimeout, + dbRouters: make(map[string]*databaseRouter), + updating: make(map[string][]chan struct{}), + dbRoutersMut: sync.Mutex{}, + sleep: time.Sleep, + log: logger, + logId: logId, } r.log.Infof(log.Router, r.logId, "Created {context: %v}", routerContext) return r @@ -98,7 +99,7 @@ func (r *Router) readTable( if dbRouter != nil && len(dbRouter.table.Routers) > 0 { routers := dbRouter.table.Routers r.log.Infof(log.Router, r.logId, "Reading routing table for '%s' from previously known routers: %v", database, routers) - table, err = readTable(ctx, r.pool, routers, r.routerContext, bookmarks, database, impersonatedUser, auth, boltLogger) + table, err = readTable(ctx, r.pool, routers, r.routerContext, r.idlenessTimeout, bookmarks, database, impersonatedUser, auth, boltLogger) } if errorutil.IsFatalDuringDiscovery(err) { r.log.Error(log.Router, r.logId, err) @@ -108,7 +109,7 @@ func (r *Router) readTable( // Try initial router if no routers or failed if table == nil { r.log.Infof(log.Router, r.logId, "Reading routing table from initial router: %s", r.rootRouter) - table, err = readTable(ctx, r.pool, []string{r.rootRouter}, r.routerContext, bookmarks, database, impersonatedUser, auth, boltLogger) + table, err = readTable(ctx, r.pool, []string{r.rootRouter}, r.routerContext, r.idlenessTimeout, bookmarks, database, impersonatedUser, auth, boltLogger) } if errorutil.IsFatalDuringDiscovery(err) { r.log.Error(log.Router, r.logId, err) @@ -119,7 +120,7 @@ func (r *Router) readTable( if table == nil && r.getRouters != nil { routers := r.getRouters() r.log.Infof(log.Router, r.logId, "Reading routing table for '%s' from custom routers: %v", routers) - table, err = readTable(ctx, r.pool, routers, r.routerContext, bookmarks, database, impersonatedUser, auth, boltLogger) + table, err = readTable(ctx, r.pool, routers, r.routerContext, r.idlenessTimeout, bookmarks, database, impersonatedUser, auth, boltLogger) } if errorutil.IsFatalDuringDiscovery(err) { r.log.Error(log.Router, r.logId, err) @@ -189,7 +190,7 @@ func (r *Router) getOrUpdateTable(ctx context.Context, bookmarksFn func(context. } func (r *Router) getTableLocked(dbRouter *databaseRouter) *idb.RoutingTable { - now := (*r.now)() + now := itime.Now() if dbRouter != nil && now.Unix() < dbRouter.dueUnix { return dbRouter.table } @@ -206,7 +207,7 @@ func (r *Router) updateTable(ctx context.Context, bookmarksFn func(context.Conte return nil, err } - err = r.storeRoutingTable(ctx, database, table, (*r.now)()) + err = r.storeRoutingTable(ctx, database, table, itime.Now()) if err != nil { return nil, err } @@ -293,7 +294,7 @@ func (r *Router) GetNameOfDefaultDatabase(ctx context.Context, bookmarks []strin return "", err } // Store the fresh routing table as well to avoid another roundtrip to receive servers from session. - now := (*r.now)() + now := itime.Now() err = r.storeRoutingTable(ctx, table.DatabaseName, table, now) if err != nil { return "", err @@ -360,7 +361,7 @@ func removeServerFromList(list []string, server string) []string { func (r *Router) CleanUp() { r.log.Debugf(log.Router, r.logId, "Cleaning up") - now := (*r.now)().Unix() + now := itime.Now().Unix() r.dbRoutersMut.Lock() defer r.dbRoutersMut.Unlock() diff --git a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/auth/auth_testkit.go b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/time/time.go similarity index 69% rename from vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/auth/auth_testkit.go rename to vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/time/time.go index 017227f..1222276 100644 --- a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/auth/auth_testkit.go +++ b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/time/time.go @@ -1,4 +1,4 @@ -//go:build internal_testkit +//go:build !internal_time_mock /* * Copyright (c) "Neo4j" @@ -17,19 +17,9 @@ * limitations under the License. */ -package auth +package time import "time" -func SetTimer(t TokenManager, timer func() time.Time) { - if t, ok := t.(*neo4jAuthTokenManager); ok { - t.now = &timer - } -} - -func ResetTime(t TokenManager) { - if t, ok := t.(*neo4jAuthTokenManager); ok { - now := time.Now - t.now = &now - } -} +var Now = time.Now +var Since = time.Since diff --git a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/time/time_mockable.go b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/time/time_mockable.go new file mode 100644 index 0000000..cec855a --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/time/time_mockable.go @@ -0,0 +1,130 @@ +//go:build internal_time_mock + +/* + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [https://neo4j.com] + * + * 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 + * + * https://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. + */ + +package time + +import ( + "errors" + "sync" + "time" +) + +type Ticker = func(*time.Time) + +var frozenNow *time.Time = nil +var tickerRegistry []Ticker = nil +var frozenNowMutex = &sync.Mutex{} + +func now() time.Time { + if frozenNow == nil { + return time.Now() + } + for _, ticker := range tickerRegistry { + ticker(frozenNow) + } + return *frozenNow +} + +func Now() time.Time { + frozenNowMutex.Lock() + defer frozenNowMutex.Unlock() + + return now() +} + +func Since(t time.Time) time.Duration { + frozenNowMutex.Lock() + defer frozenNowMutex.Unlock() + + if frozenNow == nil { + return time.Since(t) + } + return frozenNow.Sub(t) +} + +func FreezeTime() error { + frozenNowMutex.Lock() + defer frozenNowMutex.Unlock() + + if frozenNow != nil { + return errors.New("time already frozen") + } + now := now() + frozenNow = &now + return nil +} + +func ForceFreezeTime() { + if err := FreezeTime(); err != nil { + panic(err) + } +} + +func TickTime(d time.Duration) error { + frozenNowMutex.Lock() + defer frozenNowMutex.Unlock() + + if frozenNow == nil { + return errors.New("time not frozen") + } + newNow := frozenNow.Add(d) + frozenNow = &newNow + return nil +} + +func ForceTickTime(d time.Duration) { + if err := TickTime(d); err != nil { + panic(err) + } +} + +func AddTicker(ticker Ticker) error { + frozenNowMutex.Lock() + defer frozenNowMutex.Unlock() + + if frozenNow == nil { + return errors.New("time not frozen") + } + tickerRegistry = append(tickerRegistry, ticker) + return nil +} + +func ForceAddTicker(ticker Ticker) { + if err := AddTicker(ticker); err != nil { + panic(err) + } +} + +func UnfreezeTime() error { + frozenNowMutex.Lock() + defer frozenNowMutex.Unlock() + + if frozenNow == nil { + return errors.New("time not frozen") + } + frozenNow = nil + tickerRegistry = nil + return nil +} + +func ForceUnfreezeTime() { + if err := UnfreezeTime(); err != nil { + panic(err) + } +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/session_with_context.go b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/session_with_context.go index 1e2533a..18b42b2 100644 --- a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/session_with_context.go +++ b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/session_with_context.go @@ -20,17 +20,16 @@ package neo4j import ( "context" "fmt" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/collections" - idb "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/db" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/errorutil" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/pool" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/telemetry" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/notifications" "math" "time" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/collections" + idb "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/db" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/errorutil" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/retry" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/telemetry" "github.com/neo4j/neo4j-go-driver/v5/neo4j/log" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/notifications" ) // TransactionWork represents a unit of work that will be executed against the provided @@ -186,10 +185,9 @@ const FetchDefault = 0 // Connection pool as seen by the session. type sessionPool interface { - Borrow(ctx context.Context, getServerNames func() []string, wait bool, boltLogger log.BoltLogger, livenessCheckThreshold time.Duration, auth *idb.ReAuthToken) (idb.Connection, error) + Borrow(ctx context.Context, getServerNames func() []string, wait bool, boltLogger log.BoltLogger, livenessCheckTimeout time.Duration, auth *idb.ReAuthToken) (idb.Connection, error) Return(ctx context.Context, c idb.Connection) CleanUp(ctx context.Context) - Now() time.Time } type sessionWithContext struct { @@ -202,7 +200,6 @@ type sessionWithContext struct { explicitTx *explicitTransaction autocommitTx *autocommitTransaction sleep func(d time.Duration) - now *func() time.Time logId string log log.Logger throttleTime time.Duration @@ -218,7 +215,6 @@ func newSessionWithContext( pool sessionPool, logger log.Logger, token *idb.ReAuthToken, - now *func() time.Time, ) *sessionWithContext { logId := log.NewId() logger.Debugf(log.Session, logId, "Created") @@ -237,7 +233,6 @@ func newSessionWithContext( config: sessConfig, resolveHomeDb: sessConfig.DatabaseName == "", sleep: time.Sleep, - now: now, log: logger, logId: logId, throttleTime: time.Second * 1, @@ -302,7 +297,7 @@ func (s *sessionWithContext) BeginTransaction(ctx context.Context, configurers . } // Get a connection from the pool. This could fail in clustered environment. - conn, err := s.getConnection(ctx, s.defaultMode, pool.DefaultLivenessCheckThreshold) + conn, err := s.getConnection(ctx, s.defaultMode, s.driverConfig.ConnectionLivenessCheckTimeout) if err != nil { return nil, errorutil.WrapError(err) } @@ -416,7 +411,6 @@ func (s *sessionWithContext) runRetriable( Log: s.log, LogName: log.Session, LogId: s.logId, - Now: s.now, Sleep: s.sleep, Throttle: retry.Throttler(s.throttleTime), MaxDeadConnections: s.driverConfig.MaxConnectionPoolSize, @@ -442,7 +436,7 @@ func (s *sessionWithContext) executeTransactionFunction( blockingTxBegin bool, api telemetry.API) (bool, any) { - conn, err := s.getConnection(ctx, mode, pool.DefaultLivenessCheckThreshold) + conn, err := s.getConnection(ctx, mode, s.driverConfig.ConnectionLivenessCheckTimeout) if err != nil { state.OnFailure(ctx, err, conn, false) return false, nil @@ -525,14 +519,12 @@ func (s *sessionWithContext) getServers(mode idb.AccessMode) func() []string { } } -func (s *sessionWithContext) getConnection(ctx context.Context, mode idb.AccessMode, livenessCheckThreshold time.Duration) (idb.Connection, error) { +func (s *sessionWithContext) getConnection(ctx context.Context, mode idb.AccessMode, livenessCheckTimeout time.Duration) (idb.Connection, error) { timeout := s.driverConfig.ConnectionAcquisitionTimeout if timeout > 0 { var cancel context.CancelFunc ctx, cancel = context.WithTimeout(ctx, timeout) - if cancel != nil { - defer cancel() - } + defer cancel() deadline, _ := ctx.Deadline() s.log.Debugf(log.Session, s.logId, "connection acquisition timeout is %s, resolved deadline is: %s", timeout, deadline) } else if deadline, ok := ctx.Deadline(); ok { @@ -552,7 +544,7 @@ func (s *sessionWithContext) getConnection(ctx context.Context, mode idb.AccessM s.getServers(mode), timeout != 0, s.config.BoltLogger, - livenessCheckThreshold, + livenessCheckTimeout, s.auth) if err != nil { return nil, errorutil.WrapError(err) @@ -606,7 +598,7 @@ func (s *sessionWithContext) Run(ctx context.Context, return nil, err } - conn, err := s.getConnection(ctx, s.defaultMode, pool.DefaultLivenessCheckThreshold) + conn, err := s.getConnection(ctx, s.defaultMode, s.driverConfig.ConnectionLivenessCheckTimeout) if err != nil { return nil, errorutil.WrapError(err) } diff --git a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/transaction_config.go b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/transaction_config.go index 4f86aae..f7cca87 100644 --- a/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/transaction_config.go +++ b/vendor/github.com/neo4j/neo4j-go-driver/v5/neo4j/transaction_config.go @@ -56,6 +56,12 @@ type TransactionConfig struct { // To apply a transaction timeout to a write transaction function: // // session.ExecuteWrite(DoWork, WithTxTimeout(5*time.Second)) +// +// To apply a transaction timeout with the ExecuteQuery function, use ExecuteQueryWithTransactionConfig: +// +// ExecuteQuery(ctx, driver, query, parameters, transformer, +// ExecuteQueryWithTransactionConfig(WithTxTimeout(*time.Second)) +// ) func WithTxTimeout(timeout time.Duration) func(*TransactionConfig) { return func(config *TransactionConfig) { config.Timeout = timeout @@ -64,21 +70,27 @@ func WithTxTimeout(timeout time.Duration) func(*TransactionConfig) { // WithTxMetadata returns a transaction configuration function that attaches metadata to a transaction. // -// To attach a metadata to an explicit transaction: +// To attach metadata to an explicit transaction: +// +// session.BeginTransaction(WithTxMetadata(map[string]any{"work-id": 1})) +// +// To attach metadata to an auto-commit transaction: // -// session.BeginTransaction(WithTxMetadata(map[string)any{"work-id": 1})) +// session.Run("RETURN 1", nil, WithTxMetadata(map[string]any{"work-id": 1})) // -// To attach a metadata to an auto-commit transaction: +// To attach metadata to a read transaction function: // -// session.Run("RETURN 1", nil, WithTxMetadata(map[string)any{"work-id": 1})) +// session.ExecuteRead(DoWork, WithTxMetadata(map[string]any{"work-id": 1})) // -// To attach a metadata to a read transaction function: +// To attach metadata to a write transaction function: // -// session.ExecuteRead(DoWork, WithTxMetadata(map[string)any{"work-id": 1})) +// session.ExecuteWrite(DoWork, WithTxMetadata(map[string]any{"work-id": 1})) // -// To attach a metadata to a write transaction function: +// To attach metadata with the ExecuteQuery function, use ExecuteQueryWithTransactionConfig: // -// session.ExecuteWrite(DoWork, WithTxMetadata(map[string)any{"work-id": 1})) +// ExecuteQuery(ctx, driver, query, parameters, transformer, +// ExecuteQueryWithTransactionConfig(WithTxMetadata(map[string]any{"work-id": 1})) +// ) func WithTxMetadata(metadata map[string]any) func(*TransactionConfig) { return func(config *TransactionConfig) { config.Metadata = metadata diff --git a/vendor/modules.txt b/vendor/modules.txt index ff8ebb7..3f72012 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -21,7 +21,7 @@ github.com/mattn/go-colorable # github.com/mattn/go-isatty v0.0.19 ## explicit; go 1.15 github.com/mattn/go-isatty -# github.com/neo4j/neo4j-go-driver/v5 v5.15.0 +# github.com/neo4j/neo4j-go-driver/v5 v5.16.0 ## explicit; go 1.18 github.com/neo4j/neo4j-go-driver/v5/neo4j github.com/neo4j/neo4j-go-driver/v5/neo4j/auth @@ -42,6 +42,7 @@ github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/racing github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/retry github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/router github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/telemetry +github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/time github.com/neo4j/neo4j-go-driver/v5/neo4j/log github.com/neo4j/neo4j-go-driver/v5/neo4j/notifications # github.com/pmezard/go-difflib v1.0.0