[ 
https://issues.apache.org/jira/browse/CASSANDRA-21620?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Michael Semb Wever updated CASSANDRA-21620:
-------------------------------------------
    Description: 
For an sstable version that still carries the legacy minimum and maximum 
clustering values, {{StatsMetadata.StatsMetadataSerializer.serialize}} writes 
the components of each bound up to the first null one, and writes that count:

{code:java}
out.writeInt(countUntilNull(minClusteringValues.getBufferArray()));
for (ByteBuffer value : minClusteringValues.getBufferArray())
{
    if (value == null)
        break;
    ByteBufferUtil.writeWithShortLength(value, out);
}
{code}

{{serializedSize}} charges two length bytes for every component the bound 
holds, null ones included:

{code:java}
size += minClusteringValues.size() * 2 /* short length */ + 
minClusteringValues.dataSize();
{code}

A bound that {{MetadataCollector}} builds holds one entry per clustering 
column, so a covered clustering that stops short of the last column makes the 
two disagree. {{dataSize()}} already counts a null component as zero bytes, so 
the difference is the two length bytes alone.

{{MetadataSerializer.serialize}} derives the table-of-contents offset of each 
component from the returned size, and writes the whole backing array of a 
buffer allocated to that size. The STATS component therefore ends with two 
unused bytes per absent component. The file stays readable: the reader takes 
the length of each component from the offsets and stops once it has read the 
recorded count.

No production write reaches the disagreement today, which is why the ticket is 
Low. A writer uses the latest version of its format, where 
{{hasLegacyMinMax()}} is false, and a metadata mutation on an older sstable 
rebuilds the bounds from disk, where they carry exactly the components that 
were written and no nulls. The legacy branch is deprecated and due for removal 
after {{oa}}; until then the two halves of the serializer must agree, because 
the offset arithmetic depends on it.

The patch sizes both bounds with {{countUntilNull}}, the same count the writer 
uses.

Patch: 
[mck/CASSANDRA-21620/trunk|https://github.com/thelastpickle/cassandra/tree/mck/CASSANDRA-21620/trunk]
Provenance: 
[f57af096a0|https://github.com/datastax/cassandra/commit/f57af096a0a9b5225d46dc860ab683d26156a013]
 by Jacek Lewandowski. That commit repairs the size computation only; the 
writer already counts to the first null upstream.

  was:
For an sstable version that still carries the legacy minimum and maximum 
clustering values, {{StatsMetadata.StatsMetadataSerializer.serialize}} writes 
the components of each bound up to the first null one, and writes that count:

{code:java}
out.writeInt(countUntilNull(minClusteringValues.getBufferArray()));
for (ByteBuffer value : minClusteringValues.getBufferArray())
{
    if (value == null)
        break;
    ByteBufferUtil.writeWithShortLength(value, out);
}
{code}

{{serializedSize}} charges two length bytes for every component the bound 
holds, null ones included:

{code:java}
size += minClusteringValues.size() * 2 /* short length */ + 
minClusteringValues.dataSize();
{code}

A bound that {{MetadataCollector}} builds holds one entry per clustering 
column, so a covered clustering that stops short of the last column makes the 
two disagree. {{dataSize()}} already counts a null component as zero bytes, so 
the difference is the two length bytes alone.

{{MetadataSerializer.serialize}} derives the table-of-contents offset of each 
component from the returned size, and writes the whole backing array of a 
buffer allocated to that size. The STATS component therefore ends with two 
unused bytes per absent component. The file stays readable: the reader takes 
the length of each component from the offsets and stops once it has read the 
recorded count.

No production write reaches the disagreement today, which is why the ticket is 
Low. A writer uses the latest version of its format, where 
{{hasLegacyMinMax()}} is false, and a metadata mutation on an older sstable 
rebuilds the bounds from disk, where they carry exactly the components that 
were written and no nulls. The legacy branch is deprecated and due for removal 
after {{oa}}; until then the two halves of the serializer must agree, because 
the offset arithmetic depends on it.

The patch sizes both bounds with {{countUntilNull}}, the same count the writer 
uses.

Patch: 
[mck/upstream/stats-metadata-legacy-min-max-size/trunk|https://github.com/thelastpickle/cassandra/tree/mck/upstream/stats-metadata-legacy-min-max-size/trunk]
Provenance: 
[f57af096a0|https://github.com/datastax/cassandra/commit/f57af096a0a9b5225d46dc860ab683d26156a013]
 by Jacek Lewandowski. That commit repairs the size computation only; the 
writer already counts to the first null upstream.


> Stats metadata over-sizes the legacy minimum and maximum clustering values
> --------------------------------------------------------------------------
>
>                 Key: CASSANDRA-21620
>                 URL: https://issues.apache.org/jira/browse/CASSANDRA-21620
>             Project: Apache Cassandra
>          Issue Type: Bug
>          Components: Local/SSTable
>            Reporter: Michael Semb Wever
>            Priority: Normal
>             Fix For: 7.x
>
>
> For an sstable version that still carries the legacy minimum and maximum 
> clustering values, {{StatsMetadata.StatsMetadataSerializer.serialize}} writes 
> the components of each bound up to the first null one, and writes that count:
> {code:java}
> out.writeInt(countUntilNull(minClusteringValues.getBufferArray()));
> for (ByteBuffer value : minClusteringValues.getBufferArray())
> {
>     if (value == null)
>         break;
>     ByteBufferUtil.writeWithShortLength(value, out);
> }
> {code}
> {{serializedSize}} charges two length bytes for every component the bound 
> holds, null ones included:
> {code:java}
> size += minClusteringValues.size() * 2 /* short length */ + 
> minClusteringValues.dataSize();
> {code}
> A bound that {{MetadataCollector}} builds holds one entry per clustering 
> column, so a covered clustering that stops short of the last column makes the 
> two disagree. {{dataSize()}} already counts a null component as zero bytes, 
> so the difference is the two length bytes alone.
> {{MetadataSerializer.serialize}} derives the table-of-contents offset of each 
> component from the returned size, and writes the whole backing array of a 
> buffer allocated to that size. The STATS component therefore ends with two 
> unused bytes per absent component. The file stays readable: the reader takes 
> the length of each component from the offsets and stops once it has read the 
> recorded count.
> No production write reaches the disagreement today, which is why the ticket 
> is Low. A writer uses the latest version of its format, where 
> {{hasLegacyMinMax()}} is false, and a metadata mutation on an older sstable 
> rebuilds the bounds from disk, where they carry exactly the components that 
> were written and no nulls. The legacy branch is deprecated and due for 
> removal after {{oa}}; until then the two halves of the serializer must agree, 
> because the offset arithmetic depends on it.
> The patch sizes both bounds with {{countUntilNull}}, the same count the 
> writer uses.
> Patch: 
> [mck/CASSANDRA-21620/trunk|https://github.com/thelastpickle/cassandra/tree/mck/CASSANDRA-21620/trunk]
> Provenance: 
> [f57af096a0|https://github.com/datastax/cassandra/commit/f57af096a0a9b5225d46dc860ab683d26156a013]
>  by Jacek Lewandowski. That commit repairs the size computation only; the 
> writer already counts to the first null upstream.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to