Skip to content

Commit af276d9

Browse files
EDsCODEclaude
andcommitted
Remove connection pooling - each client gets own :memory: db
Simplify connection handling: each client creates its own in-memory DuckDB database and attaches DuckLake. No need for pooling since :memory: databases don't have file locking issues. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent af47c64 commit af276d9

File tree

2 files changed

+13
-41
lines changed

2 files changed

+13
-41
lines changed

server/conn.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,18 @@ func (c *clientConn) serve() error {
7777
return fmt.Errorf("startup failed: %w", err)
7878
}
7979

80-
// Get a DuckDB connection from the pool. Connections are shared across
81-
// clients to avoid DuckDB file locking issues from rapid open/close cycles.
82-
db, err := c.server.getDBConnection(c.username)
80+
// Create a DuckDB connection for this client session
81+
db, err := c.server.createDBConnection(c.username)
8382
if err != nil {
8483
c.sendError("FATAL", "28000", fmt.Sprintf("failed to open database: %v", err))
8584
return err
8685
}
8786
c.db = db
88-
// Note: Don't close the connection - it's pooled and shared across clients
87+
defer func() {
88+
if c.db != nil {
89+
c.db.Close()
90+
}
91+
}()
8992

9093
// Send initial parameters
9194
c.sendInitialParams()

server/server.go

Lines changed: 6 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,6 @@ type Server struct {
9494
// duckLakeSem serializes DuckLake attachment to avoid write-write conflicts.
9595
// Using a channel instead of mutex allows for timeout on acquisition.
9696
duckLakeSem chan struct{}
97-
98-
// dbPool caches sql.DB connections per database file to avoid DuckDB file locking
99-
// issues from rapid open/close cycles. Connections are created on first use and
100-
// kept open for the server lifetime.
101-
dbPool map[string]*sql.DB
102-
dbPoolMu sync.Mutex
10397
}
10498

10599
func New(cfg Config) (*Server, error) {
@@ -135,7 +129,6 @@ func New(cfg Config) (*Server, error) {
135129
Certificates: []tls.Certificate{cert},
136130
},
137131
duckLakeSem: make(chan struct{}, 1),
138-
dbPool: make(map[string]*sql.DB),
139132
}
140133

141134
log.Printf("TLS enabled with certificate: %s", cfg.TLSCertFile)
@@ -255,36 +248,18 @@ func (s *Server) ActiveConnections() int64 {
255248
return atomic.LoadInt64(&s.activeConns)
256249
}
257250

258-
// getDBConnection returns a DuckDB connection for a client session.
259-
// Connections are pooled per user. Uses in-memory database as an anchor
260-
// for DuckLake attachment (actual data lives in RDS/S3).
261-
func (s *Server) getDBConnection(username string) (*sql.DB, error) {
262-
// Check if we already have a connection for this user
263-
s.dbPoolMu.Lock()
264-
if db, ok := s.dbPool[username]; ok {
265-
s.dbPoolMu.Unlock()
266-
// Verify connection is still alive
267-
if err := db.Ping(); err == nil {
268-
return db, nil
269-
}
270-
// Connection is dead, remove from pool and create new one
271-
log.Printf("[%s] Pooled connection dead, creating new one", username)
272-
s.dbPoolMu.Lock()
273-
delete(s.dbPool, username)
274-
}
275-
s.dbPoolMu.Unlock()
276-
251+
// createDBConnection creates a DuckDB connection for a client session.
252+
// Uses in-memory database as an anchor for DuckLake attachment (actual data lives in RDS/S3).
253+
func (s *Server) createDBConnection(username string) (*sql.DB, error) {
277254
// Create new in-memory connection (DuckLake provides actual storage)
278255
db, err := sql.Open("duckdb", ":memory:")
279256
if err != nil {
280257
return nil, fmt.Errorf("failed to open duckdb: %w", err)
281258
}
282259

283-
// Configure connection pool - allow multiple concurrent queries since
284-
// this connection is shared across all clients for this user
285-
db.SetMaxOpenConns(10)
286-
db.SetMaxIdleConns(5)
287-
db.SetConnMaxLifetime(30 * time.Minute)
260+
// Single connection per client session
261+
db.SetMaxOpenConns(1)
262+
db.SetMaxIdleConns(1)
288263

289264
// Verify connection
290265
if err := db.Ping(); err != nil {
@@ -315,12 +290,6 @@ func (s *Server) getDBConnection(username string) (*sql.DB, error) {
315290
// Continue anyway - basic queries will still work
316291
}
317292

318-
// Add to pool
319-
s.dbPoolMu.Lock()
320-
s.dbPool[username] = db
321-
s.dbPoolMu.Unlock()
322-
323-
log.Printf("[%s] DuckDB connection ready", username)
324293
return db, nil
325294
}
326295

0 commit comments

Comments
 (0)