Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
5.0.9
* BTree.FastBuilder.reset() fails to clear savedBuffer and savedNextKey, causing ClassCastException and SSTable header corruption during schema disagreement (CASSANDRA-21216, CASSANDRA-21260)
* Fix failing select on system_views.settings for non-string keys (CASSANDRA-21348)
* Ensure SAI sends range tombstones to the coordinator for queries on static columns (CASSANDRA-21332)
Merged from 4.1:
Expand Down
120 changes: 51 additions & 69 deletions src/java/org/apache/cassandra/utils/btree/BTree.java
Original file line number Diff line number Diff line change
Expand Up @@ -3269,11 +3269,58 @@ final LeafBuilder leaf()

/**
* Clear any references we might still retain, to avoid holding onto memory.
* <p>
* While this method is not strictly necessary, it exists to
* ensure the implementing classes are aware they must handle it.
*/
abstract void reset();
void reset()
{
leaf().count = 0;
clearLeafBuffer(leaf().buffer);
if (leaf().savedBuffer != null && leaf().savedBuffer[0] != null)
Arrays.fill(leaf().savedBuffer, null);
leaf().savedNextKey = null;
BranchBuilder branch = leaf().parent;
while (branch != null && branch.inUse)
{
branch.count = 0;
clearBranchBuffer(branch.buffer);
if (branch.savedBuffer != null && branch.savedBuffer[0] != null)
Arrays.fill(branch.savedBuffer, null); // by definition full, if non-empty
branch.savedNextKey = null;
branch.inUse = false;
branch = branch.parent;
}
}

/**
* Clear the contents of a leaf buffer, aborting once we encounter a null entry
* to save time on small trees
*/
private void clearLeafBuffer(Object[] array)
{
if (array[0] == null)
return;
// find first null entry; loop from beginning, to amortise cost over size of working set
int i = 1;
while (i < array.length && array[i] != null)
++i;
Arrays.fill(array, 0, i, null);
}

/**
* Clear the contents of a branch buffer, aborting once we encounter a null entry
* to save time on small trees
*/
private void clearBranchBuffer(Object[] array)
{
if (array[0] == null)
return;

// find first null entry; loop from beginning, to amortise cost over size of working set
int i = 1;
while (i < MAX_KEYS && array[i] != null)
++i;
Arrays.fill(array, 0, i, null);
Arrays.fill(array, MAX_KEYS, MAX_KEYS + i + 1, null);
}
}

/**
Expand Down Expand Up @@ -3325,21 +3372,6 @@ public void close()
}
}

@Override
void reset()
{
Arrays.fill(leaf().buffer, null);
leaf().count = 0;
BranchBuilder branch = leaf().parent;
while (branch != null && branch.inUse)
{
Arrays.fill(branch.buffer, null);
branch.count = 0;
branch.inUse = false;
branch = branch.parent;
}
}

public boolean validateEmpty()
{
LeafOrBranchBuilder cur = leaf();
Expand Down Expand Up @@ -3368,56 +3400,6 @@ private static boolean hasOnlyNulls(Object[] buffer)

private static abstract class AbstractUpdater extends AbstractFastBuilder implements AutoCloseable
{
void reset()
{
assert leaf().count == 0;
clearLeafBuffer(leaf().buffer);
if (leaf().savedBuffer != null)
Arrays.fill(leaf().savedBuffer, null);

BranchBuilder branch = leaf().parent;
while (branch != null && branch.inUse)
{
assert branch.count == 0;
clearBranchBuffer(branch.buffer);
if (branch.savedBuffer != null && branch.savedBuffer[0] != null)
Arrays.fill(branch.savedBuffer, null); // by definition full, if non-empty
branch.inUse = false;
branch = branch.parent;
}
}

/**
* Clear the contents of a branch buffer, aborting once we encounter a null entry
* to save time on small trees
*/
private void clearLeafBuffer(Object[] array)
{
if (array[0] == null)
return;
// find first null entry; loop from beginning, to amortise cost over size of working set
int i = 1;
while (i < array.length && array[i] != null)
++i;
Arrays.fill(array, 0, i, null);
}

/**
* Clear the contents of a branch buffer, aborting once we encounter a null entry
* to save time on small trees
*/
private void clearBranchBuffer(Object[] array)
{
if (array[0] == null)
return;

// find first null entry; loop from beginning, to amortise cost over size of working set
int i = 1;
while (i < MAX_KEYS && array[i] != null)
++i;
Arrays.fill(array, 0, i, null);
Arrays.fill(array, MAX_KEYS, MAX_KEYS + i + 1, null);
}
}

/**
Expand Down
Loading