Implement {Set,Get}Tag on SquirrelBlob

This commit is contained in:
Matt Joiner 2021-08-24 18:37:38 +10:00
parent f2f541a46b
commit 08d2dea5b4
2 changed files with 48 additions and 24 deletions

View File

@ -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)

View File

@ -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