Merge branch 'cassandra-2.0' into trunk

This commit is contained in:
Jonathan Ellis 2013-10-01 14:20:53 -05:00
commit ca697d5913
12 changed files with 100 additions and 24 deletions

View File

@ -7,6 +7,7 @@
2.0.2 2.0.2
* drop queries exceeding a configurable number of tombstones (CASSANDRA-6117)
* Track and persist sstable read activity (CASSANDRA-5515) * Track and persist sstable read activity (CASSANDRA-5515)
* Fixes for speculative retry (CASSANDRA-5932) * Fixes for speculative retry (CASSANDRA-5932)
* Improve memory usage of metadata min/max column names (CASSANDRA-6077) * Improve memory usage of metadata min/max column names (CASSANDRA-6077)

View File

@ -34,6 +34,14 @@ New features
- Speculative retry defaults to 99th percentile - Speculative retry defaults to 99th percentile
(See blog post at TODO) (See blog post at TODO)
Upgrading
---------
- tombstone_debug_threshold from 1.2.11 has been changed to
tombstone_warn_threshold and tombstone_failure_threshold.
Adjust these if your application relies on scanning a large
number of tombstones; see the comments in cassandra.yaml for why
this is dangerous.
2.0.1 2.0.1
===== =====

View File

@ -404,10 +404,17 @@ snapshot_before_compaction: false
# lose data on truncation or drop. # lose data on truncation or drop.
auto_snapshot: true auto_snapshot: true
# Log a debug message if more than this many tombstones are scanned # When executing a scan, within or across a partition, we need to keep the
# in a single-partition query. Set the threshold on SliceQueryFilter # tombstones seen in memory so we can return them to the coordinator, which
# to debug to enable. # will use them to make sure other replicas also know about the deleted rows.
tombstone_debug_threshold: 10000 # With workloads that generate a lot of tombstones, this can cause performance
# problems and even exaust the server heap.
# (http://www.datastax.com/dev/blog/cassandra-anti-patterns-queues-and-queue-like-datasets)
# Adjust the thresholds here if you understand the dangers and want to
# scan more tombstones anyway. These thresholds may also be adjusted at runtime
# using the StorageService mbean.
tombstone_warn_threshold: 1000
tombstone_failure_threshold: 100000
# Add column indexes to a row after its contents reach this size. # Add column indexes to a row after its contents reach this size.
# Increase if your column values are large, or if you have a very large # Increase if your column values are large, or if you have a very large

View File

