From 08d2dea5b48528e00c9594920b892baedaf7f374 Mon Sep 17 00:00:00 2001 From: Matt Joiner Date: Tue, 24 Aug 2021 18:37:38 +1000 Subject: [PATCH] Implement {Set,Get}Tag on SquirrelBlob --- storage/sqlite/direct.go | 55 ++++++++++++++++++-------------- storage/sqlite/sqlite-storage.go | 17 ++++++++++ 2 files changed, 48 insertions(+), 24 deletions(-) diff --git a/storage/sqlite/direct.go b/storage/sqlite/direct.go index d687f64f..dd3f524d 100644 --- a/storage/sqlite/direct.go +++ b/storage/sqlite/direct.go @@ -6,6 +6,7 @@ package sqliteStorage import ( "errors" "fmt" + "io" "runtime" "sync" "time" @@ -73,7 +74,7 @@ func NewDirectStorage(opts NewDirectStorageOpts) (_ storage.ClientImplCloser, er if err != nil { return } - return &client{cache}, nil + return client{cache}, nil } func (cl *SquirrelCache) getCapacity() (ret *int64) { @@ -121,8 +122,8 @@ func (c *SquirrelCache) flushBlobs() { } } -func (c *SquirrelCache) OpenTorrent(info *metainfo.Info, infoHash metainfo.Hash) (storage.TorrentImpl, error) { - t := torrent{c} +func (c client) OpenTorrent(info *metainfo.Info, infoHash metainfo.Hash) (storage.TorrentImpl, error) { + t := torrent{c.SquirrelCache} return storage.TorrentImpl{Piece: t.Piece, Close: t.Close, Capacity: &c.capacity}, nil } @@ -175,12 +176,15 @@ func rowidForBlob(c conn, name string, length int64, create bool) (rowid int64, } func (t torrent) Piece(p metainfo.Piece) storage.PieceImpl { - name := p.Hash().HexString() - return piece{SquirrelBlob{ - name, + ret := piece{sb: SquirrelBlob{ + p.Hash().HexString(), p.Length(), t.c, - }} + }, + } + ret.ReaderAt = &ret.sb + ret.WriterAt = &ret.sb + return ret } func (t torrent) Close() error { @@ -194,7 +198,9 @@ type SquirrelBlob struct { } type piece struct { - SquirrelBlob + sb SquirrelBlob + io.ReaderAt + io.WriterAt } func (p SquirrelBlob) doAtIoWithBlob( @@ -250,18 +256,15 @@ func (p SquirrelBlob) WriteAt(b []byte, off int64) (n int, err error) { }, b, off, true) } -func (p piece) MarkComplete() error { +func (p SquirrelBlob) SetTag(name string, value interface{}) error { p.l.Lock() defer p.l.Unlock() - err := sqlitex.Exec(p.conn, "update blob set verified=true where name=?", nil, p.name) - if err != nil { - return err - } - changes := p.conn.Changes() - if changes != 1 { - panic(changes) - } - return nil + return sqlitex.Exec(p.conn, "insert or replace into tag (blob_name, tag_name, value) values (?, ?, ?)", nil, + p.name, name, value) +} + +func (p piece) MarkComplete() error { + return p.sb.SetTag("verified", true) } func (p SquirrelBlob) forgetBlob() { @@ -274,18 +277,22 @@ func (p SquirrelBlob) forgetBlob() { } func (p piece) MarkNotComplete() error { + return p.sb.SetTag("verified", false) +} + +func (p SquirrelBlob) GetTag(name string, result func(*sqlite.Stmt)) error { p.l.Lock() defer p.l.Unlock() - return sqlitex.Exec(p.conn, "update blob set verified=false where name=?", nil, p.name) + return sqlitex.Exec(p.conn, "select value from tag where blob_name=? and tag_name=?", func(stmt *sqlite.Stmt) error { + result(stmt) + return nil + }, p.name, name) } func (p piece) Completion() (ret storage.Completion) { - p.l.Lock() - defer p.l.Unlock() - err := sqlitex.Exec(p.conn, "select verified from blob where name=?", func(stmt *sqlite.Stmt) error { + err := p.sb.GetTag("verified", func(stmt *sqlite.Stmt) { ret.Complete = stmt.ColumnInt(0) != 0 - return nil - }, p.name) + }) ret.Ok = err == nil if err != nil { panic(err) diff --git a/storage/sqlite/sqlite-storage.go b/storage/sqlite/sqlite-storage.go index 2cdf1e3c..85ffdc46 100644 --- a/storage/sqlite/sqlite-storage.go +++ b/storage/sqlite/sqlite-storage.go @@ -71,6 +71,10 @@ func setSynchronous(conn conn, syncInt int) (err error) { } func initConn(conn conn, opts InitConnOpts) (err error) { + err = sqlitex.ExecTransient(conn, "pragma foreign_keys=on", nil) + if err != nil { + return err + } err = setSynchronous(conn, opts.SetSynchronous) if err != nil { return @@ -166,6 +170,13 @@ func InitSchema(conn conn, pageSize int, triggers bool) error { value ); + create table if not exists tag ( + blob_name references blob(name), + tag_name, + value, + primary key (blob_name, tag_name) + ); + create view if not exists deletable_blob as with recursive excess ( usage_with, @@ -200,6 +211,12 @@ func InitSchema(conn conn, pageSize int, triggers bool) error { } if triggers { err := sqlitex.ExecScript(conn, ` + create trigger if not exists delete_blob_tags_before_blob_deleted + before delete on blob + begin + delete from tag where blob_name=old.name; + end; + create trigger if not exists after_insert_blob after insert on blob begin -- 2.48.1