tp: final fixes in preparation for mass table migration
Add all the remaining classes/functions which are necessary for a mass
table migration: mainly this is stuff like missing Schema functions,
Iterators etc. Also address some minor remaining issues.
Change-Id: I74b62d27bbe0ec3caaca8598df8c5dabe0537249
diff --git a/python/generators/trace_processor_table/public.py b/python/generators/trace_processor_table/public.py
index 8a5493d..abd0aec 100644
--- a/python/generators/trace_processor_table/public.py
+++ b/python/generators/trace_processor_table/public.py
@@ -40,6 +40,8 @@
"""
NONE = 0
SORTED = auto()
+ HIDDEN = auto()
+ DENSE = auto()
SET_ID = auto()
@@ -122,8 +124,7 @@
columns: The columns in this table.
tabledoc: Documentation for this table. Can include documentation overrides
for auto-added columns (i.e. id and type) and aliases added in
- |wrapping_sql_view|. parent: The parent ("super-class") table for this
- table.
+ |wrapping_sql_view|.
parent: The parent table for this table. All columns are inherited from the
specified table.
wrapping_sql_view: See |WrappingSqlView|.
@@ -131,8 +132,8 @@
class_name: str
sql_name: str
columns: List[Column]
- tabledoc: TableDoc
parent: Optional['Table'] = None
+ tabledoc: Optional[TableDoc] = None
wrapping_sql_view: Optional[WrappingSqlView] = None
diff --git a/python/generators/trace_processor_table/serialize.py b/python/generators/trace_processor_table/serialize.py
index 589544a..4aee5b5 100644
--- a/python/generators/trace_processor_table/serialize.py
+++ b/python/generators/trace_processor_table/serialize.py
@@ -19,7 +19,6 @@
from python.generators.trace_processor_table.public import ColumnFlag
from python.generators.trace_processor_table.util import ParsedTable
from python.generators.trace_processor_table.util import ParsedColumn
-from python.generators.trace_processor_table.util import to_cpp_flags
class ColumnSerializer:
@@ -104,8 +103,8 @@
return None
storage = f'ColumnStorage<ColumnType::{self.name}::stored_type>'
- # TODO(lalitm): add support for dense columns.
- return f'''{self.name}_({storage}::Create<false>())'''
+ dense = str(ColumnFlag.DENSE in self.flags).lower()
+ return f'''{self.name}_({storage}::Create<{dense}>())'''
def column_init(self) -> Optional[str]:
if self.is_implicit_id or self.is_implicit_type:
@@ -158,6 +157,41 @@
name = self.name
return f' ColumnStorage<ColumnType::{name}::stored_type> {name}_;'
+ def iterator_getter(self) -> Optional[str]:
+ name = self.name
+ return f'''
+ ColumnType::{self.name}::type {name}() const {{
+ const auto& col = table_->{name}();
+ return col.GetAtIdx(its_[col.overlay_index()].index());
+ }}
+ '''
+
+ def iterator_setter(self) -> Optional[str]:
+ if self.is_implicit_id or self.is_implicit_type:
+ return None
+ return f'''
+ void set_{self.name}(ColumnType::{self.name}::non_optional_type v) {{
+ auto* col = mutable_table_->mutable_{self.name}();
+ col->SetAtIdx(its_[col->overlay_index()].index(), v);
+ }}
+ '''
+
+ def static_schema(self) -> Optional[str]:
+ if self.is_implicit_id or self.is_implicit_type:
+ return None
+ return f'''
+ schema.columns.emplace_back(Table::Schema::Column{{
+ "{self.name}", ColumnType::{self.name}::SqlValueType(), false,
+ {str(ColumnFlag.SORTED in self.flags).lower()},
+ {str(ColumnFlag.HIDDEN in self.flags).lower()},
+ {str(ColumnFlag.SET_ID in self.flags).lower()}}});
+ '''
+
+ def row_eq(self) -> Optional[str]:
+ if self.is_implicit_id or self.is_implicit_type:
+ return None
+ return f'ColumnType::{self.name}::Equals({self.name}, other.{self.name})'
+
class TableSerializer(object):
"""Functions for seralizing a single Table into C++."""
@@ -209,6 +243,7 @@
ColumnSerializer.parent_row_initializer, delimiter=', ')
row_init = self.foreach_col(
ColumnSerializer.row_initializer, delimiter=',\n ')
+ row_eq = self.foreach_col(ColumnSerializer.row_eq, delimiter=' &&\n ')
return f'''
struct Row : public {self.parent_class_name}::Row {{
Row({param},
@@ -218,6 +253,10 @@
type_ = "{self.table.sql_name}";
}}
{self.foreach_col(ColumnSerializer.row_field)}
+
+ bool operator==(const {self.table_name}::Row& other) const {{
+ return type() == other.type() && {row_eq};
+ }}
}};
'''
@@ -295,6 +334,55 @@
type_.Append(string_pool_->InternString(row.type()));
'''
+ def const_iterator(self) -> str:
+ iterator_getters = self.foreach_col(
+ ColumnSerializer.iterator_getter, delimiter='\n')
+ return f'''
+ class ConstIterator;
+ class ConstIterator : public macros_internal::AbstractConstIterator<
+ ConstIterator, {self.table_name}, RowNumber, ConstRowReference> {{
+ public:
+ {iterator_getters}
+
+ protected:
+ explicit ConstIterator(const {self.table_name}* table,
+ std::vector<ColumnStorageOverlay> overlays)
+ : AbstractConstIterator(table, std::move(overlays)) {{}}
+
+ uint32_t CurrentRowNumber() const {{
+ return its_.back().index();
+ }}
+
+ private:
+ friend class {self.table_name};
+ friend class AbstractConstIterator;
+ }};
+ '''
+
+ def iterator(self) -> str:
+ iterator_setters = self.foreach_col(
+ ColumnSerializer.iterator_setter, delimiter='\n')
+ return f'''
+ class Iterator : public ConstIterator {{
+ public:
+ {iterator_setters}
+
+ RowReference row_reference() const {{
+ return RowReference(mutable_table_, CurrentRowNumber());
+ }}
+
+ private:
+ friend class {self.table_name};
+
+ explicit Iterator({self.table_name}* table,
+ std::vector<ColumnStorageOverlay> overlays)
+ : ConstIterator(table, std::move(overlays)),
+ mutable_table_(table) {{}}
+
+ {self.table_name}* mutable_table_ = nullptr;
+ }};
+ '''
+
def serialize(self) -> str:
return f'''
class {self.table_name} : public macros_internal::MacroTable {{
@@ -307,10 +395,6 @@
{self.foreach_col(ColumnSerializer.coltype_enum)}
}};
{self.row_struct().strip()}
- struct IdAndRow {{
- uint32_t row;
- Id id;
- }};
struct ColumnFlag {{
{self.foreach_col(ColumnSerializer.flag)}
}};
@@ -331,11 +415,49 @@
{self.const_row_reference_struct().strip()}
{self.row_reference_struct().strip()}
+ {self.const_iterator().strip()}
+ {self.iterator().strip()}
+
+ struct IdAndRow {{
+ Id id;
+ uint32_t row;
+ RowReference row_reference;
+ RowNumber row_number;
+ }};
+
{self.constructor().strip()}
~{self.table_name}() override;
static const char* Name() {{ return "{self.table.sql_name}"; }}
+ static Table::Schema ComputeStaticSchema() {{
+ Table::Schema schema;
+ schema.columns.emplace_back(Table::Schema::Column{{
+ "id", SqlValue::Type::kLong, true, true, false, false}});
+ schema.columns.emplace_back(Table::Schema::Column{{
+ "type", SqlValue::Type::kString, false, false, false, false}});
+ {self.foreach_col(ColumnSerializer.static_schema)}
+ return schema;
+ }}
+
+ ConstIterator IterateRows() const {{
+ return ConstIterator(this, CopyOverlays());
+ }}
+
+ Iterator IterateRows() {{ return Iterator(this, CopyOverlays()); }}
+
+ ConstIterator FilterToIterator(
+ const std::vector<Constraint>& cs,
+ RowMap::OptimizeFor opt = RowMap::OptimizeFor::kMemory) const {{
+ return ConstIterator(this, FilterAndApplyToOverlays(cs, opt));
+ }}
+
+ Iterator FilterToIterator(
+ const std::vector<Constraint>& cs,
+ RowMap::OptimizeFor opt = RowMap::OptimizeFor::kMemory) {{
+ return Iterator(this, FilterAndApplyToOverlays(cs, opt));
+ }}
+
void ShrinkToFit() {{
{self.foreach_col(ColumnSerializer.shrink_to_fit)}
}}
@@ -356,7 +478,8 @@
{self.insert_common().strip()}
{self.foreach_col(ColumnSerializer.append)}
UpdateSelfOverlayAfterInsert();
- return IdAndRow{{row_number, std::move(id)}};
+ return IdAndRow{{std::move(id), row_number, RowReference(this, row_number),
+ RowNumber(row_number)}};
}}
{self.foreach_col(ColumnSerializer.accessor)}
@@ -395,3 +518,22 @@
#endif // {ifdef_guard}
'''.strip()
+
+
+def to_cpp_flags(raw_flag: ColumnFlag) -> str:
+ """Converts a ColumnFlag to the C++ flags which it represents
+
+ It is not valid to call this function with ColumnFlag.NONE as in this case
+ defaults for that column should be implicitly used."""
+
+ assert raw_flag != ColumnFlag.NONE
+ flags = []
+ if ColumnFlag.SORTED in raw_flag:
+ flags.append('Column::Flag::kSorted')
+ if ColumnFlag.HIDDEN in raw_flag:
+ flags.append('Column::Flag::kHidden')
+ if ColumnFlag.DENSE in raw_flag:
+ flags.append('Column::Flag::kDense')
+ if ColumnFlag.SET_ID in raw_flag:
+ flags.append('Column::Flag::kSetId')
+ return ' | '.join(flags)
diff --git a/python/generators/trace_processor_table/util.py b/python/generators/trace_processor_table/util.py
index 407bfc1..b6c38d8 100644
--- a/python/generators/trace_processor_table/util.py
+++ b/python/generators/trace_processor_table/util.py
@@ -19,12 +19,14 @@
from typing import List
from typing import Set
from typing import Optional
+from typing import Union
from python.generators.trace_processor_table.public import Alias
from python.generators.trace_processor_table.public import Column
from python.generators.trace_processor_table.public import ColumnDoc
from python.generators.trace_processor_table.public import ColumnFlag
from python.generators.trace_processor_table.public import CppColumnType
+from python.generators.trace_processor_table.public import CppDouble
from python.generators.trace_processor_table.public import CppInt32
from python.generators.trace_processor_table.public import CppInt64
from python.generators.trace_processor_table.public import CppOptional
@@ -101,6 +103,8 @@
return ParsedType('int32_t')
if isinstance(col_type, CppUint32):
return ParsedType('uint32_t')
+ if isinstance(col_type, CppDouble):
+ return ParsedType('double')
if isinstance(col_type, CppString):
return ParsedType('StringPool::Id')
@@ -161,36 +165,24 @@
wrapping_view = table.wrapping_sql_view
return wrapping_view.view_name if wrapping_view else table.sql_name
-
-def to_cpp_flags(raw_flag: ColumnFlag) -> str:
- """Converts a ColumnFlag to the C++ flags which it represents
-
- It is not valid to call this function with ColumnFlag.NONE as in this case
- defaults for that column should be implicitly used."""
-
- assert raw_flag != ColumnFlag.NONE
- flags = []
- if ColumnFlag.SORTED in raw_flag:
- flags.append('Column::Flag::kSorted')
- if ColumnFlag.SET_ID in raw_flag:
- flags.append('Column::Flag::kSetId')
- return ' | '.join(flags)
-
-
def _create_implicit_columns_for_root(parsed: ParsedTable
) -> List[ParsedColumn]:
"""Given a root table, returns the implicit id and type columns."""
- assert parsed.table.parent is None
+ table = parsed.table
+ assert table.parent is None
- sql_name = public_sql_name(parsed.table)
+ sql_name = public_sql_name(table)
+ id_doc = table.tabledoc.columns.get('id') if table.tabledoc else None
+ type_doc = table.tabledoc.columns.get('type') if table.tabledoc else None
return [
ParsedColumn(
Column('id', CppSelfTableId(), ColumnFlag.SORTED),
- ColumnDoc(doc=f'Unique idenitifier for this {sql_name}.'),
+ _to_column_doc(id_doc) if id_doc else ColumnDoc(
+ doc=f'Unique idenitifier for this {sql_name}.'),
is_implicit_id=True),
ParsedColumn(
Column('type', CppString(), ColumnFlag.NONE),
- ColumnDoc(doc='''
+ _to_column_doc(type_doc) if type_doc else ColumnDoc(doc='''
The name of the "most-specific" child table containing this
row.
'''),
@@ -226,6 +218,14 @@
return result
+def _to_column_doc(doc: Union[ColumnDoc, str, None]) -> Optional[ColumnDoc]:
+ """Cooerces a user specified ColumnDoc or string into a ColumnDoc."""
+
+ if doc is None or isinstance(doc, ColumnDoc):
+ return doc
+ return ColumnDoc(doc=doc)
+
+
def parse_tables_from_files(input_paths: List[str]) -> List[ParsedTable]:
"""Creates a list of tables with the associated paths."""
@@ -244,9 +244,10 @@
# Create the list of parsed columns
for i, parsed in enumerate(sorted_tables):
parsed_columns: List[ParsedColumn]
+ table = parsed.table
- if parsed.table.parent:
- parsed_parent = parsed_tables[parsed.table.parent.class_name]
+ if table.parent:
+ parsed_parent = parsed_tables[table.parent.class_name]
parsed_columns = [
dataclasses.replace(c, is_ancestor=True)
for c in parsed_parent.columns
@@ -254,19 +255,11 @@
else:
parsed_columns = _create_implicit_columns_for_root(parsed)
- for c in parsed.table.columns:
- doc = parsed.table.tabledoc.columns.get(c.name)
- columndoc: Optional[ColumnDoc]
- if not doc:
- columndoc = None
- elif isinstance(doc, ColumnDoc):
- columndoc = doc
- else:
- columndoc = ColumnDoc(doc=doc)
- parsed_columns.append(ParsedColumn(c, columndoc))
+ for c in table.columns:
+ doc = table.tabledoc.columns.get(c.name) if table.tabledoc else None
+ parsed_columns.append(ParsedColumn(c, _to_column_doc(doc)))
- new_table = dataclasses.replace(parsed, columns=parsed_columns)
- parsed_tables[parsed.table.class_name] = new_table
- sorted_tables[i] = new_table
+ sorted_tables[i] = dataclasses.replace(parsed, columns=parsed_columns)
+ parsed_tables[parsed.table.class_name] = sorted_tables[i]
return sorted_tables