-(dnsforward): start using lastProbeLineIdx in the Seek

This commit is contained in:
Andrey Meshkov 2020-02-21 12:57:12 +03:00
parent 696a6df6ba
commit 87c0410914
3 changed files with 41 additions and 15 deletions

View File

@ -59,10 +59,12 @@ func NewQLogFile(path string) (*QLogFile, error) {
// it shifts seek position to 3/4 of the file. Otherwise, to 1/4 of the file. // it shifts seek position to 3/4 of the file. Otherwise, to 1/4 of the file.
// 5. It performs the search again, every time the search scope is narrowed twice. // 5. It performs the search again, every time the search scope is narrowed twice.
// //
// It returns the position of the the line with the timestamp we were looking for // Returns:
// * It returns the position of the the line with the timestamp we were looking for
// so that when we call "ReadNext" this line was returned. // so that when we call "ReadNext" this line was returned.
// If we could not find it, it returns 0 and ErrSeekNotFound // * Depth of the search (how many times we compared timestamps).
func (q *QLogFile) Seek(timestamp int64) (int64, error) { // * If we could not find it, it returns ErrSeekNotFound
func (q *QLogFile) Seek(timestamp int64) (int64, int, error) {
q.lock.Lock() q.lock.Lock()
defer q.lock.Unlock() defer q.lock.Unlock()
@ -72,7 +74,7 @@ func (q *QLogFile) Seek(timestamp int64) (int64, error) {
// First of all, check the file size // First of all, check the file size
fileInfo, err := q.file.Stat() fileInfo, err := q.file.Stat()
if err != nil { if err != nil {
return 0, err return 0, 0, err
} }
// Define the search scope // Define the search scope
@ -91,14 +93,14 @@ func (q *QLogFile) Seek(timestamp int64) (int64, error) {
// Get the line at the specified position // Get the line at the specified position
line, lineIdx, err = q.readProbeLine(probe) line, lineIdx, err = q.readProbeLine(probe)
if err != nil { if err != nil {
return 0, err return 0, depth, err
} }
// Get the timestamp from the query log record // Get the timestamp from the query log record
ts := readQLogTimestamp(line) ts := readQLogTimestamp(line)
if ts == 0 { if ts == 0 {
return 0, ErrSeekNotFound return 0, depth, ErrSeekNotFound
} }
if ts == timestamp { if ts == timestamp {
@ -109,9 +111,12 @@ func (q *QLogFile) Seek(timestamp int64) (int64, error) {
if lastProbeLineIdx == lineIdx { if lastProbeLineIdx == lineIdx {
// If we're testing the same line twice then most likely // If we're testing the same line twice then most likely
// the scope is too narrow and we won't find anything anymore // the scope is too narrow and we won't find anything anymore
return 0, ErrSeekNotFound return 0, depth, ErrSeekNotFound
} }
// Save the last found idx
lastProbeLineIdx = lineIdx
// Narrow the scope and repeat the search // Narrow the scope and repeat the search
if ts > timestamp { if ts > timestamp {
// If the timestamp we're looking for is OLDER than what we found // If the timestamp we're looking for is OLDER than what we found
@ -128,12 +133,12 @@ func (q *QLogFile) Seek(timestamp int64) (int64, error) {
depth++ depth++
if depth >= 100 { if depth >= 100 {
log.Error("Seek depth is too high, aborting. File %s, ts %v", q.file.Name(), timestamp) log.Error("Seek depth is too high, aborting. File %s, ts %v", q.file.Name(), timestamp)
return 0, ErrSeekNotFound return 0, depth, ErrSeekNotFound
} }
} }
q.position = lineIdx + int64(len(line)) q.position = lineIdx + int64(len(line))
return q.position, nil return q.position, depth, nil
} }
// SeekStart changes the current position to the end of the file // SeekStart changes the current position to the end of the file

View File

@ -4,6 +4,7 @@ import (
"encoding/binary" "encoding/binary"
"io" "io"
"io/ioutil" "io/ioutil"
"math"
"net" "net"
"os" "os"
"strings" "strings"
@ -95,13 +96,23 @@ func TestQLogFileSeekLargeFile(t *testing.T) {
testSeekLineQLogFile(t, q, count) testSeekLineQLogFile(t, q, count)
// CASE 5: Seek non-existent (too low) // CASE 5: Seek non-existent (too low)
_, err = q.Seek(123) _, _, err = q.Seek(123)
assert.NotNil(t, err) assert.NotNil(t, err)
// CASE 6: Seek non-existent (too high) // CASE 6: Seek non-existent (too high)
ts, _ := time.Parse(time.RFC3339, "2100-01-02T15:04:05Z07:00") ts, _ := time.Parse(time.RFC3339, "2100-01-02T15:04:05Z07:00")
_, err = q.Seek(ts.UnixNano()) _, _, err = q.Seek(ts.UnixNano())
assert.NotNil(t, err) assert.NotNil(t, err)
// CASE 7: "Almost" found
line, err := getQLogFileLine(q, count/2)
assert.Nil(t, err)
// ALMOST the record we need
timestamp := readQLogTimestamp(line) - 1
assert.NotEqual(t, uint64(0), timestamp)
_, depth, err := q.Seek(timestamp)
assert.NotNil(t, err)
assert.True(t, depth <= int(math.Log2(float64(count))+3))
} }
func TestQLogFileSeekSmallFile(t *testing.T) { func TestQLogFileSeekSmallFile(t *testing.T) {
@ -131,13 +142,23 @@ func TestQLogFileSeekSmallFile(t *testing.T) {
testSeekLineQLogFile(t, q, count) testSeekLineQLogFile(t, q, count)
// CASE 5: Seek non-existent (too low) // CASE 5: Seek non-existent (too low)
_, err = q.Seek(123) _, _, err = q.Seek(123)
assert.NotNil(t, err) assert.NotNil(t, err)
// CASE 6: Seek non-existent (too high) // CASE 6: Seek non-existent (too high)
ts, _ := time.Parse(time.RFC3339, "2100-01-02T15:04:05Z07:00") ts, _ := time.Parse(time.RFC3339, "2100-01-02T15:04:05Z07:00")
_, err = q.Seek(ts.UnixNano()) _, _, err = q.Seek(ts.UnixNano())
assert.NotNil(t, err) assert.NotNil(t, err)
// CASE 7: "Almost" found
line, err := getQLogFileLine(q, count/2)
assert.Nil(t, err)
// ALMOST the record we need
timestamp := readQLogTimestamp(line) - 1
assert.NotEqual(t, uint64(0), timestamp)
_, depth, err := q.Seek(timestamp)
assert.NotNil(t, err)
assert.True(t, depth <= int(math.Log2(float64(count))+3))
} }
func testSeekLineQLogFile(t *testing.T, q *QLogFile, lineNumber int) { func testSeekLineQLogFile(t *testing.T, q *QLogFile, lineNumber int) {
@ -147,7 +168,7 @@ func testSeekLineQLogFile(t *testing.T, q *QLogFile, lineNumber int) {
assert.NotEqual(t, uint64(0), ts) assert.NotEqual(t, uint64(0), ts)
// try seeking to that line now // try seeking to that line now
pos, err := q.Seek(ts) pos, _, err := q.Seek(ts)
assert.Nil(t, err) assert.Nil(t, err)
assert.NotEqual(t, int64(0), pos) assert.NotEqual(t, int64(0), pos)

View File

@ -51,7 +51,7 @@ func NewQLogReader(files []string) (*QLogReader, error) {
func (r *QLogReader) Seek(timestamp int64) error { func (r *QLogReader) Seek(timestamp int64) error {
for i := len(r.qFiles) - 1; i >= 0; i-- { for i := len(r.qFiles) - 1; i >= 0; i-- {
q := r.qFiles[i] q := r.qFiles[i]
_, err := q.Seek(timestamp) _, _, err := q.Seek(timestamp)
if err == nil { if err == nil {
// Our search is finished, we found the element we were looking for // Our search is finished, we found the element we were looking for
// Update currentFile only, position is already set properly in the QLogFile // Update currentFile only, position is already set properly in the QLogFile