Esempio n. 1
0
func (e *SegmentTermsEnum) SeekExactFromLast(target []byte, otherState TermState) error {
	log.Printf("BTTR.seekExact termState seg=%v target=%v state=%v", e.segment, brToString(target), otherState)
	e.eof = false
	if !fst.CompareFSTValue(target, e.term.toBytes()) || !e.termExists {
		assert(otherState != nil)
		// TODO can not assert type conversion here
		// _, ok := otherState.(*BlockTermState)
		// assert(ok)
		e.currentFrame = e.staticFrame
		e.currentFrame.state.CopyFrom(otherState)
		e.term.copyBytes(target)
		e.currentFrame.metaDataUpto = e.currentFrame.getTermBlockOrd()
		assert(e.currentFrame.metaDataUpto > 0)
		e.validIndexPrefix = 0
	} else {
		log.Printf("  skip seek: already on target state=%v", e.currentFrame.state)
	}
	return nil
}
Esempio n. 2
0
func (e *SegmentTermsEnum) SeekExact(target []byte) (ok bool, err error) {
	if e.index == nil {
		panic("terms index was not loaded")
	}

	if cap(e.term.bytes) <= len(target) {
		e.term.ensureSize(1 + len(target))
	}

	e.eof = false
	log.Printf("BTTR.seekExact seg=%v target=%v:%v current=%v (exists?=%v) validIndexPrefix=%v",
		e.segment, e.fieldInfo.Name, brToString(target), e.term, e.termExists, e.validIndexPrefix)
	e.printSeekState()

	var arc *fst.Arc
	var targetUpto int
	var output []byte

	e.targetBeforeCurrentLength = e.currentFrame.ord

	// if e.currentFrame != e.staticFrame {
	if e.currentFrame.ord != e.staticFrame.ord {
		// We are already seek'd; find the common
		// prefix of new seek term vs current term and
		// re-use the corresponding seek state.  For
		// example, if app first seeks to foobar, then
		// seeks to foobaz, we can re-use the seek state
		// for the first 5 bytes.

		log.Printf("  re-use current seek state validIndexPrefix=%v", e.validIndexPrefix)

		arc = e.arcs[0]
		if !arc.IsFinal() {
			panic("assert fail")
		}
		output = arc.Output.([]byte)
		targetUpto = 0

		lastFrame := e.stack[0]
		if e.validIndexPrefix > e.term.length {
			panic("assert fail")
		}

		targetLimit := len(target)
		if e.validIndexPrefix < targetLimit {
			targetLimit = e.validIndexPrefix
		}

		cmp := 0

		// TODO: reverse vLong byte order for better FST
		// prefix output sharing

		noOutputs := e.fstOutputs.NoOutput()

		// First compare up to valid seek frames:
		for targetUpto < targetLimit {
			cmp = int(e.term.bytes[targetUpto]) - int(target[targetUpto])
			log.Printf("    cycle targetUpto=%v (vs limit=%v) cmp=%v (targetLabel=%c vs termLabel=%c) arc.output=%v output=%v",
				targetUpto, targetLimit, cmp, target[targetUpto], e.term.bytes[targetUpto], arc.Output, output)
			if cmp != 0 {
				break
			}

			arc = e.arcs[1+targetUpto]
			if arc.Label != int(target[targetUpto]) {
				log.Printf("FAIL: arc.label=%c targetLabel=%c", arc.Label, target[targetUpto])
				panic("assert fail")
			}
			if arc.Output != noOutputs {
				output = e.fstOutputs.Add(output, arc.Output).([]byte)
			}
			if arc.IsFinal() {
				lastFrame = e.stack[1+lastFrame.ord]
			}
			targetUpto++
		}

		if cmp == 0 {
			targetUptoMid := targetUpto

			// Second compare the rest of the term, but
			// don't save arc/output/frame; we only do this
			// to find out if the target term is before,
			// equal or after the current term
			targetLimit2 := len(target)
			if e.term.length < targetLimit2 {
				targetLimit2 = e.term.length
			}
			for targetUpto < targetLimit2 {
				cmp = int(e.term.bytes[targetUpto]) - int(target[targetUpto])
				log.Printf("    cycle2 targetUpto=%v (vs limit=%v) cmp=%v (targetLabel=%c vs termLabel=%c)",
					targetUpto, targetLimit, cmp, target[targetUpto], e.term.bytes[targetUpto])
				if cmp != 0 {
					break
				}
				targetUpto++
			}

			if cmp == 0 {
				cmp = e.term.length - len(target)
			}
			targetUpto = targetUptoMid
		}

		if cmp < 0 {
			// Common case: target term is after current
			// term, ie, app is seeking multiple terms
			// in sorted order
			log.Printf("  target is after current (shares prefixLen=%v); frame.ord=%v", targetUpto, lastFrame.ord)
			e.currentFrame = lastFrame
		} else if cmp > 0 {
			// Uncommon case: target term
			// is before current term; this means we can
			// keep the currentFrame but we must rewind it
			// (so we scan from the start)
			e.targetBeforeCurrentLength = 0
			log.Printf("  target is before current (shares prefixLen=%v); rewind frame ord=%v", targetUpto, lastFrame.ord)
			e.currentFrame = lastFrame
			e.currentFrame.rewind()
		} else {
			// Target is exactly the same as current term
			if e.term.length != len(target) {
				panic("assert fail")
			}
			if e.termExists {
				log.Println("  target is same as current; return true")
				return true, nil
			} else {
				log.Println("  target is same as current but term doesn't exist")
			}
		}
	} else {
		e.targetBeforeCurrentLength = -1
		arc = e.index.FirstArc(e.arcs[0])

		// Empty string prefix must have an output (block) in the index!
		if !arc.IsFinal() || arc.Output == nil {
			panic("assert fail")
		}

		log.Println("    no seek state; push root frame")

		output = arc.Output.([]byte)

		e.currentFrame = e.staticFrame

		targetUpto = 0
		e.currentFrame, err = e.pushFrame(arc, e.fstOutputs.Add(output, arc.NextFinalOutput).([]byte), 0)
		if err != nil {
			return false, err
		}
	}

	log.Printf("  start index loop targetUpto=%v output=%v currentFrame.ord=%v targetBeforeCurrentLength=%v",
		targetUpto, output, e.currentFrame.ord, e.targetBeforeCurrentLength)

	for targetUpto < len(target) {
		targetLabel := int(target[targetUpto])
		nextArc, err := e.index.FindTargetArc(targetLabel, arc, e.getArc(1+targetUpto), e.fstReader)
		if err != nil {
			return false, err
		}
		if nextArc == nil {
			// Index is exhausted
			log.Printf("    index: index exhausted label=%c %x", targetLabel, targetLabel)

			e.validIndexPrefix = e.currentFrame.prefix

			e.currentFrame.scanToFloorFrame(target)

			if !e.currentFrame.hasTerms {
				e.termExists = false
				e.term.bytes[targetUpto] = byte(targetLabel)
				log.Printf("  FAST NOT_FOUND term=%v", e.term)
				return false, nil
			}

			e.currentFrame.loadBlock()

			status, err := e.currentFrame.scanToTerm(target, true)
			if err != nil {
				return false, err
			}
			if status == SEEK_STATUS_FOUND {
				log.Printf("  return FOUND term=%v", e.term)
				return true, nil
			} else {
				log.Printf("  got %v; return NOT_FOUND term=%v", status, e.term)
				return false, nil
			}
		} else {
			// Follow this arc
			arc = nextArc
			e.term.bytes[targetUpto] = byte(targetLabel)
			if arc.Output == nil {
				panic("assert fail")
			}
			noOutputs := e.fstOutputs.NoOutput()
			if !fst.CompareFSTValue(arc.Output, noOutputs) {
				output = e.fstOutputs.Add(output, arc.Output).([]byte)
			}
			log.Printf("    index: follow label=%x arc.output=%v arc.nfo=%v",
				target[targetUpto], arc.Output, arc.NextFinalOutput)
			targetUpto++

			if arc.IsFinal() {
				log.Println("    arc is final!")
				e.currentFrame, err = e.pushFrame(arc, e.fstOutputs.Add(output, arc.NextFinalOutput).([]byte), targetUpto)
				if err != nil {
					return false, err
				}
				log.Printf("    curFrame.ord=%v hasTerms=%v", e.currentFrame.ord, e.currentFrame.hasTerms)
			}
		}
	}

	e.validIndexPrefix = e.currentFrame.prefix

	e.currentFrame.scanToFloorFrame(target)

	// Target term is entirely contained in the index:
	if !e.currentFrame.hasTerms {
		e.termExists = false
		e.term.length = targetUpto
		log.Printf("  FAST NOT_FOUND term=%v", e.term)
		return false, nil
	}

	e.currentFrame.loadBlock()

	status, err := e.currentFrame.scanToTerm(target, true)
	if err != nil {
		return false, err
	}
	if status == SEEK_STATUS_FOUND {
		log.Printf("  return FOUND term=%v", e.term)
		return true, nil
	} else {
		log.Printf("  got result %v; return NOT_FOUND term=%v", status, e.term)
		return false, nil
	}
}