This commit is contained in:
Aliaksandr Valialkin 2024-05-09 15:18:27 +02:00
parent 9e4abde51d
commit 7b72c6df5b
No known key found for this signature in database
GPG key ID: 52C003EE2BCDB9EB
7 changed files with 167 additions and 132 deletions

View file

@ -166,24 +166,32 @@ func (br *blockResult) setResultColumns(rcs []resultColumn) {
} }
func (br *blockResult) fetchAllColumns(bs *blockSearch, bm *bitmap) { func (br *blockResult) fetchAllColumns(bs *blockSearch, bm *bitmap) {
// Add _time column unneededColumnNames := bs.bsw.so.unneededColumnNames
br.addTimeColumn()
// Add _stream column if !slices.Contains(unneededColumnNames, "_time") {
if !br.addStreamColumn(bs) { // Add _time column
// Skip the current block, since the associated stream tags are missing. br.addTimeColumn()
br.reset()
return
} }
// Add _msg column if !slices.Contains(unneededColumnNames, "_stream") {
v := bs.csh.getConstColumnValue("_msg") // Add _stream column
if v != "" { if !br.addStreamColumn(bs) {
br.addConstColumn("_msg", v) // Skip the current block, since the associated stream tags are missing.
} else if ch := bs.csh.getColumnHeader("_msg"); ch != nil { br.reset()
br.addColumn(bs, ch, bm) return
} else { }
br.addConstColumn("_msg", "") }
if !slices.Contains(unneededColumnNames, "_msg") {
// Add _msg column
v := bs.csh.getConstColumnValue("_msg")
if v != "" {
br.addConstColumn("_msg", v)
} else if ch := bs.csh.getColumnHeader("_msg"); ch != nil {
br.addColumn(bs, ch, bm)
} else {
br.addConstColumn("_msg", "")
}
} }
// Add other const columns // Add other const columns
@ -191,7 +199,9 @@ func (br *blockResult) fetchAllColumns(bs *blockSearch, bm *bitmap) {
if isMsgFieldName(cc.Name) { if isMsgFieldName(cc.Name) {
continue continue
} }
br.addConstColumn(cc.Name, cc.Value) if !slices.Contains(unneededColumnNames, cc.Name) {
br.addConstColumn(cc.Name, cc.Value)
}
} }
// Add other non-const columns // Add other non-const columns
@ -201,7 +211,9 @@ func (br *blockResult) fetchAllColumns(bs *blockSearch, bm *bitmap) {
if isMsgFieldName(ch.name) { if isMsgFieldName(ch.name) {
continue continue
} }
br.addColumn(bs, ch, bm) if !slices.Contains(unneededColumnNames, ch.name) {
br.addColumn(bs, ch, bm)
}
} }
} }

View file

@ -206,7 +206,7 @@ func (q *Query) String() string {
return s return s
} }
func (q *Query) getNeededColumns() []string { func (q *Query) getNeededColumns() ([]string, []string) {
neededFields := newFieldsSet() neededFields := newFieldsSet()
neededFields.add("*") neededFields.add("*")
unneededFields := newFieldsSet() unneededFields := newFieldsSet()
@ -216,7 +216,7 @@ func (q *Query) getNeededColumns() []string {
pipes[i].updateNeededFields(neededFields, unneededFields) pipes[i].updateNeededFields(neededFields, unneededFields)
} }
return neededFields.getAll() return neededFields.getAll(), unneededFields.getAll()
} }
// ParseQuery parses s. // ParseQuery parses s.

View file

