github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/internal/datastore/crdb/pool/node_id.go (about) 1 package pool 2 3 import ( 4 "github.com/jackc/pgx/v5" 5 ) 6 7 // The Postgres wire protocol sends a `BackendKey` when it establishes a new 8 // connection with a client. The `BackendKey` includes two fields, `ProcessID` 9 // and `SecretKey`. 10 // 11 // In postgres, the ProcessID is the PID of the process that is 12 // handling the current session, and `SecretKey`, which is unique per session 13 // and is for cancelling a running query (out of band, on a new connection). 14 // 15 // In the wire protocol, the BackendKey is a single 64 bit field. 16 // 17 // In CockroachDB, a "SqlInstanceID" and random data get encoded into the 18 // BackendKey in one of two ways: 19 // 20 // - A 12 bit node ID and 52 bits of random data. This is used when talking to 21 // standalone (non-multitenant) CockroachDB nodes. 22 // - A 32 bit instance ID and 32 bits of random data. This is used when talking 23 // to multi-tenant CockroachDB nodes - it is stable for a single sql instance 24 // but may not correspond to the physical node ID. 25 // 26 // The first bit is a sentinel that indicates which type of encoding is used. 27 // 28 // In both cases, random data fills the SecretKey portion of the BackendKey and 29 // for compatibility with postgres, can also be used to cancel running queries 30 // (CockroachDB also has a separate first-class CANCEL command). 31 // 32 // This diagram shows how Cockroach and Postgres encode/decode the bits of the 33 // BackendKey field: 34 // 35 // 0 1 2 3 4 5 6 36 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 37 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 38 // | PG BackendKey.ProcessID | PG BackendKey.SecretKey | 39 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 40 // |0| Short ID (Node ID) | Random Data | 41 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 42 // |1| Long ID | Random Data | 43 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 44 // 45 // For tracking connections to CRDB nodes this means that the SqlInstanceID can be used to track which nodes have 46 // connections. 47 // 48 // Refs: 49 // - get_backend_pid(): https://www.postgresql.org/docs/15/functions-info.html 50 // - BackendKey and query cancellation: https://www.postgresql.org/docs/current/protocol-flow.html 51 // - BackendKey wire definition: https://github.com/jackc/pgproto3/blob/master/backend_key_data.go 52 // - CRDB implementation: https://github.com/cockroachdb/cockroach/blob/fd33b0a3f5daeb6045e4c9ec925db8ef8ca38ca8/pkg/sql/pgwire/pgwirecancel/backend_key_data.go#L21 53 54 // nodeID returns the sqlInstanceID for a pgxpool.Conn 55 func nodeID(conn *pgx.Conn) uint32 { 56 return sqlInstanceID(conn.PgConn().PID()) 57 } 58 59 // sqlInstanceID returns the instance ID encoded into the PID field 60 func sqlInstanceID(pid uint32) uint32 { 61 // If leading bit is 0, we have a "short" sqlInstanceID 62 // which should be the nodeID for standalone Cockroach nodes. 63 // The first 12 bits are the id, the rest is random 64 if pid&(1<<31) == 0 { 65 return pid >> 20 66 } 67 68 // If the leading bit is 1, we have a "long" sqlInstanceID 69 // These are stable for all connections to the same SQL node but 70 // may not correspond to the physical node ID. 71 // This should only happen when talking to a tenanted CRDB cluster. 72 73 // clear out the sentinel bit - the rest is the instance ID 74 return pid &^ (1 << 31) 75 }