OpenWithDriver opens a file-based database, creating it if it does not exist. After this function returns, an actual SQLite file will always exist. If the database is opened in WAL mode, the WAL files will also be created if they do not exist.
(drv *Driver, dbPath string, fkEnabled, wal bool)
| 242 | // database is opened in WAL mode, the WAL files will also be created if they |
| 243 | // do not exist. |
| 244 | func OpenWithDriver(drv *Driver, dbPath string, fkEnabled, wal bool) (retDB *DB, retErr error) { |
| 245 | logger := log.New(log.Writer(), "[db] ", log.LstdFlags) |
| 246 | startTime := time.Now() |
| 247 | defer func() { |
| 248 | if retErr != nil { |
| 249 | return |
| 250 | } |
| 251 | if dur := time.Since(startTime); dur > durToOpenLog { |
| 252 | logger.Printf("opened database %s in %s", dbPath, dur) |
| 253 | } |
| 254 | recordDuration(openDuration, startTime) |
| 255 | }() |
| 256 | |
| 257 | ///////////////////////////////////////////////////////////////////////// |
| 258 | // Main RW connection |
| 259 | rwDSN := MakeDSN(dbPath, ModeReadWrite, fkEnabled, wal) |
| 260 | rwDB, err := sql.Open(drv.name, rwDSN) |
| 261 | if err != nil { |
| 262 | return nil, fmt.Errorf("open: %s", err.Error()) |
| 263 | } |
| 264 | |
| 265 | ///////////////////////////////////////////////////////////////////////// |
| 266 | // Read-only connection |
| 267 | roDSN := MakeDSN(dbPath, ModeReadOnly, fkEnabled, wal) |
| 268 | roDB, err := sql.Open(drv.name, roDSN) |
| 269 | if err != nil { |
| 270 | return nil, err |
| 271 | } |
| 272 | |
| 273 | // Set connection pool behaviour. |
| 274 | rwDB.SetConnMaxLifetime(0) |
| 275 | rwDB.SetMaxOpenConns(1) // Key to ensure a new connection doesn't enable checkpointing |
| 276 | roDB.SetConnMaxIdleTime(30 * time.Second) |
| 277 | roDB.SetConnMaxLifetime(0) |
| 278 | |
| 279 | // Critical that rqlite has full control over the checkpointing process. |
| 280 | if _, err := rwDB.Exec("PRAGMA wal_autocheckpoint=0"); err != nil { |
| 281 | return nil, fmt.Errorf("disable autocheckpointing: %s", err.Error()) |
| 282 | } |
| 283 | |
| 284 | if err := rwDB.Ping(); err != nil { |
| 285 | return nil, fmt.Errorf("failed to ping on-disk database: %s", err.Error()) |
| 286 | } |
| 287 | if wal && !fsutil.FileExists(dbPath+"-wal") { |
| 288 | // Force creation of the WAL files so any external read-only connections |
| 289 | // can read the database. See https://www.sqlite.org/draft/wal.html, section 5. |
| 290 | err := func() error { |
| 291 | // Ensure it takes place on the same connection. |
| 292 | conn, err := rwDB.Conn(context.Background()) |
| 293 | if err != nil { |
| 294 | return err |
| 295 | } |
| 296 | defer conn.Close() |
| 297 | if _, err := conn.ExecContext(context.Background(), "BEGIN IMMEDIATE"); err != nil { |
| 298 | return err |
| 299 | } |
| 300 | if _, err := conn.ExecContext(context.Background(), "ROLLBACK"); err != nil { |
| 301 | return err |