Skip to content

Commit 1451496

Browse files
committed
Updates
1 parent de428c1 commit 1451496

File tree

12 files changed

+250
-62
lines changed

12 files changed

+250
-62
lines changed

etc/server.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ plugins:
33
- build/httpserver.plugin
44
- build/log.plugin
55
- build/sqlite3.plugin
6-
- build/static.plugin
6+
# - build/static.plugin
77

88
# HTTP Server parameters
99
httpserver:
@@ -18,11 +18,11 @@ handlers:
1818
# Requests are logged
1919
middleware:
2020
- log
21-
static:
22-
prefix: /api/static
21+
# static:
22+
# prefix: /api/static
2323

24-
static:
25-
"/": npm/sqlite3/dist
24+
#static:
25+
# "/": npm/sqlite3/dist
2626

2727
sqlite3:
2828
# Databases to load and/or create. Only the 'main' database is required.

pkg/sqlite3/cache.go

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,21 @@ package sqlite3
33
import (
44
"sync"
55

6-
// Namespace Imports
7-
. "github.com/djthorpe/go-errors"
6+
// Packages
87
sqlite3 "github.com/djthorpe/go-sqlite/sys/sqlite3"
98
multierror "github.com/hashicorp/go-multierror"
9+
10+
// Namespace Imports
11+
. "github.com/djthorpe/go-errors"
1012
)
1113

1214
////////////////////////////////////////////////////////////////////////////////
1315
// TYPES
1416

15-
// PoolCache caches prepared statements and profiling information for
16-
// statements so it's possible to see slow queries, etc.
17-
type PoolCache struct{}
18-
1917
type ConnCache struct {
2018
sync.Mutex
2119
sync.Map
20+
cap int // Capacity of the cache, defaults to 100 prepared statements
2221
}
2322