@ -1256,7 +1256,7 @@ func TestParseQueryFailure(t *testing.T) {
} }
func TestQueryGetNeededColumns(t *testing.T) { func TestQueryGetNeededColumns(t *testing.T) {
f := func(s, neededColumnsExpected string) { f := func(s, neededColumnsExpected, unneededColumnsExpected string) {
t.Helper() t.Helper()
q, err := ParseQuery(s) q, err := ParseQuery(s)
@ -1264,96 +1264,105 @@ func TestQueryGetNeededColumns(t *testing.T) {
t.Fatalf("cannot parse query %s: %s", s, err) t.Fatalf("cannot parse query %s: %s", s, err)
} }
columns := q.getNeededColumns() needed, unneeded := q.getNeededColumns()
neededColumns := strings.Join(columns, ",") neededColumns := strings.Join(needed, ",")
unneededColumns := strings.Join(unneeded, ",")
if neededColumns != neededColumnsExpected { if neededColumns != neededColumnsExpected {
t.Fatalf("unexpected neededColumns; got %q; want %q", neededColumns, neededColumnsExpected) t.Fatalf("unexpected neededColumns; got %q; want %q", neededColumns, neededColumnsExpected)
} }
if unneededColumns != unneededColumnsExpected {
t.Fatalf("unexpected unneededColumns; got %q; want %q", unneededColumns, unneededColumnsExpected)
}
} }
f(`*`, `*`) f(`*`, `*`, ``)
f(`foo bar`, `*`) f(`foo bar`, `*`, ``)
f(`foo:bar _time:5m baz`, `*`) f(`foo:bar _time:5m baz`, `*`, ``)
f(`* | fields *`, `*`) f(`* | fields *`, `*`, ``)
f(`* | fields * | offset 10`, `*`) f(`* | fields * | offset 10`, `*`, ``)
f(`* | fields * | offset 10 | limit 20`, `*`) f(`* | fields * | offset 10 | limit 20`, `*`, ``)
f(`* | fields foo`, `foo`) f(`* | fields foo`, `foo`, ``)
f(`* | fields foo, bar`, `bar,foo`) f(`* | fields foo, bar`, `bar,foo`, ``)
f(`* | fields foo, bar | fields baz, bar`, `bar`) f(`* | fields foo, bar | fields baz, bar`, `bar`, ``)
f(`* | fields foo, bar | fields baz, a`, ``) f(`* | fields foo, bar | fields baz, a`, ``, ``)
f(`* | fields f1, f2 | rm f3, f4`, `f1,f2`) f(`* | fields f1, f2 | rm f3, f4`, `f1,f2`, ``)
f(`* | fields f1, f2 | rm f2, f3`, `f1`) f(`* | fields f1, f2 | rm f2, f3`, `f1`, ``)
f(`* | fields f1, f2 | rm f1, f2, f3`, ``) f(`* | fields f1, f2 | rm f1, f2, f3`, ``, ``)
f(`* | fields f1, f2 | cp f1 f2, f3 f4`, `f1`) f(`* | fields f1, f2 | cp f1 f2, f3 f4`, `f1`, ``)
f(`* | fields f1, f2 | cp f1 f3, f4 f5`, `f1,f2`) f(`* | fields f1, f2 | cp f1 f3, f4 f5`, `f1,f2`, ``)
f(`* | fields f1, f2 | cp f2 f3, f4 f5`, `f1,f2`) f(`* | fields f1, f2 | cp f2 f3, f4 f5`, `f1,f2`, ``)
f(`* | fields f1, f2 | cp f2 f3, f4 f1`, `f2`) f(`* | fields f1, f2 | cp f2 f3, f4 f1`, `f2`, ``)
f(`* | fields f1, f2 | mv f1 f2, f3 f4`, `f1`) f(`* | fields f1, f2 | mv f1 f2, f3 f4`, `f1`, ``)
f(`* | fields f1, f2 | mv f1 f3, f4 f5`, `f1,f2`) f(`* | fields f1, f2 | mv f1 f3, f4 f5`, `f1,f2`, ``)
f(`* | fields f1, f2 | mv f2 f3, f4 f5`, `f1,f2`) f(`* | fields f1, f2 | mv f2 f3, f4 f5`, `f1,f2`, ``)
f(`* | fields f1, f2 | mv f2 f3, f4 f1`, `f2`) f(`* | fields f1, f2 | mv f2 f3, f4 f1`, `f2`, ``)
f(`* | fields f1, f2 | stats count() r1`, ``) f(`* | fields f1, f2 | stats count() r1`, ``, ``)
f(`* | fields f1, f2 | stats count_uniq() r1`, `f1,f2`) f(`* | fields f1, f2 | stats count_uniq() r1`, `f1,f2`, ``)
f(`* | fields f1, f2 | stats count(f1) r1`, `f1`) f(`* | fields f1, f2 | stats count(f1) r1`, `f1`, ``)
f(`* | fields f1, f2 | stats count(f1,f2,f3) r1`, `f1,f2`) f(`* | fields f1, f2 | stats count(f1,f2,f3) r1`, `f1,f2`, ``)
f(`* | fields f1, f2 | stats by(b1) count() r1`, ``) f(`* | fields f1, f2 | stats by(b1) count() r1`, ``, ``)
f(`* | fields f1, f2 | stats by(b1,f1) count() r1`, `f1`) f(`* | fields f1, f2 | stats by(b1,f1) count() r1`, `f1`, ``)
f(`* | fields f1, f2 | stats by(b1,f1) count(f1) r1`, `f1`) f(`* | fields f1, f2 | stats by(b1,f1) count(f1) r1`, `f1`, ``)
f(`* | fields f1, f2 | stats by(b1,f1) count(f1,f2,f3) r1`, `f1,f2`) f(`* | fields f1, f2 | stats by(b1,f1) count(f1,f2,f3) r1`, `f1,f2`, ``)
f(`* | fields f1, f2 | sort by(f3)`, `f1,f2`) f(`* | fields f1, f2 | sort by(f3)`, `f1,f2`, ``)
f(`* | fields f1, f2 | sort by(f1,f3)`, `f1,f2`) f(`* | fields f1, f2 | sort by(f1,f3)`, `f1,f2`, ``)
f(`* | fields f1, f2 | sort by(f3) | stats count() r1`, ``) f(`* | fields f1, f2 | sort by(f3) | stats count() r1`, ``, ``)
f(`* | fields f1, f2 | sort by(f1) | stats count() r1`, `f1`) f(`* | fields f1, f2 | sort by(f1) | stats count() r1`, `f1`, ``)
f(`* | fields f1, f2 | sort by(f1) | stats count(f2,f3) r1`, `f1,f2`) f(`* | fields f1, f2 | sort by(f1) | stats count(f2,f3) r1`, `f1,f2`, ``)
f(`* | fields f1, f2 | sort by(f3) | fields f2`, `f2`) f(`* | fields f1, f2 | sort by(f3) | fields f2`, `f2`, ``)
f(`* | fields f1, f2 | sort by(f1,f3) | fields f2`, `f1,f2`) f(`* | fields f1, f2 | sort by(f1,f3) | fields f2`, `f1,f2`, ``)
f(`* | cp foo bar`, `*`) f(`* | cp foo bar`, `*`, `bar`)
f(`* | cp foo bar, baz a`, `*`) f(`* | cp foo bar, baz a`, `*`, `a,bar`)
f(`* | cp foo bar, baz a | fields foo,a,b`, `b,baz,foo`) f(`* | cp foo bar, baz a | fields foo,a,b`, `b,baz,foo`, ``)
f(`* | cp foo bar, baz a | fields bar,a,b`, `b,baz,foo`) f(`* | cp foo bar, baz a | fields bar,a,b`, `b,baz,foo`, ``)
f(`* | cp foo bar, baz a | fields baz,a,b`, `b,baz`) f(`* | cp foo bar, baz a | fields baz,a,b`, `b,baz`, ``)
f(`* | cp foo bar | fields bar,a`, `a,foo`) f(`* | cp foo bar | fields bar,a`, `a,foo`, ``)
f(`* | cp foo bar | fields baz,a`, `a,baz`) f(`* | cp foo bar | fields baz,a`, `a,baz`, ``)
f(`* | cp foo bar | fields foo,a`, `a,foo`) f(`* | cp foo bar | fields foo,a`, `a,foo`, ``)
f(`* | cp f1 f2 | rm f1`, `*`) f(`* | cp f1 f2 | rm f1`, `*`, `f2`)
f(`* | cp f1 f2 | rm f2`, `*`) f(`* | cp f1 f2 | rm f2`, `*`, `f2`)
f(`* | cp f1 f2 | rm f3`, `*`) f(`* | cp f1 f2 | rm f3`, `*`, `f2,f3`)
f(`* | mv foo bar`, `*`) f(`* | mv foo bar`, `*`, `bar`)
f(`* | mv foo bar, baz a`, `*`) f(`* | mv foo bar, baz a`, `*`, `a,bar`)
f(`* | mv foo bar, baz a | fields foo,a,b`, `b,baz`) f(`* | mv foo bar, baz a | fields foo,a,b`, `b,baz`, ``)
f(`* | mv foo bar, baz a | fields bar,a,b`, `b,baz,foo`) f(`* | mv foo bar, baz a | fields bar,a,b`, `b,baz,foo`, ``)
f(`* | mv foo bar, baz a | fields baz,a,b`, `b,baz`) f(`* | mv foo bar, baz a | fields baz,a,b`, `b,baz`, ``)
f(`* | mv foo bar, baz a | fields baz,foo,b`, `b`) f(`* | mv foo bar, baz a | fields baz,foo,b`, `b`, ``)
f(`* | mv foo bar | fields bar,a`, `a,foo`) f(`* | mv foo bar | fields bar,a`, `a,foo`, ``)
f(`* | mv foo bar | fields baz,a`, `a,baz`) f(`* | mv foo bar | fields baz,a`, `a,baz`, ``)
f(`* | mv foo bar | fields foo,a`, `a`) f(`* | mv foo bar | fields foo,a`, `a`, ``)
f(`* | mv f1 f2 | rm f1`, `*`) f(`* | mv f1 f2 | rm f1`, `*`, `f2`)
f(`* | mv f1 f2 | rm f2`, `*`) f(`* | mv f1 f2 | rm f2,f3`, `*`, `f1,f2,f3`)
f(`* | mv f1 f2 | rm f3`, `*`) f(`* | mv f1 f2 | rm f3`, `*`, `f2,f3`)
f(`* | sort by (f1)`, `*`) f(`* | sort by (f1)`, `*`, ``)
f(`* | sort by (f1) | fields f2`, `f1,f2`) f(`* | sort by (f1) | fields f2`, `f1,f2`, ``)
f(`* | sort by (f1) | fields *`, `*`) f(`* | sort by (f1) | fields *`, `*`, ``)
f(`* | sort by (f1) | sort by (f2,f3 desc) desc`, `*`) f(`* | sort by (f1) | sort by (f2,f3 desc) desc`, `*`, ``)
f(`* | sort by (f1) | sort by (f2,f3 desc) desc | fields f4`, `f1,f2,f3,f4`) f(`* | sort by (f1) | sort by (f2,f3 desc) desc | fields f4`, `f1,f2,f3,f4`, ``)
f(`* | sort by (f1) | sort by (f2,f3 desc) desc | fields f4 | rm f1,f2,f5`, `f1,f2,f3,f4`) f(`* | sort by (f1) | sort by (f2,f3 desc) desc | fields f4 | rm f1,f2,f5`, `f1,f2,f3,f4`, ``)
f(`* | stats by(f1) count(f2) r1, count(f3,f4) r2`, `f1,f2,f3,f4`) f(`* | stats by(f1) count(f2) r1, count(f3,f4) r2`, `f1,f2,f3,f4`, ``)
f(`* | stats by(f1) count(f2) r1, count(f3,f4) r2 | fields f1`, ``) f(`* | stats by(f1) count(f2) r1, count(f3,f4) r2 | fields f1`, ``, ``)
f(`* | stats by(f1) count(f2) r1, count(f3,f4) r2 | fields r1`, `f1,f2`) f(`* | stats by(f1) count(f2) r1, count(f3,f4) r2 | fields r1`, `f1,f2`, ``)
f(`* | stats by(f1) count(f2) r1, count(f3,f4) r2 | fields r2,r3`, `f1,f3,f4`) f(`* | stats by(f1) count(f2) r1, count(f3,f4) r2 | fields r2,r3`, `f1,f3,f4`, ``)
f(`* | rm f1, f2`, `*`) f(`* | rm f1, f2`, `*`, `f1,f2`)
f(`* | rm f1, f2 | fields f3`, `f3`) f(`* | rm f1, f2 | mv f2 f3`, `*`, `f1,f2,f3`)
f(`* | rm f1, f2 | fields f1,f3`, `f3`) f(`* | rm f1, f2 | cp f2 f3`, `*`, `f1,f2,f3`)
f(`* | rm f1, f2 | stats count() f1`, ``) f(`* | rm f1, f2 | mv f2 f3 | sort by(f4)`, `*`, `f1,f2,f3`)
f(`* | rm f1, f2 | stats count(f3) r1`, `f3`) f(`* | rm f1, f2 | mv f2 f3 | sort by(f1)`, `*`, `f1,f2,f3`)
f(`* | rm f1, f2 | stats count(f1) r1`, ``) f(`* | rm f1, f2 | fields f3`, `f3`, ``)
f(`* | rm f1, f2 | stats count(f1,f3) r1`, `f3`) f(`* | rm f1, f2 | fields f1,f3`, `f3`, ``)
f(`* | rm f1, f2 | stats by(f1) count(f2) r1`, ``) f(`* | rm f1, f2 | stats count() f1`, ``, ``)
f(`* | rm f1, f2 | stats by(f3) count(f2) r1`, `f3`) f(`* | rm f1, f2 | stats count(f3) r1`, `f3`, ``)
f(`* | rm f1, f2 | stats by(f3) count(f4) r1`, `f3,f4`) f(`* | rm f1, f2 | stats count(f1) r1`, ``, ``)
f(`* | rm f1, f2 | stats count(f1,f3) r1`, `f3`, ``)
f(`* | rm f1, f2 | stats by(f1) count(f2) r1`, ``, ``)
f(`* | rm f1, f2 | stats by(f3) count(f2) r1`, `f3`, ``)
f(`* | rm f1, f2 | stats by(f3) count(f4) r1`, `f3,f4`, ``)
} }

