go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/logdog/common/storage/entry.go (about)

     1  // Copyright 2016 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package storage
    16  
    17  import (
    18  	"go.chromium.org/luci/common/errors"
    19  	"go.chromium.org/luci/logdog/api/logpb"
    20  	"go.chromium.org/luci/logdog/common/types"
    21  
    22  	"github.com/golang/protobuf/proto"
    23  )
    24  
    25  // Entry is a logpb.LogEntry wrapper that lazily evaluates / unmarshals the
    26  // underlying LogEntry data as needed.
    27  //
    28  // Entry is not goroutine-safe.
    29  type Entry struct {
    30  	D []byte
    31  
    32  	streamIndex types.MessageIndex
    33  	le          *logpb.LogEntry
    34  }
    35  
    36  // MakeEntry creates a new Entry.
    37  //
    38  // All Entry must be backed by data. The index, "idx", is optional. If <0, it
    39  // will be calculated by unmarshalling the data into a LogEntry and pulling the
    40  // value from there.
    41  func MakeEntry(d []byte, idx types.MessageIndex) *Entry {
    42  	return &Entry{
    43  		D:           d,
    44  		streamIndex: idx,
    45  	}
    46  }
    47  
    48  // GetStreamIndex returns the LogEntry's stream index.
    49  //
    50  // If this needs to be calculated by unmarshalling the LogEntry, this will be
    51  // done. If this fails, an error will be returned.
    52  //
    53  // If GetLogEntry has succeeded, subsequent GetStreamIndex calls will always
    54  // be fast and succeed.
    55  func (e *Entry) GetStreamIndex() (types.MessageIndex, error) {
    56  	if e.streamIndex < 0 {
    57  		le, err := e.GetLogEntry()
    58  		if err != nil {
    59  			return -1, err
    60  		}
    61  
    62  		e.streamIndex = types.MessageIndex(le.StreamIndex)
    63  	}
    64  
    65  	return e.streamIndex, nil
    66  }
    67  
    68  // GetLogEntry returns the unmarshalled LogEntry data.
    69  //
    70  // The first time this is called, the LogEntry will be unmarshalled from its
    71  // underlying data.
    72  func (e *Entry) GetLogEntry() (*logpb.LogEntry, error) {
    73  	if e.le == nil {
    74  		if e.D == nil {
    75  			// This can happen with keys-only results.
    76  			return nil, errors.New("no log entry data")
    77  		}
    78  
    79  		var le logpb.LogEntry
    80  		if err := proto.Unmarshal(e.D, &le); err != nil {
    81  			return nil, errors.Annotate(err, "failed to unmarshal").Err()
    82  		}
    83  		e.le = &le
    84  	}
    85  
    86  	return e.le, nil
    87  }