2423
////////////////////////////////////////////////////////////////////////////////
@@ -31,13 +30,17 @@ const (
3130
////////////////////////////////////////////////////////////////////////////////
3231
// PUBLIC METHODS
3332

33+
func (cache *ConnCache) SetCap(cap int) {
34+
cache.cap = intMax(0, cap)
35+
}
36+
3437
// Return a prepared statement from the cache, or prepare a new statement
3538
// and put it in the cache before returning
3639
func (cache *ConnCache) Prepare(conn *sqlite3.ConnEx, q string) (*Results, error) {
3740
if conn == nil {
3841
return nil, ErrInternalAppError
3942
}
40-
st, _ := cache.Map.Load(q)
43+
st := cache.load(q)
4144
if st == nil {
4245
// Prepare a statement and store in cache
4346
var err error
@@ -48,11 +51,8 @@ func (cache *ConnCache) Prepare(conn *sqlite3.ConnEx, q string) (*Results, error
4851
} else {
4952
cache.Map.Store(q, st)
5053
}
51-
} else {
52-
// Increment counter by one
53-
st.(*sqlite3.StatementEx).Inc(1)
5454
}
55-
return NewResults(st.(*sqlite3.StatementEx)), nil
55+
return NewResults(st), nil
5656
}
5757

5858
// Close all conn cache prepared statements
@@ -68,3 +68,22 @@ func (cache *ConnCache) Close() error {
6868
// Return any errors
6969
return result
7070
}
71+
72+
////////////////////////////////////////////////////////////////////////////////
73+
// PRIVATE METHODS
74+
75+
func (cache *ConnCache) load(key string) *sqlite3.StatementEx {
76+
// If cache is switched off, then return nil
77+
if cache.cap == 0 {
78+
return nil
79+
}
80+
// Load statement from cache and return
81+
st, _ := cache.Map.Load(key)
82+
if st, ok := st.(*sqlite3.StatementEx); !ok {
83+
return nil
84+
} else {
85+
// Increment counter by one
86+
st.Inc(1)
87+
return st
88+
}
89+
}

pkg/sqlite3/cache_test.go

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package sqlite3_test
22

33
import (
44
"context"
5+
"errors"
6+
"io"
57
"math/rand"
68
"sync"
79
"testing"
@@ -16,26 +18,41 @@ import (
1618
)
1719

1820
func Test_Cache_001(t *testing.T) {
19-
// Create a connection
20-
conn, err := OpenPath(":memory:", sqlite3.DefaultFlags)
21+
// Create a connection and enable the connection cache (which caches prepared statements)
22+
conn, err := OpenPath(":memory:", sqlite3.DefaultFlags|sqlite3.SQLITE_OPEN_CONNCACHE)
2123
if err != nil {
2224
t.Fatal(err)
2325
}
2426
defer conn.Close()
2527

2628
// Perform caching in a transaction
2729
conn.Do(context.Background(), 0, func(txn SQTransaction) error {
28-
// Read values from the cache
30+
// SELECT n between 0-9 over 100 executions in parallel should
31+
// return the same result, with a perfect cache hit rate of 9 in 10?
2932
var wg sync.WaitGroup
30-
for i := 0; i < 99; i++ {
33+
for i := 0; i < 20; i++ {
3134
wg.Add(1)
3235
go func() {
3336
defer wg.Done()
34-
n := rand.Uint32() % 5
35-
if r, err := txn.Query(Q("SELECT ", n)); err != nil {
36-
t.Error(err)
37-
} else {
38-
t.Log(r)
37+
n := rand.Uint32() % 10
38+
r, err := txn.Query(Q("SELECT ", n))
39+
if err != nil {
40+
t.Error("Query Error: ", err)
41+
return
42+
}
43+
for {
44+
row, err := r.Next()
45+
if errors.Is(err, io.EOF) {
46+
break
47+
} else if err != nil {
48+
t.Error("Next Error: ", err)
49+
} else if len(row) != 1 {
50+
t.Error("Unexpected row length: ", row)
51+
} else if int64(n) != row[0] {
52+
t.Error("Unexpected row value: ", row, " expected [", n, "]")
53+
} else {
54+
t.Log(n, "=>", row[0])
55+
}
3956
}
4057
}()
4158
}

pkg/sqlite3/conn.go

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ type TxnFunc func(SQTransaction) error
3939
// LIFECYCLE
4040

4141
func OpenPath(path string, flags sqlite3.OpenFlags) (*Conn, error) {
42-
poolconn := new(Conn)
42+
conn := new(Conn)
4343

4444
// If no create flag then check to make sure database exists
4545
if path != defaultMemory && flags&sqlite3.SQLITE_OPEN_CREATE == 0 {
@@ -51,22 +51,29 @@ func OpenPath(path string, flags sqlite3.OpenFlags) (*Conn, error) {
5151
}
5252

5353
// Open database with flags
54-
if conn, err := sqlite3.OpenPathEx(path, flags, ""); err != nil {
54+
if c, err := sqlite3.OpenPathEx(path, flags, ""); err != nil {
5555
return nil, err
5656
} else {
57-
poolconn.ConnEx = conn
57+
conn.ConnEx = c
58+
}
59+
60+
// Set cache to default size
61+
if flags&sqlite3.SQLITE_OPEN_CONNCACHE != 0 {
62+
conn.SetCap(defaultCapacity)
63+
} else {
64+
conn.SetCap(0)
5865
}
5966

6067
// Finalizer to panic when connection not closed before garbage collection
6168
_, file, line, _ := runtime.Caller(1)
62-
runtime.SetFinalizer(poolconn, func(conn *Conn) {
69+
runtime.SetFinalizer(conn, func(conn *Conn) {
6370
if conn.c != nil {
6471
panic(fmt.Sprintf("%s:%d: missing associated call to Close()", file, line))
6572
}
6673
})
6774

6875
// Return success
69-
return poolconn, nil
76+
return conn, nil
7077
}
7178

7279
func (conn *Conn) Close() error {
@@ -139,13 +146,21 @@ func (conn *Conn) Do(ctx context.Context, flag SQTxnFlag, fn func(SQTransaction)
139146

140147
// Commit or rollback transaction
141148
if result == nil {
142-
result = multierror.Append(result, conn.ConnEx.Commit())
149+
if err := conn.ConnEx.Commit(); err != nil {
150+
result = multierror.Append(result, err)
151+
}
143152
} else {
144-
result = multierror.Append(result, conn.ConnEx.Rollback())
153+
if err := conn.ConnEx.Rollback(); err != nil {
154+
result = multierror.Append(result, err)
155+
}
145156
}
146157

147-
// Return foreign key constraints
148-
result = multierror.Append(result, conn.SetForeignKeyConstraints(fk))
158+
// Return foreign key constraints to previous value
159+
if flag&SQLITE_TXN_NO_FOREIGNKEY_CONSTRAINTS != 0 {
160+
if err := conn.SetForeignKeyConstraints(fk); err != nil {
161+
result = multierror.Append(result, err)
162+
}
163+
}
149164

150165
// Return any errors
151166
return result

pkg/sqlite3/pool.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ var (
5757
Trace: false,
5858
Create: true,
5959
Schemas: map[string]string{defaultSchema: defaultMemory},
60-
Flags: sqlite3.SQLITE_OPEN_CREATE | sqlite3.SQLITE_OPEN_READWRITE | sqlite3.SQLITE_OPEN_SHAREDCACHE,
60+
Flags: sqlite3.SQLITE_OPEN_CREATE | sqlite3.SQLITE_OPEN_SHAREDCACHE | sqlite3.SQLITE_OPEN_CONNCACHE,
6161
}
6262
)
6363

pkg/sqlite3/results.go

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"errors"
55
"fmt"
66
"io"
7+
"reflect"
78

89
// Packages
910
sqlite3 "github.com/djthorpe/go-sqlite/sys/sqlite3"
@@ -56,8 +57,42 @@ func (r *Results) NextQuery(v ...interface{}) error {
5657
} else {
5758
r.results = results
5859
r.n++
59-
// TODO: Set LastInsertId, Changes, Columns, etc.
60-
fmt.Println(r.results)
60+
// TODO: Set Columns, etc.
6161
return nil
6262
}
6363
}
64+
65+
// Return a row from the results, or return io.EOF if all results have been consumed
66+
func (r *Results) Next(t ...reflect.Type) ([]interface{}, error) {
67+
if r.results == nil {
68+
return nil, io.EOF
69+
} else {
70+
return r.results.Next(t...)
71+
}
72+
}
73+
74+
func (r *Results) ExpandedSQL() string {
75+
if r.results == nil {
76+
return ""
77+
} else {
78+
return r.results.ExpandedSQL()
79+
}
80+
}
81+
82+
// Return LastInsertId by last execute or -1 if no valid results
83+
func (r *Results) LastInsertId() int64 {
84+
if r.results == nil {
85+
return -1
86+
} else {
87+
return r.results.LastInsertId()
88+
}
89+
}
90+
91+
// Return RowsAffected by last execute or -1 if no valid results
92+
func (r *Results) RowsAffected() int {
93+
if r.results == nil {
94+
return -1
95+
} else {
96+
return r.results.RowsAffected()
97+
}
98+
}

pkg/sqlite3/util.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,11 @@ func stringToBool(v string) bool {
4444
return false
4545
}
4646
}
47+
48+
// intMax returns the maximum of two ints
49+
func intMax(a, b int) int {
50+
if a > b {
51+
return a
52+
}
53+
return b
54+
}

0 commit comments

Comments
 (0)