treat Has as an implicit Write

Rationale: the VM uses the Has check to avoid issuing a duplicate Write in the blockstore.
This means that live objects that would be otherwise written are not actually written, resulting
in the first write epoch being considered the write epoch.
This commit is contained in:
vyzo 2021-07-02 09:36:15 +03:00
parent f97535d87e
commit 6a3cbea790
2 changed files with 48 additions and 13 deletions

View File

@ -18,7 +18,6 @@ import (
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/lotus/chain/types"
blocks "github.com/ipfs/go-block-format"
cid "github.com/ipfs/go-cid"
)
@ -103,7 +102,7 @@ func (d *debugLog) LogReadMiss(curTs *types.TipSet, cid cid.Cid) {
}
}
func (d *debugLog) LogWrite(curTs *types.TipSet, blk blocks.Block, writeEpoch abi.ChainEpoch) {
func (d *debugLog) LogWrite(curTs *types.TipSet, c cid.Cid, writeEpoch abi.ChainEpoch) {
if d == nil {
return
}
@ -118,13 +117,13 @@ func (d *debugLog) LogWrite(curTs *types.TipSet, blk blocks.Block, writeEpoch ab
d.writeCnt++
_, err := fmt.Fprintf(d.writeLog, "%s %d %s %d%s\n", d.timestamp(), curTs.Height(), blk.Cid(), writeEpoch, stack)
_, err := fmt.Fprintf(d.writeLog, "%s %d %s %d%s\n", d.timestamp(), curTs.Height(), c, writeEpoch, stack)
if err != nil {
log.Warnf("error writing write log: %s", err)
}
}
func (d *debugLog) LogWriteMany(curTs *types.TipSet, blks []blocks.Block, writeEpoch abi.ChainEpoch) {
func (d *debugLog) LogWriteMany(curTs *types.TipSet, cids []cid.Cid, writeEpoch abi.ChainEpoch) {
if d == nil {
return
}
@ -137,11 +136,11 @@ func (d *debugLog) LogWriteMany(curTs *types.TipSet, blks []blocks.Block, writeE
d.writeMx.Lock()
defer d.writeMx.Unlock()
d.writeCnt += len(blks)
d.writeCnt += len(cids)
now := d.timestamp()
for _, blk := range blks {
_, err := fmt.Fprintf(d.writeLog, "%s %d %s %d%s\n", now, curTs.Height(), blk.Cid(), writeEpoch, stack)
for _, c := range cids {
_, err := fmt.Fprintf(d.writeLog, "%s %d %s %d%s\n", now, curTs.Height(), c, writeEpoch, stack)
if err != nil {
log.Warnf("error writing write log: %s", err)
break

View File

@ -219,12 +219,35 @@ func (s *SplitStore) Has(cid cid.Cid) (bool, error) {
has, err := s.hot.Has(cid)
if err != nil || has {
if has && s.txnProtect != nil {
err = s.txnProtect.Mark(cid)
if err != nil {
return has, err
}
if has {
// treat it as an implicit Write, absence options -- the vm uses this check to avoid duplicate
// writes on Flush. When we have options in the API, the vm can explicitly signal that this is
// an implicit Write.
s.mx.Lock()
curTs := s.curTs
epoch := s.writeEpoch
s.mx.Unlock()
err = s.tracker.Put(cid, epoch)
if err != nil {
log.Errorf("error tracking implicit write in hotstore: %s", err)
return true, err
}
return has, err
s.debug.LogWrite(curTs, cid, epoch)
// also make sure the object is considered live during compaction
if s.txnProtect != nil {
err = s.txnProtect.Mark(cid)
if err != nil {
log.Errorf("error protecting object in compaction transaction: %s", err)
}
return true, err
}
}
return s.cold.Has(cid)
@ -240,6 +263,9 @@ func (s *SplitStore) Get(cid cid.Cid) (blocks.Block, error) {
case nil:
if s.txnProtect != nil {
err = s.txnProtect.Mark(cid)
if err != nil {
log.Errorf("error protecting object in compaction transaction: %s", err)
}
}
return blk, err
@ -275,6 +301,9 @@ func (s *SplitStore) GetSize(cid cid.Cid) (int, error) {
case nil:
if s.txnProtect != nil {
err = s.txnProtect.Mark(cid)
if err != nil {
log.Errorf("error protecting object in compaction transaction: %s", err)
}
}
return size, err
@ -319,11 +348,14 @@ func (s *SplitStore) Put(blk blocks.Block) error {
return s.cold.Put(blk)
}
s.debug.LogWrite(curTs, blk, epoch)
s.debug.LogWrite(curTs, blk.Cid(), epoch)
err = s.hot.Put(blk)
if err == nil && s.txnProtect != nil {
err = s.txnProtect.Mark(blk.Cid())
if err != nil {
log.Errorf("error protecting object in compaction transaction: %s", err)
}
}
if err != nil {
@ -358,13 +390,14 @@ func (s *SplitStore) PutMany(blks []blocks.Block) error {
return s.cold.PutMany(blks)
}
s.debug.LogWriteMany(curTs, blks, epoch)
s.debug.LogWriteMany(curTs, batch, epoch)
err = s.hot.PutMany(blks)
if err == nil && s.txnProtect != nil {
for _, cid := range batch {
err2 := s.txnProtect.Mark(cid)
if err2 != nil {
log.Errorf("error protecting object in compaction transaction: %s", err)
err = multierr.Combine(err, err2)
}
}
@ -425,6 +458,9 @@ func (s *SplitStore) View(cid cid.Cid, cb func([]byte) error) error {
case nil:
if s.txnProtect != nil {
err = s.txnProtect.Mark(cid)
if err != nil {
log.Errorf("error protecting object in compaction transaction: %s", err)
}
}
return err