Skip to content

Commit 1d1755d

Browse files
committed
Switch MemtableAverageRowSize to use trie directly and expand test
1 parent 7b9bcc7 commit 1d1755d

File tree

8 files changed

+89
-16
lines changed

8 files changed

+89
-16
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package org.apache.cassandra.db;
20+
21+
/// Shared interface for providing data size information
22+
public interface IDataSize
23+
{
24+
int dataSize();
25+
}

src/java/org/apache/cassandra/db/memtable/MemtableAverageRowSize.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,15 @@
1818

1919
package org.apache.cassandra.db.memtable;
2020

21+
import java.util.function.Consumer;
22+
2123
import org.apache.cassandra.db.DataRange;
24+
import org.apache.cassandra.db.IDataSize;
2225
import org.apache.cassandra.db.filter.ColumnFilter;
2326
import org.apache.cassandra.db.rows.Row;
2427
import org.apache.cassandra.db.rows.Unfiltered;
2528
import org.apache.cassandra.db.rows.UnfilteredRowIterator;
29+
import org.apache.cassandra.db.tries.Trie;
2630

2731
class MemtableAverageRowSize
2832
{
@@ -31,6 +35,35 @@ class MemtableAverageRowSize
3135
public final long rowSize;
3236
public final long operations;
3337

38+
public MemtableAverageRowSize(Memtable memtable, Trie<?> trie)
39+
{
40+
// If this is a trie-based memtable, get the row sizes from the trie elements. This achieves two things:
41+
// - makes sure the size used is the size reflected in the memtable's dataSize
42+
// (which e.g. excludes clustering keys)
43+
// - avoids the conversion to Row, which has non-trivial cost
44+
45+
class SizeCalculator implements Trie.ValueConsumer<Object>
46+
{
47+
long totalSize = 0;
48+
long count = 0;
49+
50+
@Override
51+
public void accept(Object o)
52+
{
53+
if (o instanceof IDataSize)
54+
{
55+
totalSize += ((IDataSize) o).dataSize();
56+
++count;
57+
}
58+
}
59+
}
60+
61+
SizeCalculator sizeCalculator = new SizeCalculator();
62+
trie.forEachValue(sizeCalculator);
63+
64+
this.rowSize = sizeCalculator.count > 0 ? sizeCalculator.totalSize / sizeCalculator.count : 0;
65+
this.operations = memtable.getOperations();
66+
}
3467

3568
public MemtableAverageRowSize(Memtable memtable)
3669
{

src/java/org/apache/cassandra/db/memtable/TrieMemtable.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ public int getShardCount()
299299
public long getEstimatedAverageRowSize()
300300
{
301301
if (estimatedAverageRowSize == null || currentOperations.get() > estimatedAverageRowSize.operations * 1.5)
302-
estimatedAverageRowSize = new MemtableAverageRowSize(this);
302+
estimatedAverageRowSize = new MemtableAverageRowSize(this, mergedTrie.contentOnlyTrie());
303303
return estimatedAverageRowSize.rowSize;
304304
}
305305

src/java/org/apache/cassandra/db/memtable/TrieMemtableStage2.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ public int getShardCount()
307307
public long getEstimatedAverageRowSize()
308308
{
309309
if (estimatedAverageRowSize == null || currentOperations.get() > estimatedAverageRowSize.operations * 1.5)
310-
estimatedAverageRowSize = new MemtableAverageRowSize(this);
310+
estimatedAverageRowSize = new MemtableAverageRowSize(this, mergedTrie);
311311
return estimatedAverageRowSize.rowSize;
312312
}
313313

src/java/org/apache/cassandra/db/partitions/TrieBackedPartition.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.apache.cassandra.db.ClusteringPrefix;
3131
import org.apache.cassandra.db.DecoratedKey;
3232
import org.apache.cassandra.db.DeletionTime;
33+
import org.apache.cassandra.db.IDataSize;
3334
import org.apache.cassandra.db.LivenessInfo;
3435
import org.apache.cassandra.db.RegularAndStaticColumns;
3536
import org.apache.cassandra.db.Slice;
@@ -113,7 +114,7 @@ public static boolean isPartitionBoundary(Object content)
113114
/// The representation of a row stored at the leaf of a trie. Does not contain the row key.
114115
///
115116
/// The method [#toRow] combines this with a clustering for the represented [Row].
116-
public static class RowData
117+
public static class RowData implements IDataSize
117118
{
118119
final Object[] columnsBTree;
119120
final LivenessInfo livenessInfo;

src/java/org/apache/cassandra/db/partitions/TrieBackedPartitionStage2.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.apache.cassandra.db.DecoratedKey;
3232
import org.apache.cassandra.db.DeletionInfo;
3333
import org.apache.cassandra.db.DeletionTime;
34+
import org.apache.cassandra.db.IDataSize;
3435
import org.apache.cassandra.db.LivenessInfo;
3536
import org.apache.cassandra.db.MutableDeletionInfo;
3637
import org.apache.cassandra.db.RangeTombstone;
@@ -98,7 +99,7 @@ public class TrieBackedPartitionStage2 implements Partition
9899
*
99100
* The methods toRow and copyToOnHeapRow combine this with a clustering for the represented Row.
100101
*/
101-
public static class RowData
102+
public static class RowData implements IDataSize
102103
{
103104
final Object[] columnsBTree;
104105
final LivenessInfo livenessInfo;

src/java/org/apache/cassandra/db/rows/Row.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
* it's own data. For instance, a {@code Row} cannot contains a cell that is deleted by its own
5252
* row deletion.
5353
*/
54-
public interface Row extends Unfiltered, Iterable<ColumnData>
54+
public interface Row extends Unfiltered, Iterable<ColumnData>, IDataSize
5555
{
5656
/**
5757
* The clustering values for this row.

test/unit/org/apache/cassandra/index/sai/plan/SingleRestrictionEstimatedRowCountTest.java

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import java.util.Map;
2626

2727
import org.junit.Test;
28+
import org.junit.runner.RunWith;
29+
import org.junit.runners.Parameterized;
2830

2931
import org.apache.cassandra.Util;
3032
import org.apache.cassandra.cql3.CQL3Type;
@@ -43,8 +45,18 @@
4345
import static org.junit.Assert.assertNotNull;
4446
import static org.junit.Assert.fail;
4547

48+
@RunWith(Parameterized.class)
4649
public class SingleRestrictionEstimatedRowCountTest extends SAITester
4750
{
51+
@Parameterized.Parameter
52+
public String memtableClass;
53+
54+
@Parameterized.Parameters(name = "{0}")
55+
public static String[] memtableClasses()
56+
{
57+
return new String[]{ "TrieMemtable", "TrieMemtableStage2", "TrieMemtableStage1" };
58+
}
59+
4860
static protected Map<Map.Entry<Version, CQL3Type.Native>, ColumnFamilyStore> tables = new HashMap<>();
4961
static Version[] versions = new Version[]{ Version.DB, Version.EB };
5062
static CQL3Type.Native[] types = new CQL3Type.Native[]{ INT, DECIMAL, VARINT };
@@ -75,12 +87,12 @@ public void testMemtablesSAI()
7587
createTables();
7688

7789
RowCountTest test = new RowCountTest(Operator.NEQ, 25);
78-
test.doTest(Version.DB, INT, 97.0);
79-
test.doTest(Version.EB, INT, 97.0);
90+
test.doTest(Version.DB, INT, 100);
91+
test.doTest(Version.EB, INT, 100);
8092
// Truncated numeric types planned differently
81-
test.doTest(Version.DB, DECIMAL, 97.0);
82-
test.doTest(Version.EB, DECIMAL, 97.0);
83-
test.doTest(Version.EB, VARINT, 97.0);
93+
test.doTest(Version.DB, DECIMAL, 100);
94+
test.doTest(Version.EB, DECIMAL, 100);
95+
test.doTest(Version.EB, VARINT, 100);
8496

8597
test = new RowCountTest(Operator.LT, 50);
8698
test.doTest(Version.DB, INT, 48);
@@ -89,10 +101,10 @@ public void testMemtablesSAI()
89101
test.doTest(Version.EB, DECIMAL, 48);
90102

91103
test = new RowCountTest(Operator.LT, 150);
92-
test.doTest(Version.DB, INT, 97);
93-
test.doTest(Version.EB, INT, 97);
94-
test.doTest(Version.DB, DECIMAL, 97);
95-
test.doTest(Version.EB, DECIMAL, 97);
104+
test.doTest(Version.DB, INT, 100);
105+
test.doTest(Version.EB, INT, 100);
106+
test.doTest(Version.DB, DECIMAL, 100);
107+
test.doTest(Version.EB, DECIMAL, 100);
96108

97109
test = new RowCountTest(Operator.EQ, 31);
98110
test.doTest(Version.DB, INT, 15);
@@ -109,7 +121,8 @@ void createTables()
109121
SAIUtil.setLatestVersion(version);
110122
for (CQL3Type.Native type : types)
111123
{
112-
createTable("CREATE TABLE %s (pk text PRIMARY KEY, age " + type + ')');
124+
createTable("CREATE TABLE %s (pk text PRIMARY KEY, age " + type + ") " +
125+
"WITH memtable = {'class': '" + memtableClass + "'}");
113126
createIndex("CREATE CUSTOM INDEX ON %s(age) USING 'StorageAttachedIndex'");
114127
tables.put(tablesEntryKey(version, type), getCurrentColumnFamilyStore());
115128
}
@@ -159,7 +172,7 @@ void doTest(Version version, CQL3Type.Native type, double expectedRows)
159172

160173
long totalRows = controller.planFactory.tableMetrics.rows;
161174
assertEquals(0, cfs.metrics().liveSSTableCount.getValue().intValue());
162-
assertEquals(97, totalRows);
175+
assertEquals(100, totalRows);
163176

164177
Plan plan = controller.buildPlan();
165178
assert plan instanceof Plan.RowsIteration;

0 commit comments

Comments
 (0)