Skip to content

Commit

Permalink
A really dirty rip-out of the subtree revisions
Browse files Browse the repository at this point in the history
Just to confirm that removing this will actually work in practice.

The tests pass, so now we need to design an upgrade mechanism.
Probably forking this mysql driver / schema to be a mysql2 which is
effectively a different driver.

We'll also need to make some changes to this to support MariaDB.
The 'REPLACE INTO' syntax is, I'm pretty sure, a MySQL specfic
extension. There is a more standard format for doing this, but it
involved passing in more '?' parameters which was already getting
too wild for me with the '<placeholder>' expansion. Probably a
solveable problem, but one for when I'm a bit less ill :-)
  • Loading branch information
mhutchinson committed Nov 9, 2023
1 parent 5f424ec commit f5b22ff
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 32 deletions.
2 changes: 1 addition & 1 deletion storage/mysql/log_storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ type logTreeTX struct {
func (t *logTreeTX) GetMerkleNodes(ctx context.Context, ids []compact.NodeID) ([]tree.Node, error) {
t.treeTX.mu.Lock()
defer t.treeTX.mu.Unlock()
return t.subtreeCache.GetNodes(ids, t.getSubtreesAtRev(ctx, t.readRev))
return t.subtreeCache.GetNodes(ids, t.getSubtreesFunc(ctx))
}

func (t *logTreeTX) DequeueLeaves(ctx context.Context, limit int, cutoffTime time.Time) ([]*trillian.LogLeaf, error) {
Expand Down
3 changes: 1 addition & 2 deletions storage/mysql/schema/storage.sql
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,9 @@ CREATE TABLE IF NOT EXISTS Subtree(
TreeId BIGINT NOT NULL,
SubtreeId VARBINARY(255) NOT NULL,
Nodes MEDIUMBLOB NOT NULL,
SubtreeRevision INTEGER NOT NULL,
-- Key columns must be in ASC order in order to benefit from group-by/min-max
-- optimization in MySQL.
PRIMARY KEY(TreeId, SubtreeId, SubtreeRevision),
PRIMARY KEY(TreeId, SubtreeId),
FOREIGN KEY(TreeId) REFERENCES Trees(TreeId) ON DELETE CASCADE
);

Expand Down
43 changes: 14 additions & 29 deletions storage/mysql/tree_storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,15 @@ import (

// These statements are fixed
const (
insertSubtreeMultiSQL = `INSERT INTO Subtree(TreeId, SubtreeId, Nodes, SubtreeRevision) ` + placeholderSQL
insertSubtreeMultiSQL = `REPLACE INTO Subtree(TreeId, SubtreeId, Nodes) ` + placeholderSQL
insertTreeHeadSQL = `INSERT INTO TreeHead(TreeId,TreeHeadTimestamp,TreeSize,RootHash,TreeRevision,RootSignature)
VALUES(?,?,?,?,?,?)`

selectSubtreeSQL = `
SELECT x.SubtreeId, x.MaxRevision, Subtree.Nodes
FROM (
SELECT n.TreeId, n.SubtreeId, max(n.SubtreeRevision) AS MaxRevision
FROM Subtree n
WHERE n.SubtreeId IN (` + placeholderSQL + `) AND
n.TreeId = ? AND n.SubtreeRevision <= ?
GROUP BY n.TreeId, n.SubtreeId
) AS x
INNER JOIN Subtree
ON Subtree.SubtreeId = x.SubtreeId
AND Subtree.SubtreeRevision = x.MaxRevision
AND Subtree.TreeId = x.TreeId
AND Subtree.TreeId = ?`
SELECT SubtreeId, Subtree.Nodes
FROM Subtree
WHERE Subtree.TreeId = ?
AND SubtreeId IN (` + placeholderSQL + `)`
placeholderSQL = "<placeholder>"
)

Expand Down Expand Up @@ -138,7 +129,7 @@ func (m *mySQLTreeStorage) getSubtreeStmt(ctx context.Context, num int) (*sql.St
}

func (m *mySQLTreeStorage) setSubtreeStmt(ctx context.Context, num int) (*sql.Stmt, error) {
return m.getStmt(ctx, insertSubtreeMultiSQL, num, "VALUES(?, ?, ?, ?)", "(?, ?, ?, ?)")
return m.getStmt(ctx, insertSubtreeMultiSQL, num, "VALUES(?, ?, ?)", "(?, ?, ?)")
}

func (m *mySQLTreeStorage) beginTreeTx(ctx context.Context, tree *trillian.Tree, hashSizeBytes int, subtreeCache *cache.SubtreeCache) (treeTX, error) {
Expand Down Expand Up @@ -172,7 +163,7 @@ type treeTX struct {
writeRevision int64
}

func (t *treeTX) getSubtrees(ctx context.Context, treeRevision int64, ids [][]byte) ([]*storagepb.SubtreeProto, error) {
func (t *treeTX) getSubtrees(ctx context.Context, ids [][]byte) ([]*storagepb.SubtreeProto, error) {
klog.V(2).Infof("getSubtrees(len(ids)=%d)", len(ids))
klog.V(4).Infof("getSubtrees(")
if len(ids) == 0 {
Expand All @@ -190,18 +181,15 @@ func (t *treeTX) getSubtrees(ctx context.Context, treeRevision int64, ids [][]by
}
}()

args := make([]interface{}, 0, len(ids)+3)
args := make([]interface{}, 0, len(ids)+1)
args = append(args, t.treeID)

// populate args with ids.
for _, id := range ids {
klog.V(4).Infof(" id: %x", id)
args = append(args, id)
}

args = append(args, t.treeID)
args = append(args, treeRevision)
args = append(args, t.treeID)

rows, err := stx.QueryContext(ctx, args...)
if err != nil {
klog.Warningf("Failed to get merkle subtrees: %s", err)
Expand All @@ -223,9 +211,8 @@ func (t *treeTX) getSubtrees(ctx context.Context, treeRevision int64, ids [][]by

for rows.Next() {
var subtreeIDBytes []byte
var subtreeRev int64
var nodesRaw []byte
if err := rows.Scan(&subtreeIDBytes, &subtreeRev, &nodesRaw); err != nil {
if err := rows.Scan(&subtreeIDBytes, &nodesRaw); err != nil {
klog.Warningf("Failed to scan merkle subtree: %s", err)
return nil, err
}
Expand Down Expand Up @@ -296,7 +283,6 @@ func (t *treeTX) storeSubtrees(ctx context.Context, subtrees []*storagepb.Subtre
args = append(args, t.treeID)
args = append(args, s.Prefix)
args = append(args, subtreeBytes)
args = append(args, t.writeRevision)
}

tmpl, err := t.ts.setSubtreeStmt(ctx, len(subtrees))
Expand Down Expand Up @@ -340,18 +326,17 @@ func checkResultOkAndRowCountIs(res sql.Result, err error, count int64) error {
return nil
}

// getSubtreesAtRev returns a GetSubtreesFunc which reads at the passed in rev.
func (t *treeTX) getSubtreesAtRev(ctx context.Context, rev int64) cache.GetSubtreesFunc {
// getSubtrees returns a GetSubtreesFunc.
func (t *treeTX) getSubtreesFunc(ctx context.Context) cache.GetSubtreesFunc {
return func(ids [][]byte) ([]*storagepb.SubtreeProto, error) {
return t.getSubtrees(ctx, rev, ids)
return t.getSubtrees(ctx, ids)
}
}

func (t *treeTX) SetMerkleNodes(ctx context.Context, nodes []tree.Node) error {
t.mu.Lock()
defer t.mu.Unlock()
rev := t.writeRevision - 1
return t.subtreeCache.SetNodes(nodes, t.getSubtreesAtRev(ctx, rev))
return t.subtreeCache.SetNodes(nodes, t.getSubtreesFunc(ctx))
}

func (t *treeTX) Commit(ctx context.Context) error {
Expand Down

0 comments on commit f5b22ff

Please sign in to comment.