Skip to content

Commit

Permalink
Another stab at fixing 'no such database' errors
Browse files Browse the repository at this point in the history
  • Loading branch information
johnwarden committed Aug 22, 2023
1 parent 0db8827 commit 43a19ed
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 17 deletions.
36 changes: 26 additions & 10 deletions database.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"context"
"database/sql"
"fmt"
"os"
Expand All @@ -23,6 +24,28 @@ type newsDatabase struct {
selectLastCrawlTimeStatement *sql.Stmt
selectStoryDetailsStatement *sql.Stmt
selectStoryCountStatement *sql.Stmt

sqliteDataDir string
}

/* Attach the frontpage dataset for each context, to solve "no such table" errors,
per suggestion here https://stackoverflow.com/users/saves/2573589
*/

func (ndb newsDatabase) upvotesDBWithDataset(ctx context.Context) (*sql.Conn, error) {
conn, err := ndb.upvotesDB.Conn(ctx)
if err != nil {
return nil, errors.Wrap(err, "ndb.upvotesDB.Conn")
}

frontpageDatabaseFilename := fmt.Sprintf("%s/%s", ndb.sqliteDataDir, sqliteDataFilename)

// attach frontpage database as readonly. This way, we can write to the upvotes database while the crawler
// is writing to the frontpage database.
s := fmt.Sprintf("attach database 'file:%s?mode=ro' as frontpage", frontpageDatabaseFilename)
_, err = conn.ExecContext(ctx, s)
return conn, errors.Wrap(err, "attach frontpage database")
}

func (ndb newsDatabase) close() {
Expand Down Expand Up @@ -158,15 +181,15 @@ func openNewsDatabase(sqliteDataDir string) (newsDatabase, error) {

frontpageDatabaseFilename := fmt.Sprintf("%s/%s", sqliteDataDir, sqliteDataFilename)

ndb := newsDatabase{}
ndb := newsDatabase{sqliteDataDir: sqliteDataDir}

var err error

// Register some extension functions from go-sqlite3-stdlib so we can actually do math in sqlite3.
stdlib.Register("sqlite3_ext")

// Connect to database
ndb.db, err = sql.Open("sqlite3_ext", fmt.Sprintf("file:%s?_journal_mode=WAL&_mutex=full", frontpageDatabaseFilename))
ndb.db, err = sql.Open("sqlite3_ext", fmt.Sprintf("file:%s?_journal_mode=WAL", frontpageDatabaseFilename))

if err != nil {
return ndb, errors.Wrap(err, "open frontpageDatabase")
Expand All @@ -180,7 +203,7 @@ func openNewsDatabase(sqliteDataDir string) (newsDatabase, error) {
{
upvotesDatabaseFilename := fmt.Sprintf("%s/upvotes.sqlite", sqliteDataDir)

ndb.upvotesDB, err = sql.Open("sqlite3_ext", fmt.Sprintf("file:%s?_journal_mode=WAL&_mutex=full", upvotesDatabaseFilename))
ndb.upvotesDB, err = sql.Open("sqlite3_ext", fmt.Sprintf("file:%s?_journal_mode=WAL", upvotesDatabaseFilename))
if err != nil {
return ndb, errors.Wrap(err, "open upvotesDB")
}
Expand All @@ -190,13 +213,6 @@ func openNewsDatabase(sqliteDataDir string) (newsDatabase, error) {
return ndb, errors.Wrap(err, "initUpvotesDB")
}

// attach frontpage database as readonly. This way, we can write to the upvotes database while the crawler
// is writing to the frontpage database.
s := fmt.Sprintf("attach database 'file:%s?mode=ro' as frontpage", frontpageDatabaseFilename)
_, err = ndb.upvotesDB.Exec(s)
if err != nil {
return ndb, errors.Wrap(err, "attach frontpage database")
}
}

// the newsDatabase type has a few prepared statements that are defined here
Expand Down
17 changes: 10 additions & 7 deletions position.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,33 +99,36 @@ func (p Position) IsGain() bool {
func (app app) getDetailedPositions(ctx context.Context, userID int) ([]Position, error) {
positions := make([]Position, 0)

db := app.ndb.upvotesDB
db, err := app.ndb.upvotesDBWithDataset(ctx)
if err != nil {
return positions, errors.Wrap(err, "upvotesDBWithDataset")
}

var statement *sql.Stmt
// userIDs < 100 are pseudo-users that upvote randomly according to a strategy
Debugf(app.logger, "Getting positions for user %d", userID)
if userID < 100 {
switch userID {
case 0:
randomNewVoterStmt, err := db.Prepare(fmt.Sprintf(randomVoterSQL, "new", userID))
randomNewVoterStmt, err := db.PrepareContext(ctx, fmt.Sprintf(randomVoterSQL, "new", userID))
if err != nil {
return positions, errors.Wrap(err, "Preparing randomNewVoterStmt")
}
statement = randomNewVoterStmt
case 1:
randomTopVoterStmt, err := db.Prepare(fmt.Sprintf(randomVoterSQL, "top", userID))
randomTopVoterStmt, err := db.PrepareContext(ctx, fmt.Sprintf(randomVoterSQL, "top", userID))
if err != nil {
return positions, errors.Wrapf(err, "Preparing randomTopVoterStmt %s", fmt.Sprintf(randomVoterSQL, "top"))
}
statement = randomTopVoterStmt
case 2:
everyStoryVoter, err := db.Prepare(fmt.Sprintf(everyStoryVoterSQL, userID, 1))
everyStoryVoter, err := db.PrepareContext(ctx, fmt.Sprintf(everyStoryVoterSQL, userID, 1))
if err != nil {
return positions, errors.Wrap(err, "Preparing everyStoryVoter")
}
statement = everyStoryVoter
case 3:
everyStoryDownVoter, err := db.Prepare(fmt.Sprintf(everyStoryVoterSQL, userID, -1))
everyStoryDownVoter, err := db.PrepareContext(ctx, fmt.Sprintf(everyStoryVoterSQL, userID, -1))
if err != nil {
return positions, errors.Wrap(err, "Preparing everyStoryVoter")
}
Expand Down Expand Up @@ -166,7 +169,7 @@ func (app app) getDetailedPositions(ctx context.Context, userID int) ([]Position
// }
} else {

getDetailedPositionsStmt, err := db.Prepare(getDetailedPositionsSQL)
getDetailedPositionsStmt, err := db.PrepareContext(ctx, getDetailedPositionsSQL)
if err != nil {
return positions, errors.Wrap(err, "Preparing getDetailedPositionsStmt")
}
Expand Down Expand Up @@ -228,7 +231,7 @@ func (app app) getPositions(ctx context.Context, userID int64, storyIDs []int) (
db := app.ndb.upvotesDB

// TODO: only select votes relevant to the stories on the page
getPositionsStatement, err := db.Prepare(`
getPositionsStatement, err := db.PrepareContext(ctx, `
select
storyID
, direction
Expand Down

0 comments on commit 43a19ed

Please sign in to comment.