2019-05-22 15:50:22 +01:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package satellitedb
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"context"
|
|
|
|
"database/sql"
|
2020-07-14 14:04:38 +01:00
|
|
|
"errors"
|
2019-05-22 15:50:22 +01:00
|
|
|
|
2020-06-26 16:44:25 +01:00
|
|
|
"go.uber.org/zap"
|
|
|
|
|
2019-12-27 11:48:47 +00:00
|
|
|
"storj.io/common/pb"
|
|
|
|
"storj.io/common/storj"
|
2021-06-11 15:34:46 +01:00
|
|
|
"storj.io/common/uuid"
|
2019-07-28 06:55:36 +01:00
|
|
|
"storj.io/storj/satellite/audit"
|
2021-04-21 13:42:57 +01:00
|
|
|
"storj.io/storj/satellite/metabase"
|
2020-01-15 02:29:51 +00:00
|
|
|
"storj.io/storj/satellite/satellitedb/dbx"
|
2019-05-22 15:50:22 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
type containment struct {
|
2019-12-14 02:29:54 +00:00
|
|
|
db *satelliteDB
|
2019-05-22 15:50:22 +01:00
|
|
|
}
|
|
|
|
|
2020-07-16 15:18:02 +01:00
|
|
|
// Get gets the pending audit by node id.
|
2019-06-04 12:55:38 +01:00
|
|
|
func (containment *containment) Get(ctx context.Context, id pb.NodeID) (_ *audit.PendingAudit, err error) {
|
|
|
|
defer mon.Task()(&ctx)(&err)
|
2019-05-22 15:50:22 +01:00
|
|
|
if id.IsZero() {
|
|
|
|
return nil, audit.ContainError.New("node ID empty")
|
|
|
|
}
|
|
|
|
|
2021-06-11 15:34:46 +01:00
|
|
|
pending, err := containment.db.Get_SegmentPendingAudits_By_NodeId(ctx, dbx.SegmentPendingAudits_NodeId(id.Bytes()))
|
2019-05-22 15:50:22 +01:00
|
|
|
if err != nil {
|
2020-07-14 14:04:38 +01:00
|
|
|
if errors.Is(err, sql.ErrNoRows) {
|
2019-08-21 17:30:29 +01:00
|
|
|
return nil, audit.ErrContainedNotFound.New("%v", id)
|
2019-05-22 15:50:22 +01:00
|
|
|
}
|
|
|
|
return nil, audit.ContainError.Wrap(err)
|
|
|
|
}
|
|
|
|
|
2019-06-04 12:55:38 +01:00
|
|
|
return convertDBPending(ctx, pending)
|
2019-05-22 15:50:22 +01:00
|
|
|
}
|
|
|
|
|
2020-07-16 15:18:02 +01:00
|
|
|
// IncrementPending creates a new pending audit entry, or increases its reverify count if it already exists.
|
2019-06-04 12:55:38 +01:00
|
|
|
func (containment *containment) IncrementPending(ctx context.Context, pendingAudit *audit.PendingAudit) (err error) {
|
|
|
|
defer mon.Task()(&ctx)(&err)
|
2021-06-11 15:34:46 +01:00
|
|
|
|
2019-12-19 09:52:17 +00:00
|
|
|
err = containment.db.WithTx(ctx, func(ctx context.Context, tx *dbx.Tx) error {
|
2021-06-11 15:34:46 +01:00
|
|
|
existingAudit, err := tx.Get_SegmentPendingAudits_By_NodeId(ctx, dbx.SegmentPendingAudits_NodeId(pendingAudit.NodeID.Bytes()))
|
2021-05-14 16:05:42 +01:00
|
|
|
switch {
|
|
|
|
case errors.Is(err, sql.ErrNoRows):
|
2019-12-19 09:52:17 +00:00
|
|
|
statement := containment.db.Rebind(
|
2021-06-11 15:34:46 +01:00
|
|
|
`INSERT INTO segment_pending_audits (
|
|
|
|
node_id, piece_id, stripe_index, share_size, expected_share_hash, reverify_count, stream_id, position
|
|
|
|
)
|
|
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
2019-12-19 09:52:17 +00:00
|
|
|
)
|
2021-06-11 15:34:46 +01:00
|
|
|
_, err = tx.Tx.ExecContext(ctx, statement,
|
|
|
|
pendingAudit.NodeID.Bytes(), pendingAudit.PieceID.Bytes(), pendingAudit.StripeIndex,
|
|
|
|
pendingAudit.ShareSize, pendingAudit.ExpectedShareHash, pendingAudit.ReverifyCount,
|
|
|
|
pendingAudit.StreamID, pendingAudit.Position.Encode())
|
2019-12-19 09:52:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-05-14 16:05:42 +01:00
|
|
|
case err == nil:
|
2019-12-19 09:52:17 +00:00
|
|
|
if !bytes.Equal(existingAudit.ExpectedShareHash, pendingAudit.ExpectedShareHash) {
|
2021-06-11 15:34:46 +01:00
|
|
|
containment.db.log.Info("pending audit already exists",
|
|
|
|
zap.String("node id", pendingAudit.NodeID.String()),
|
|
|
|
zap.String("segment streamid", pendingAudit.StreamID.String()),
|
|
|
|
zap.Uint64("segment position", pendingAudit.Position.Encode()),
|
|
|
|
)
|
2020-06-26 16:44:25 +01:00
|
|
|
return nil
|
2019-12-19 09:52:17 +00:00
|
|
|
}
|
|
|
|
statement := containment.db.Rebind(
|
2021-06-11 15:34:46 +01:00
|
|
|
`UPDATE segment_pending_audits SET reverify_count = segment_pending_audits.reverify_count + 1
|
|
|
|
WHERE segment_pending_audits.node_id=?`,
|
2019-12-19 09:52:17 +00:00
|
|
|
)
|
|
|
|
_, err = tx.Tx.ExecContext(ctx, statement, pendingAudit.NodeID.Bytes())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return err
|
2019-05-22 15:50:22 +01:00
|
|
|
}
|
|
|
|
|
2019-12-19 09:52:17 +00:00
|
|
|
updateContained := dbx.Node_Update_Fields{
|
|
|
|
Contained: dbx.Node_Contained(true),
|
|
|
|
}
|
2019-05-22 15:50:22 +01:00
|
|
|
|
2019-12-19 09:52:17 +00:00
|
|
|
return tx.UpdateNoReturn_Node_By_Id(ctx, dbx.Node_Id(pendingAudit.NodeID.Bytes()), updateContained)
|
|
|
|
})
|
|
|
|
return audit.ContainError.Wrap(err)
|
2019-05-22 15:50:22 +01:00
|
|
|
}
|
|
|
|
|
2020-07-16 15:18:02 +01:00
|
|
|
// Delete deletes the pending audit.
|
2019-12-19 09:52:17 +00:00
|
|
|
func (containment *containment) Delete(ctx context.Context, id pb.NodeID) (isDeleted bool, err error) {
|
2019-06-04 12:55:38 +01:00
|
|
|
defer mon.Task()(&ctx)(&err)
|
2019-05-22 15:50:22 +01:00
|
|
|
if id.IsZero() {
|
|
|
|
return false, audit.ContainError.New("node ID empty")
|
|
|
|
}
|
|
|
|
|
2019-12-19 09:52:17 +00:00
|
|
|
err = containment.db.WithTx(ctx, func(ctx context.Context, tx *dbx.Tx) (err error) {
|
2021-06-11 15:34:46 +01:00
|
|
|
isDeleted, err = tx.Delete_SegmentPendingAudits_By_NodeId(ctx, dbx.SegmentPendingAudits_NodeId(id.Bytes()))
|
2019-12-19 09:52:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-05-22 15:50:22 +01:00
|
|
|
|
2019-12-19 09:52:17 +00:00
|
|
|
updateContained := dbx.Node_Update_Fields{
|
|
|
|
Contained: dbx.Node_Contained(false),
|
|
|
|
}
|
2019-05-22 15:50:22 +01:00
|
|
|
|
2019-12-19 09:52:17 +00:00
|
|
|
return tx.UpdateNoReturn_Node_By_Id(ctx, dbx.Node_Id(id.Bytes()), updateContained)
|
|
|
|
})
|
|
|
|
return isDeleted, audit.ContainError.Wrap(err)
|
2019-05-22 15:50:22 +01:00
|
|
|
}
|
|
|
|
|
2021-06-11 15:34:46 +01:00
|
|
|
func convertDBPending(ctx context.Context, info *dbx.SegmentPendingAudits) (_ *audit.PendingAudit, err error) {
|
2019-06-04 12:55:38 +01:00
|
|
|
defer mon.Task()(&ctx)(&err)
|
2019-05-22 15:50:22 +01:00
|
|
|
if info == nil {
|
|
|
|
return nil, Error.New("missing info")
|
|
|
|
}
|
|
|
|
|
|
|
|
nodeID, err := storj.NodeIDFromBytes(info.NodeId)
|
|
|
|
if err != nil {
|
|
|
|
return nil, audit.ContainError.Wrap(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
pieceID, err := storj.PieceIDFromBytes(info.PieceId)
|
|
|
|
if err != nil {
|
|
|
|
return nil, audit.ContainError.Wrap(err)
|
|
|
|
}
|
|
|
|
|
2021-06-11 15:34:46 +01:00
|
|
|
streamID, err := uuid.FromBytes(info.StreamId)
|
2020-12-14 12:54:22 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, audit.ContainError.Wrap(err)
|
|
|
|
}
|
|
|
|
|
2021-06-11 15:34:46 +01:00
|
|
|
position := metabase.SegmentPositionFromEncoded(info.Position)
|
|
|
|
|
2019-05-22 15:50:22 +01:00
|
|
|
pending := &audit.PendingAudit{
|
|
|
|
NodeID: nodeID,
|
|
|
|
PieceID: pieceID,
|
2020-12-14 12:54:22 +00:00
|
|
|
StripeIndex: int32(info.StripeIndex),
|
2019-05-23 21:07:19 +01:00
|
|
|
ShareSize: int32(info.ShareSize),
|
2019-05-22 15:50:22 +01:00
|
|
|
ExpectedShareHash: info.ExpectedShareHash,
|
2019-05-23 21:07:19 +01:00
|
|
|
ReverifyCount: int32(info.ReverifyCount),
|
2021-06-11 15:34:46 +01:00
|
|
|
StreamID: streamID,
|
|
|
|
Position: position,
|
2019-05-22 15:50:22 +01:00
|
|
|
}
|
|
|
|
return pending, nil
|
|
|
|
}
|