Enable Binding-scoped agent push/pull, empty-table schema ensure, SyncPage inspect/drop-table, default module import, and agent-bound publish docs from the 宇恒联调意见. Co-authored-by: Cursor <cursoragent@cursor.com>
86 lines
2.0 KiB
Go
86 lines
2.0 KiB
Go
package dbsync
|
||
|
||
import (
|
||
"database/sql"
|
||
"fmt"
|
||
"strings"
|
||
"sync"
|
||
"time"
|
||
)
|
||
|
||
// remotePool 复用线上 A 连接,避免每次 push 冷开 SQLite(Windows 上常 >3s → 旧默认超时 503)。
|
||
type remotePool struct {
|
||
mu sync.Mutex
|
||
dbs map[string]*pooledDB
|
||
}
|
||
|
||
type pooledDB struct {
|
||
db *sql.DB
|
||
driver Driver
|
||
lastUsed time.Time
|
||
}
|
||
|
||
var sharedRemotePool = &remotePool{dbs: map[string]*pooledDB{}}
|
||
|
||
func poolKey(driver Driver, dsn string) string {
|
||
if driver == DriverSQLite {
|
||
dsn = normalizeSQLiteDSN(dsn)
|
||
}
|
||
return string(driver) + "|" + dsn
|
||
}
|
||
|
||
// AcquireRemote 获取(或新建)remote 连接;调用方不要 Close。
|
||
func AcquireRemote(driver Driver, dsn string) (*sql.DB, error) {
|
||
return sharedRemotePool.acquire(driver, dsn)
|
||
}
|
||
|
||
func (p *remotePool) acquire(driver Driver, dsn string) (*sql.DB, error) {
|
||
key := poolKey(driver, dsn)
|
||
p.mu.Lock()
|
||
defer p.mu.Unlock()
|
||
if e, ok := p.dbs[key]; ok && e.db != nil {
|
||
if err := e.db.Ping(); err == nil {
|
||
e.lastUsed = time.Now()
|
||
return e.db, nil
|
||
}
|
||
_ = e.db.Close()
|
||
delete(p.dbs, key)
|
||
}
|
||
db, err := Open(driver, dsn)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
p.dbs[key] = &pooledDB{db: db, driver: driver, lastUsed: time.Now()}
|
||
return db, nil
|
||
}
|
||
|
||
// WarmRemote 通道启动时预热,把冷开成本挪出请求路径。
|
||
func WarmRemote(driver Driver, dsn string) error {
|
||
if strings.TrimSpace(dsn) == "" {
|
||
return fmt.Errorf("dsn required")
|
||
}
|
||
_, err := AcquireRemote(driver, dsn)
|
||
return err
|
||
}
|
||
|
||
// InvalidateRemote 通道 DSN 变更或停用时丢掉缓存连接。
|
||
func InvalidateRemote(driver Driver, dsn string) {
|
||
key := poolKey(driver, dsn)
|
||
sharedRemotePool.mu.Lock()
|
||
defer sharedRemotePool.mu.Unlock()
|
||
if e, ok := sharedRemotePool.dbs[key]; ok {
|
||
_ = e.db.Close()
|
||
delete(sharedRemotePool.dbs, key)
|
||
}
|
||
}
|
||
|
||
// CloseAllRemotes 测试或进程退出时关闭池内连接。
|
||
func CloseAllRemotes() {
|
||
sharedRemotePool.mu.Lock()
|
||
defer sharedRemotePool.mu.Unlock()
|
||
for k, e := range sharedRemotePool.dbs {
|
||
_ = e.db.Close()
|
||
delete(sharedRemotePool.dbs, k)
|
||
}
|
||
}
|