]> Sergey Matveev's repositories - btrtrc.git/commitdiff
Implement {Set,Get}Tag on SquirrelBlob
authorMatt Joiner <anacrolix@gmail.com>
Tue, 24 Aug 2021 08:37:38 +0000 (18:37 +1000)
committerMatt Joiner <anacrolix@gmail.com>
Tue, 24 Aug 2021 08:37:38 +0000 (18:37 +1000)
storage/sqlite/direct.go
storage/sqlite/sqlite-storage.go

index d687f64f0b75c8a38608f963f84c3b60025bf1a4..dd3f524d94ba6d82f6cea1a1167c0d4e506ab134 100644 (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)
index 2cdf1e3c0ef65b5f6f26dc443264662dced4e62a..85ffdc46394a2283eac21b622928cbbf5e1b22fa 100644 (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