@ -179,7 +179,8 @@ public class Config
private static boolean outboundBindAny = false; private static boolean outboundBindAny = false;
public volatile int tombstone_debug_threshold = 10000; public volatile int tombstone_warn_threshold = 1000;
public volatile int tombstone_failure_threshold = 100000;
public static boolean getOutboundBindAny() public static boolean getOutboundBindAny()
{ {

View File

@ -890,18 +890,24 @@ public class DatabaseDescriptor
return conf.commitlog_directory; return conf.commitlog_directory;
} }
/** public static int getTombstoneWarnThreshold()
* How many tombstones need to be scanned before we log a
* debug message
*/
public static int getTombstoneDebugThreshold()
{ {
return conf.tombstone_debug_threshold; return conf.tombstone_warn_threshold;
} }
public static void setTombstoneDebugThreshold(int tombstoneDebugThreshold) public static void setTombstoneWarnThreshold(int threshold)
{ {
conf.tombstone_debug_threshold = tombstoneDebugThreshold; conf.tombstone_warn_threshold = threshold;
}
public static int getTombstoneFailureThreshold()
{
return conf.tombstone_failure_threshold;
}
public static void setTombstoneFailureThreshold(int threshold)
{
conf.tombstone_failure_threshold = threshold;
} }
/** /**

View File

@ -20,6 +20,7 @@ package org.apache.cassandra.db;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.apache.cassandra.db.filter.TombstoneOverwhelmingException;
import org.apache.cassandra.net.IVerbHandler; import org.apache.cassandra.net.IVerbHandler;
import org.apache.cassandra.net.MessageIn; import org.apache.cassandra.net.MessageIn;
import org.apache.cassandra.net.MessageOut; import org.apache.cassandra.net.MessageOut;
@ -40,7 +41,16 @@ public class ReadVerbHandler implements IVerbHandler<ReadCommand>
ReadCommand command = message.payload; ReadCommand command = message.payload;
Keyspace keyspace = Keyspace.open(command.ksName); Keyspace keyspace = Keyspace.open(command.ksName);
Row row = command.getRow(keyspace); Row row;
try
{
row = command.getRow(keyspace);
}
catch (TombstoneOverwhelmingException e)
{
// error already logged. Drop the request
return;
}
MessageOut<ReadResponse> reply = new MessageOut<ReadResponse>(MessagingService.Verb.REQUEST_RESPONSE, MessageOut<ReadResponse> reply = new MessageOut<ReadResponse>(MessagingService.Verb.REQUEST_RESPONSE,
getResponse(command, row), getResponse(command, row),

View File

@ -29,4 +29,10 @@ public class IdentityQueryFilter extends SliceQueryFilter
{ {
super(ByteBufferUtil.EMPTY_BYTE_BUFFER, ByteBufferUtil.EMPTY_BYTE_BUFFER, false, Integer.MAX_VALUE); super(ByteBufferUtil.EMPTY_BYTE_BUFFER, ByteBufferUtil.EMPTY_BYTE_BUFFER, false, Integer.MAX_VALUE);
} }
@Override
protected boolean respectTombstoneFailures()
{
return false;
}
} }

View File

@ -194,12 +194,24 @@ public class SliceQueryFilter implements IDiskAtomFilter
if (columnCounter.live() > count) if (columnCounter.live() > count)
break; break;
if (respectTombstoneFailures() && columnCounter.ignored() > DatabaseDescriptor.getTombstoneFailureThreshold())
{
Tracing.trace("Scanned over {} tombstones; query aborted (see tombstone_fail_threshold)", DatabaseDescriptor.getTombstoneFailureThreshold());
logger.error("Scanned over {} tombstones; query aborted (see tombstone_fail_threshold)", DatabaseDescriptor.getTombstoneFailureThreshold());
throw new TombstoneOverwhelmingException();
}
container.addIfRelevant(column, tester, gcBefore); container.addIfRelevant(column, tester, gcBefore);
} }
Tracing.trace("Read {} live and {} tombstoned cells", columnCounter.live(), columnCounter.ignored()); Tracing.trace("Read {} live and {} tombstoned cells", columnCounter.live(), columnCounter.ignored());
if (columnCounter.ignored() > DatabaseDescriptor.getTombstoneDebugThreshold()) if (columnCounter.ignored() > DatabaseDescriptor.getTombstoneWarnThreshold())
logger.debug("Read {} live and {} tombstoned cells", columnCounter.live(), columnCounter.ignored()); logger.warn("Read {} live and {} tombstoned cells (see tombstone_warn_threshold)", columnCounter.live(), columnCounter.ignored());
}
protected boolean respectTombstoneFailures()
{
return true;
} }
public int getLiveCount(ColumnFamily cf, long now) public int getLiveCount(ColumnFamily cf, long now)

View File

@ -0,0 +1,5 @@
package org.apache.cassandra.db.filter;
public class TombstoneOverwhelmingException extends RuntimeException
{
}

View File

@ -19,6 +19,7 @@ package org.apache.cassandra.service;
import org.apache.cassandra.db.AbstractRangeCommand; import org.apache.cassandra.db.AbstractRangeCommand;
import org.apache.cassandra.db.RangeSliceReply; import org.apache.cassandra.db.RangeSliceReply;
import org.apache.cassandra.db.filter.TombstoneOverwhelmingException;
import org.apache.cassandra.net.IVerbHandler; import org.apache.cassandra.net.IVerbHandler;
import org.apache.cassandra.net.MessageIn; import org.apache.cassandra.net.MessageIn;
import org.apache.cassandra.net.MessagingService; import org.apache.cassandra.net.MessagingService;
@ -39,6 +40,10 @@ public class RangeSliceVerbHandler implements IVerbHandler<AbstractRangeCommand>
Tracing.trace("Enqueuing response to {}", message.from); Tracing.trace("Enqueuing response to {}", message.from);
MessagingService.instance().sendReply(reply.createMessage(), id, message.from); MessagingService.instance().sendReply(reply.createMessage(), id, message.from);
} }
catch (TombstoneOverwhelmingException e)
{
// error already logged. Drop the request
}
catch (Exception ex) catch (Exception ex)
{ {
throw new RuntimeException(ex); throw new RuntimeException(ex);

View File

@ -3652,13 +3652,23 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
return DatabaseDescriptor.getPartitionerName(); return DatabaseDescriptor.getPartitionerName();
} }
public int getTombstoneDebugThreshold() public int getTombstoneWarnThreshold()
{ {
return DatabaseDescriptor.getTombstoneDebugThreshold(); return DatabaseDescriptor.getTombstoneWarnThreshold();
} }
public void setTombstoneDebugThreshold(int tombstoneDebugThreshold) public void setTombstoneWarnThreshold(int threshold)
{ {
DatabaseDescriptor.setTombstoneDebugThreshold(tombstoneDebugThreshold); DatabaseDescriptor.setTombstoneWarnThreshold(threshold);
}
public int getTombstoneFailureThreshold()
{
return DatabaseDescriptor.getTombstoneFailureThreshold();
}
public void setTombstoneFailureThreshold(int threshold)
{
DatabaseDescriptor.setTombstoneFailureThreshold(threshold);
} }
} }

View File

@ -477,8 +477,13 @@ public interface StorageServiceMBean extends NotificationEmitter
/** Returns the cluster partitioner */ /** Returns the cluster partitioner */
public String getPartitionerName(); public String getPartitionerName();
/** Returns the threshold for returning debugging queries with many tombstones */ /** Returns the threshold for warning of queries with many tombstones */
public int getTombstoneDebugThreshold(); public int getTombstoneWarnThreshold();
/** Sets the threshold for returning debugging queries with many tombstones */ /** Sets the threshold for warning queries with many tombstones */
public void setTombstoneDebugThreshold(int tombstoneDebugThreshold); public void setTombstoneWarnThreshold(int tombstoneDebugThreshold);
/** Returns the threshold for abandoning queries with many tombstones */
public int getTombstoneFailureThreshold();
/** Sets the threshold for abandoning queries with many tombstones */
public void setTombstoneFailureThreshold(int tombstoneDebugThreshold);
} }