// snapshotAtOrBeforeSeq returns true if the snapshot represents a seq
// number at or before the given seq number.
func snapshotAtOrBeforeSeq(path string, ss moss.Snapshot,
	seqMaxKey []byte, seqMaxWant uint64) (bool, error) {
	// Equivalent of bleve.Index.GetInternal(seqMaxKey).
	v, err := ss.Get(seqMaxKey, moss.ReadOptions{})
	if err != nil {
		return false, err
	}
	if v == nil {
		return false, nil
	}
	if len(v) != 8 {
		return false, fmt.Errorf("wrong len seqMaxKey: %s, v: %s", seqMaxKey, v)
	}

	seqMaxCurr := binary.BigEndian.Uint64(v[0:8])

	log.Printf("pindex_bleve_rollback: examining snapshot, path: %s,"+
		" seqMaxKey: %s, seqMaxCurr: %d, seqMaxWant: %d",
		path, seqMaxKey, seqMaxCurr, seqMaxWant)

	return seqMaxCurr <= seqMaxWant, nil
}
Exemple #2
0
// update() mutates this lower level store with latest data from the
// given higher level moss.Snapshot and returns a new moss.Snapshot
// that the higher level can use which represents this lower level
// store.
func (s *llStore) update(ssHigher moss.Snapshot, maxBatchSize uint64) (
	ssLower moss.Snapshot, err error) {
	if ssHigher != nil {
		iter, err := ssHigher.StartIterator(nil, nil, moss.IteratorOptions{
			IncludeDeletions: true,
			SkipLowerLevel:   true,
		})
		if err != nil {
			return nil, err
		}

		defer func() {
			err = iter.Close()
			if err != nil {
				s.logf("llStore iter.Close err: %v", err)
			}
		}()

		kvWriter, err := s.kvStore.Writer()
		if err != nil {
			return nil, err
		}

		defer func() {
			err = kvWriter.Close()
			if err != nil {
				s.logf("llStore kvWriter.Close err: %v", err)
			}
		}()

		batch := kvWriter.NewBatch()

		defer func() {
			if batch != nil {
				err = batch.Close()
				if err != nil {
					s.logf("llStore batch.Close err: %v", err)
				}
			}
		}()

		var readOptions moss.ReadOptions

		i := uint64(0)
		for {
			if i%1000000 == 0 {
				s.logf("llStore.update, i: %d", i)
			}

			ex, key, val, err := iter.CurrentEx()
			if err == moss.ErrIteratorDone {
				break
			}
			if err != nil {
				return nil, err
			}

			switch ex.Operation {
			case moss.OperationSet:
				batch.Set(key, val)

			case moss.OperationDel:
				batch.Delete(key)

			case moss.OperationMerge:
				val, err = ssHigher.Get(key, readOptions)
				if err != nil {
					return nil, err
				}

				if val != nil {
					batch.Set(key, val)
				} else {
					batch.Delete(key)
				}

			default:
				return nil, fmt.Errorf("moss store, update,"+
					" unexpected operation, ex: %v", ex)
			}

			i++

			err = iter.Next()
			if err == moss.ErrIteratorDone {
				break
			}
			if err != nil {
				return nil, err
			}

			if maxBatchSize > 0 && i%maxBatchSize == 0 {
				err = kvWriter.ExecuteBatch(batch)
				if err != nil {
					return nil, err
				}

				err = batch.Close()
				if err != nil {
					return nil, err
				}

				batch = kvWriter.NewBatch()
			}
		}

		if i > 0 {
			s.logf("llStore.update, ExecuteBatch,"+
				" path: %s, total: %d, start", s.llConfig["path"], i)

			err = kvWriter.ExecuteBatch(batch)
			if err != nil {
				return nil, err
			}

			s.logf("llStore.update, ExecuteBatch,"+
				" path: %s: total: %d, done", s.llConfig["path"], i)
		}
	}

	kvReader, err := s.kvStore.Reader()
	if err != nil {
		return nil, err
	}

	s.logf("llStore.update, new reader")

	return &llSnapshot{
		llStore:  s.addRef(),
		kvReader: kvReader,
		refs:     1,
	}, nil
}
// Attempt partial rollback.  Implementation sketch: walk through
// previous mossStore snapshots until we reach to a point at or before
// the wanted rollbackSeq.  If found, revert to that prevous snapshot.
func (t *BleveDest) partialRollbackLOCKED(partition string,
	rollbackSeq uint64) (bool, bool, error) {
	if t.bindex == nil {
		return false, false, nil
	}

	_, kvstore, err := t.bindex.Advanced()
	if err != nil {
		return false, false, err
	}

	llsh, ok := kvstore.(LowerLevelStoreHolder)
	if !ok {
		return false, false, fmt.Errorf("kvstore not a llsh, kvstore: %#v", kvstore)
	}

	lls := llsh.LowerLevelStore()
	if lls == nil {
		return false, false, fmt.Errorf("lls nil")
	}

	msah, ok := lls.(MossStoreActualHolder)
	if !ok {
		return false, false, fmt.Errorf("llsh not a msah, llsh: %#v", llsh)
	}

	store := msah.Actual()
	if store == nil {
		return false, false, nil // No moss store, so no partial rollback.
	}

	store.AddRef()
	defer store.Close()

	// TODO: Handle non-upsidedown bleve index types some day.
	seqMaxKey := upsidedown.NewInternalRow([]byte(partition), nil).Key()

	totSnapshotsExamined := 0
	defer func() {
		log.Printf("pindex_bleve_rollback: path: %s, totSnapshotsExamined: %d",
			t.path, totSnapshotsExamined)
	}()

	var ss, ssPrev moss.Snapshot

	ss, err = store.Snapshot()
	for err == nil && ss != nil {
		totSnapshotsExamined++

		var tryRevert bool

		tryRevert, err = snapshotAtOrBeforeSeq(t.path, ss, seqMaxKey, rollbackSeq)
		if err != nil {
			ss.Close()
			return false, false, err
		}

		if tryRevert {
			log.Printf("pindex_bleve_rollback: trying revert, path: %s", t.path)

			// Close the bleve index, but keep our ref-counts on the
			// underlying store and snapshot until after the revert.
			t.closeLOCKED()

			err = store.SnapshotRevert(ss)

			ss.Close()

			return true, err == nil, err
		}

		ssPrev, err = store.SnapshotPrevious(ss)
		ss.Close()
		ss = ssPrev
	}

	return false, false, err
}