View file

@ -32,26 +32,26 @@ func (pc *pipeCopy) String() string {
} }
func (pc *pipeCopy) updateNeededFields(neededFields, unneededFields fieldsSet) { func (pc *pipeCopy) updateNeededFields(neededFields, unneededFields fieldsSet) {
m := make(map[string]int) neededSrcFields := make([]bool, len(pc.srcFields))
for i, dstField := range pc.dstFields { for i, dstField := range pc.dstFields {
if neededFields.contains(dstField) && !unneededFields.contains(dstField) { if neededFields.contains(dstField) && !unneededFields.contains(dstField) {
m[pc.srcFields[i]]++ neededSrcFields[i] = true
} }
} }
if neededFields.contains("*") { if neededFields.contains("*") {
// update only unneeded fields // update only unneeded fields
unneededFields.addAll(pc.dstFields) unneededFields.addAll(pc.dstFields)
for i, srcField := range pc.srcFields { for i, srcField := range pc.srcFields {
if m[srcField] > 0 { if neededSrcFields[i] {
unneededFields.remove(pc.srcFields[i]) unneededFields.remove(srcField)
} }
} }
} else { } else {
// update only needed fields and reset unneeded fields // update only needed fields and reset unneeded fields
neededFields.removeAll(pc.dstFields) neededFields.removeAll(pc.dstFields)
for i, srcField := range pc.srcFields { for i, srcField := range pc.srcFields {
if m[srcField] > 0 { if neededSrcFields[i] {
neededFields.add(pc.srcFields[i]) neededFields.add(srcField)
} }
} }
unneededFields.reset() unneededFields.reset()

View file

@ -32,28 +32,30 @@ func (pr *pipeRename) String() string {
} }
func (pr *pipeRename) updateNeededFields(neededFields, unneededFields fieldsSet) { func (pr *pipeRename) updateNeededFields(neededFields, unneededFields fieldsSet) {
m := make(map[string]int) neededSrcFields := make([]bool, len(pr.srcFields))
for i, dstField := range pr.dstFields { for i, dstField := range pr.dstFields {
if neededFields.contains(dstField) && !unneededFields.contains(dstField) { if neededFields.contains(dstField) && !unneededFields.contains(dstField) {
m[pr.srcFields[i]]++ neededSrcFields[i] = true
} }
} }
if neededFields.contains("*") { if neededFields.contains("*") {
// update only unneeded fields // update only unneeded fields
unneededFields.addAll(pr.dstFields) unneededFields.addAll(pr.dstFields)
for i, srcField := range pr.srcFields { for i, srcField := range pr.srcFields {
if m[srcField] > 0 { if neededSrcFields[i] {
unneededFields.remove(pr.srcFields[i]) unneededFields.remove(srcField)
} else {
unneededFields.add(srcField)
} }
} }
} else { } else {
// update only needed fields and reset unneeded fields // update only needed fields and reset unneeded fields
neededFields.removeAll(pr.dstFields) neededFields.removeAll(pr.dstFields)
for i, srcField := range pr.srcFields { for i, srcField := range pr.srcFields {
if m[srcField] > 0 { if neededSrcFields[i] {
neededFields.add(pr.srcFields[i]) neededFields.add(srcField)
} else { } else {
neededFields.remove(pr.srcFields[i]) neededFields.remove(srcField)
} }
} }
unneededFields.reset() unneededFields.reset()

View file

@ -32,11 +32,11 @@ func TestPipeRenameUpdateNeededFields(t *testing.T) {
f("rename s1 d1, s2 d2", "*", "s1,f1,f2", "*", "d1,d2,f1,f2") f("rename s1 d1, s2 d2", "*", "s1,f1,f2", "*", "d1,d2,f1,f2")
// all the needed fields, unneeded fields intersect with dst // all the needed fields, unneeded fields intersect with dst
f("rename s1 d1, s2 d2", "*", "d2,f1,f2", "*", "d1,d2,f1,f2") f("rename s1 d1, s2 d2", "*", "d2,f1,f2", "*", "d1,d2,f1,f2,s2")
// all the needed fields, unneeded fields intersect with src and dst // all the needed fields, unneeded fields intersect with src and dst
f("rename s1 d1, s2 d2", "*", "s1,d1,f1,f2", "*", "d1,d2,f1,f2,s1") f("rename s1 d1, s2 d2", "*", "s1,d1,f1,f2", "*", "d1,d2,f1,f2,s1")
f("rename s1 d1, s2 d2", "*", "s1,d2,f1,f2", "*", "d1,d2,f1,f2") f("rename s1 d1, s2 d2", "*", "s1,d2,f1,f2", "*", "d1,d2,f1,f2,s2")
// needed fields do not intersect with src and dst // needed fields do not intersect with src and dst
f("rename s1 d1, s2 d2", "f1,f2", "", "f1,f2", "") f("rename s1 d1, s2 d2", "f1,f2", "", "f1,f2", "")

View file

@ -19,10 +19,15 @@ type genericSearchOptions struct {
// filter is the filter to use for the search // filter is the filter to use for the search
filter filter filter filter
// neededColumnNames is names of columns to return in the result // neededColumnNames contains names of columns to return in the result
neededColumnNames []string neededColumnNames []string
// needAllColumns is set to true when all the columns must be returned in the result // unneededColumnNames contains names of columns, which mustn't be returned in the result.
//
// This list is consulted if needAllColumns=true
unneededColumnNames []string
// needAllColumns is set to true when all the columns except of unneededColumnNames must be returned in the result
needAllColumns bool needAllColumns bool
} }
@ -44,21 +49,27 @@ type searchOptions struct {
// filter is the filter to use for the search // filter is the filter to use for the search
filter filter filter filter
// neededColumnNames is names of columns to return in the result // neededColumnNames contains names of columns to return in the result
neededColumnNames []string neededColumnNames []string
// needAllColumns is set to true when all the columns must be returned in the result // unneededColumnNames contains names of columns, which mustn't be returned in the result.
//
// This list is consulted when needAllColumns=true.
unneededColumnNames []string
// needAllColumns is set to true when all the columns except of unneededColumnNames must be returned in the result
needAllColumns bool needAllColumns bool
} }
// RunQuery runs the given q and calls writeBlock for results. // RunQuery runs the given q and calls writeBlock for results.
func (s *Storage) RunQuery(ctx context.Context, tenantIDs []TenantID, q *Query, writeBlock func(workerID uint, timestamps []int64, columns []BlockColumn)) error { func (s *Storage) RunQuery(ctx context.Context, tenantIDs []TenantID, q *Query, writeBlock func(workerID uint, timestamps []int64, columns []BlockColumn)) error {
neededColumnNames := q.getNeededColumns() neededColumnNames, unneededColumnNames := q.getNeededColumns()
so := &genericSearchOptions{ so := &genericSearchOptions{
tenantIDs: tenantIDs, tenantIDs: tenantIDs,
filter: q.f, filter: q.f,
neededColumnNames: neededColumnNames, neededColumnNames: neededColumnNames,
needAllColumns: slices.Contains(neededColumnNames, "*"), unneededColumnNames: unneededColumnNames,
needAllColumns: slices.Contains(neededColumnNames, "*"),
} }
workersCount := cgroup.AvailableCPUs() workersCount := cgroup.AvailableCPUs()
@ -317,13 +328,14 @@ func (pt *partition) search(ft *filterTime, sf *StreamFilter, f filter, so *gene
f = initStreamFilters(tenantIDs, pt.idb, f) f = initStreamFilters(tenantIDs, pt.idb, f)
} }
soInternal := &searchOptions{ soInternal := &searchOptions{
tenantIDs: tenantIDs, tenantIDs: tenantIDs,
streamIDs: streamIDs, streamIDs: streamIDs,
minTimestamp: ft.minTimestamp, minTimestamp: ft.minTimestamp,
maxTimestamp: ft.maxTimestamp, maxTimestamp: ft.maxTimestamp,
filter: f, filter: f,
neededColumnNames: so.neededColumnNames, neededColumnNames: so.neededColumnNames,
needAllColumns: so.needAllColumns, unneededColumnNames: so.unneededColumnNames,
needAllColumns: so.needAllColumns,
} }
return pt.ddb.search(soInternal, workCh, stopCh) return pt.ddb.search(soInternal, workCh, stopCh)
} }