@@ -12,6 +12,7 @@ import (
12
12
"io/fs"
13
13
"net/url"
14
14
"strings"
15
+ "sync"
15
16
"time"
16
17
17
18
_ "modernc.org/sqlite"
@@ -40,6 +41,7 @@ func linkID(short string) string {
40
41
// SQLiteDB stores Links in a SQLite database.
41
42
type SQLiteDB struct {
42
43
db * sql.DB
44
+ mu sync.RWMutex
43
45
}
44
46
45
47
//go:embed schema.sql
@@ -66,6 +68,9 @@ func NewSQLiteDB(f string) (*SQLiteDB, error) {
66
68
//
67
69
// The caller owns the returned values.
68
70
func (s * SQLiteDB ) LoadAll () ([]* Link , error ) {
71
+ s .mu .RLock ()
72
+ defer s .mu .RUnlock ()
73
+
69
74
var links []* Link
70
75
rows , err := s .db .Query ("SELECT Short, Long, Created, LastEdit, Owner FROM Links" )
71
76
if err != nil {
@@ -91,6 +96,9 @@ func (s *SQLiteDB) LoadAll() ([]*Link, error) {
91
96
//
92
97
// The caller owns the returned value.
93
98
func (s * SQLiteDB ) Load (short string ) (* Link , error ) {
99
+ s .mu .RLock ()
100
+ defer s .mu .RUnlock ()
101
+
94
102
link := new (Link )
95
103
var created , lastEdit int64
96
104
row := s .db .QueryRow ("SELECT Short, Long, Created, LastEdit, Owner FROM Links WHERE ID = ?1 LIMIT 1" , linkID (short ))
@@ -108,6 +116,9 @@ func (s *SQLiteDB) Load(short string) (*Link, error) {
108
116
109
117
// Save saves a Link.
110
118
func (s * SQLiteDB ) Save (link * Link ) error {
119
+ s .mu .Lock ()
120
+ defer s .mu .Unlock ()
121
+
111
122
result , err := s .db .Exec ("INSERT OR REPLACE INTO Links (ID, Short, Long, Created, LastEdit, Owner) VALUES (?, ?, ?, ?, ?, ?)" , linkID (link .Short ), link .Short , link .Long , link .Created .Unix (), link .LastEdit .Unix (), link .Owner )
112
123
if err != nil {
113
124
return err
@@ -133,6 +144,9 @@ func (s *SQLiteDB) LoadStats() (ClickStats, error) {
133
144
linkmap [linkID (link .Short )] = link .Short
134
145
}
135
146
147
+ s .mu .RLock ()
148
+ defer s .mu .RUnlock ()
149
+
136
150
rows , err := s .db .Query ("SELECT ID, sum(Clicks) FROM Stats GROUP BY ID" )
137
151
if err != nil {
138
152
return nil , err
@@ -155,6 +169,9 @@ func (s *SQLiteDB) LoadStats() (ClickStats, error) {
155
169
// incremental clicks that have occurred since the last time SaveStats
156
170
// was called.
157
171
func (s * SQLiteDB ) SaveStats (stats ClickStats ) error {
172
+ s .mu .Lock ()
173
+ defer s .mu .Unlock ()
174
+
158
175
tx , err := s .db .BeginTx (context .TODO (), nil )
159
176
if err != nil {
160
177
return err
0 commit comments