github.com/bartle-stripe/trillian@v1.2.1/storage/mysql/queue.go (about)

     1  // +build !batched_queue
     2  
     3  // Copyright 2017 Google Inc. All Rights Reserved.
     4  //
     5  // Licensed under the Apache License, Version 2.0 (the "License");
     6  // you may not use this file except in compliance with the License.
     7  // You may obtain a copy of the License at
     8  //
     9  //     http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing, software
    12  // distributed under the License is distributed on an "AS IS" BASIS,
    13  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  // See the License for the specific language governing permissions and
    15  // limitations under the License.
    16  
    17  package mysql
    18  
    19  import (
    20  	"context"
    21  	"database/sql"
    22  	"errors"
    23  	"fmt"
    24  	"time"
    25  
    26  	"github.com/golang/glog"
    27  	"github.com/golang/protobuf/ptypes"
    28  	"github.com/google/trillian"
    29  )
    30  
    31  const (
    32  	// If this statement ORDER BY clause is changed refer to the comment in removeSequencedLeaves
    33  	selectQueuedLeavesSQL = `SELECT LeafIdentityHash,MerkleLeafHash,QueueTimestampNanos
    34  			FROM Unsequenced
    35  			WHERE TreeID=?
    36  			AND Bucket=0
    37  			AND QueueTimestampNanos<=?
    38  			ORDER BY QueueTimestampNanos,LeafIdentityHash ASC LIMIT ?`
    39  	insertUnsequencedEntrySQL = `INSERT INTO Unsequenced(TreeId,Bucket,LeafIdentityHash,MerkleLeafHash,QueueTimestampNanos)
    40  			VALUES(?,0,?,?,?)`
    41  	deleteUnsequencedSQL = "DELETE FROM Unsequenced WHERE TreeId=? AND Bucket=0 AND QueueTimestampNanos=? AND LeafIdentityHash=?"
    42  )
    43  
    44  type dequeuedLeaf struct {
    45  	queueTimestampNanos int64
    46  	leafIdentityHash    []byte
    47  }
    48  
    49  func dequeueInfo(leafIDHash []byte, queueTimestamp int64) dequeuedLeaf {
    50  	return dequeuedLeaf{queueTimestampNanos: queueTimestamp, leafIdentityHash: leafIDHash}
    51  }
    52  
    53  func (t *logTreeTX) dequeueLeaf(rows *sql.Rows) (*trillian.LogLeaf, dequeuedLeaf, error) {
    54  	var leafIDHash []byte
    55  	var merkleHash []byte
    56  	var queueTimestamp int64
    57  
    58  	err := rows.Scan(&leafIDHash, &merkleHash, &queueTimestamp)
    59  	if err != nil {
    60  		glog.Warningf("Error scanning work rows: %s", err)
    61  		return nil, dequeuedLeaf{}, err
    62  	}
    63  
    64  	// Note: the LeafData and ExtraData being nil here is OK as this is only used by the
    65  	// sequencer. The sequencer only writes to the SequencedLeafData table and the client
    66  	// supplied data was already written to LeafData as part of queueing the leaf.
    67  	queueTimestampProto, err := ptypes.TimestampProto(time.Unix(0, queueTimestamp))
    68  	if err != nil {
    69  		return nil, dequeuedLeaf{}, fmt.Errorf("got invalid queue timestamp: %v", err)
    70  	}
    71  	leaf := &trillian.LogLeaf{
    72  		LeafIdentityHash: leafIDHash,
    73  		MerkleLeafHash:   merkleHash,
    74  		QueueTimestamp:   queueTimestampProto,
    75  	}
    76  	return leaf, dequeueInfo(leafIDHash, queueTimestamp), nil
    77  }
    78  
    79  func queueArgs(treeID int64, identityHash []byte, queueTimestamp time.Time) []interface{} {
    80  	return []interface{}{queueTimestamp.UnixNano()}
    81  }
    82  
    83  func (t *logTreeTX) UpdateSequencedLeaves(ctx context.Context, leaves []*trillian.LogLeaf) error {
    84  	for _, leaf := range leaves {
    85  		// This should fail on insert but catch it early
    86  		if len(leaf.LeafIdentityHash) != t.hashSizeBytes {
    87  			return errors.New("sequenced leaf has incorrect hash size")
    88  		}
    89  
    90  		iTimestamp, err := ptypes.Timestamp(leaf.IntegrateTimestamp)
    91  		if err != nil {
    92  			return fmt.Errorf("got invalid integrate timestamp: %v", err)
    93  		}
    94  		_, err = t.tx.ExecContext(
    95  			ctx,
    96  			insertSequencedLeafSQL+valuesPlaceholder5,
    97  			t.treeID,
    98  			leaf.LeafIdentityHash,
    99  			leaf.MerkleLeafHash,
   100  			leaf.LeafIndex,
   101  			iTimestamp.UnixNano())
   102  		if err != nil {
   103  			glog.Warningf("Failed to update sequenced leaves: %s", err)
   104  			return err
   105  		}
   106  	}
   107  
   108  	return nil
   109  }
   110  
   111  // removeSequencedLeaves removes the passed in leaves slice (which may be
   112  // modified as part of the operation).
   113  func (t *logTreeTX) removeSequencedLeaves(ctx context.Context, leaves []dequeuedLeaf) error {
   114  	// Don't need to re-sort because the query ordered by leaf hash. If that changes because
   115  	// the query is expensive then the sort will need to be done here. See comment in
   116  	// QueueLeaves.
   117  	stx, err := t.tx.PrepareContext(ctx, deleteUnsequencedSQL)
   118  	if err != nil {
   119  		glog.Warningf("Failed to prep delete statement for sequenced work: %v", err)
   120  		return err
   121  	}
   122  	for _, dql := range leaves {
   123  		result, err := stx.ExecContext(ctx, t.treeID, dql.queueTimestampNanos, dql.leafIdentityHash)
   124  		err = checkResultOkAndRowCountIs(result, err, int64(1))
   125  		if err != nil {
   126  			return err
   127  		}
   128  	}
   129  
   130  	return nil
   131  }