Merge branch 'cassandra-2.0' into cassandra-2.1

Conflicts:
	CHANGES.txt
	src/java/org/apache/cassandra/db/ColumnFamilyStore.java
	src/java/org/apache/cassandra/db/commitlog/CommitLogAllocator.java
This commit is contained in:
Sylvain Lebresne 2014-05-21 17:49:40 +02:00
commit e024a1cc2b
10 changed files with 169 additions and 125 deletions

View File

@ -58,6 +58,9 @@ Merged from 2.0:
* Fix writetime/ttl functions for static columns (CASSANDRA-7081)
* Suggest CTRL-C or semicolon after three blank lines in cqlsh (CASSANDRA-7142)
* Fix 2ndary index queries with DESC clustering order (CASSANDRA-6950)
* Invalid key cache entries on DROP (CASSANDRA-6525)
* Fix flapping RecoveryManagerTest (CASSANDRA-7084)
* Add missing iso8601 patterns for date strings (6973)
Merged from 1.2:
* Add Cloudstack snitch (CASSANDRA-7147)
* Update system.peers correctly when relocating tokens (CASSANDRA-7126)

View File

@ -373,6 +373,7 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean
indexManager.invalidate();
CacheService.instance.invalidateRowCacheForCf(metadata.cfId);
CacheService.instance.invalidateKeyCacheForCf(metadata.cfId);
}
/**

View File

@ -53,43 +53,7 @@ public class DateType extends AbstractType<Date>
if (source.isEmpty())
return ByteBufferUtil.EMPTY_BYTE_BUFFER;
return ByteBufferUtil.bytes(dateStringToTimestamp(source));
}
public static long dateStringToTimestamp(String source) throws MarshalException
{
long millis;
if (source.toLowerCase().equals("now"))
{
millis = System.currentTimeMillis();
}
// Milliseconds since epoch?
else if (source.matches("^-?\\d+$"))
{
try
{
millis = Long.parseLong(source);
}
catch (NumberFormatException e)
{
throw new MarshalException(String.format("unable to make long (for date) from: '%s'", source), e);
}
}
// Last chance, attempt to parse as date-time string
else
{
try
{
millis = DateUtils.parseDateStrictly(source, TimestampSerializer.iso8601Patterns).getTime();
}
catch (ParseException e1)
{
throw new MarshalException(String.format("unable to coerce '%s' to a formatted date (long)", source), e1);
}
}
return millis;
return ByteBufferUtil.bytes(TimestampSerializer.dateStringToTimestamp(source));
}
@Override

View File

@ -25,6 +25,7 @@ import org.apache.cassandra.cql3.CQL3Type;
import org.apache.cassandra.serializers.TypeSerializer;
import org.apache.cassandra.serializers.MarshalException;
import org.apache.cassandra.serializers.TimeUUIDSerializer;
import org.apache.cassandra.serializers.TimestampSerializer;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.cassandra.utils.UUIDGen;
@ -105,9 +106,10 @@ public class TimeUUIDType extends AbstractType<UUID>
if (uuid.version() != 1)
throw new MarshalException("TimeUUID supports only version 1 UUIDs");
} else
}
else
{
idBytes = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes(DateType.dateStringToTimestamp(source)));
idBytes = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes(TimestampSerializer.dateStringToTimestamp(source)));
}
return idBytes;

View File

@ -18,9 +18,7 @@
package org.apache.cassandra.db.marshal;
import java.nio.ByteBuffer;
import java.text.ParseException;
import java.util.Date;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -29,7 +27,6 @@ import org.apache.cassandra.serializers.TypeSerializer;
import org.apache.cassandra.serializers.MarshalException;
import org.apache.cassandra.serializers.TimestampSerializer;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.commons.lang3.time.DateUtils;
/**
* Type for date-time values.
@ -44,8 +41,6 @@ public class TimestampType extends AbstractType<Date>
public static final TimestampType instance = new TimestampType();
private static final Pattern timestampPattern = Pattern.compile("^-?\\d+$");
private TimestampType() {} // singleton
public int compare(ByteBuffer o1, ByteBuffer o2)
@ -59,43 +54,7 @@ public class TimestampType extends AbstractType<Date>
if (source.isEmpty())
return ByteBufferUtil.EMPTY_BYTE_BUFFER;
return ByteBufferUtil.bytes(dateStringToTimestamp(source));
}
public static long dateStringToTimestamp(String source) throws MarshalException
{
long millis;
if (source.toLowerCase().equals("now"))
{
millis = System.currentTimeMillis();
}
// Milliseconds since epoch?
else if (timestampPattern.matcher(source).matches())
{
try
{
millis = Long.parseLong(source);
}
catch (NumberFormatException e)
{
throw new MarshalException(String.format("unable to make long (for date) from: '%s'", source), e);
}
}
// Last chance, attempt to parse as date-time string
else
{
try
{
millis = DateUtils.parseDateStrictly(source, TimestampSerializer.iso8601Patterns).getTime();
}
catch (ParseException e1)
{
throw new MarshalException(String.format("unable to coerce '%s' to a formatted date (long)", source), e1);
}
}
return millis;
return ByteBufferUtil.bytes(TimestampSerializer.dateStringToTimestamp(source));
}
@Override

View File

@ -26,12 +26,11 @@ import org.apache.cassandra.cql3.CQL3Type;
import org.apache.cassandra.serializers.TypeSerializer;
import org.apache.cassandra.serializers.MarshalException;
import org.apache.cassandra.serializers.UUIDSerializer;
import org.apache.cassandra.serializers.TimestampSerializer;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.cassandra.utils.UUIDGen;
import org.apache.commons.lang3.time.DateUtils;
import static org.apache.cassandra.serializers.TimestampSerializer.iso8601Patterns;
/**
* Compares UUIDs using the following criteria:<br>
* - if count of supplied bytes is less than 16, compare counts<br>
@ -165,8 +164,6 @@ public class UUIDType extends AbstractType<UUID>
if (source.isEmpty())
return ByteBufferUtil.EMPTY_BYTE_BUFFER;
ByteBuffer idBytes = null;
// ffffffff-ffff-ffff-ffff-ffffffffff
if (TimeUUIDType.regexPattern.matcher(source).matches())
{
@ -174,43 +171,22 @@ public class UUIDType extends AbstractType<UUID>
try
{
uuid = UUID.fromString(source);
idBytes = ByteBuffer.wrap(UUIDGen.decompose(uuid));
return ByteBuffer.wrap(UUIDGen.decompose(uuid));
}
catch (IllegalArgumentException e)
{
throw new MarshalException(String.format("unable to make UUID from '%s'", source), e);
}
} else if (source.toLowerCase().equals("now"))
{
idBytes = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes());
}
// Milliseconds since epoch?
else if (source.matches("^\\d+$"))
{
try
{
idBytes = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes(Long.parseLong(source)));
}
catch (NumberFormatException e)
{
throw new MarshalException(String.format("unable to make version 1 UUID from '%s'", source), e);
}
}
// Last chance, attempt to parse as date-time string
else
{
try
{
long timestamp = DateUtils.parseDate(source, iso8601Patterns).getTime();
idBytes = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes(timestamp));
}
catch (ParseException e1)
{
throw new MarshalException(String.format("unable to coerce '%s' to version 1 UUID", source), e1);
}
}
return idBytes;
try
{
return ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes(TimestampSerializer.dateStringToTimestamp(source)));
}
catch (MarshalException e)
{
throw new MarshalException(String.format("unable to make version 1 UUID from '%s'", source), e);
}
}
public CQL3Type asCQL3Type()

View File

@ -21,30 +21,49 @@ import org.apache.cassandra.utils.ByteBufferUtil;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.util.Date;
import java.util.regex.Pattern;
import org.apache.commons.lang3.time.DateUtils;
public class TimestampSerializer implements TypeSerializer<Date>
{
public static final String[] iso8601Patterns = new String[] {
private static final String[] dateStringPatterns = new String[] {
"yyyy-MM-dd HH:mm",
"yyyy-MM-dd HH:mm:ss",
"yyyy-MM-dd HH:mmZ",
"yyyy-MM-dd HH:mm:ssZ",
"yyyy-MM-dd HH:mmX",
"yyyy-MM-dd HH:mmXX",
"yyyy-MM-dd HH:mmXXX",
"yyyy-MM-dd HH:mm:ssX",
"yyyy-MM-dd HH:mm:ssXX",
"yyyy-MM-dd HH:mm:ssXXX",
"yyyy-MM-dd HH:mm:ss.SSS",
"yyyy-MM-dd HH:mm:ss.SSSZ",
"yyyy-MM-dd HH:mm:ss.SSSX",
"yyyy-MM-dd HH:mm:ss.SSSXX",
"yyyy-MM-dd HH:mm:ss.SSSXXX",
"yyyy-MM-dd'T'HH:mm",
"yyyy-MM-dd'T'HH:mmZ",
"yyyy-MM-dd'T'HH:mmX",
"yyyy-MM-dd'T'HH:mmXX",
"yyyy-MM-dd'T'HH:mmXXX",
"yyyy-MM-dd'T'HH:mm:ss",
"yyyy-MM-dd'T'HH:mm:ssZ",
"yyyy-MM-dd'T'HH:mm:ssX",
"yyyy-MM-dd'T'HH:mm:ssXX",
"yyyy-MM-dd'T'HH:mm:ssXXX",
"yyyy-MM-dd'T'HH:mm:ss.SSS",
"yyyy-MM-dd'T'HH:mm:ss.SSSZ",
"yyyy-MM-dd'T'HH:mm:ss.SSSX",
"yyyy-MM-dd'T'HH:mm:ss.SSSXX",
"yyyy-MM-dd'T'HH:mm:ss.SSSXXX",
"yyyy-MM-dd",
"yyyy-MM-ddZ"
"yyyy-MM-ddX",
"yyyy-MM-ddXX",
"yyyy-MM-ddXXX"
};
static final String DEFAULT_FORMAT = iso8601Patterns[3];
private static final String DEFAULT_FORMAT = dateStringPatterns[3];
private static final Pattern timestampPattern = Pattern.compile("^-?\\d+$");
static final ThreadLocal<SimpleDateFormat> FORMATTER = new ThreadLocal<SimpleDateFormat>()
private static final ThreadLocal<SimpleDateFormat> FORMATTER = new ThreadLocal<SimpleDateFormat>()
{
protected SimpleDateFormat initialValue()
{
@ -64,6 +83,35 @@ public class TimestampSerializer implements TypeSerializer<Date>
return value == null ? ByteBufferUtil.EMPTY_BYTE_BUFFER : ByteBufferUtil.bytes(value.getTime());
}
public static long dateStringToTimestamp(String source) throws MarshalException
{
if (source.equalsIgnoreCase("now"))
return System.currentTimeMillis();
// Milliseconds since epoch?
if (timestampPattern.matcher(source).matches())
{
try
{
return Long.parseLong(source);
}
catch (NumberFormatException e)
{
throw new MarshalException(String.format("unable to make long (for date) from: '%s'", source), e);
}
}
// Last chance, attempt to parse as date-time string
try
{
return DateUtils.parseDateStrictly(source, dateStringPatterns).getTime();
}
catch (ParseException e1)
{
throw new MarshalException(String.format("unable to coerce '%s' to a formatted date (long)", source), e1);
}
}
public void validate(ByteBuffer bytes) throws MarshalException
{
if (bytes.remaining() != 8 && bytes.remaining() != 0)

View File

@ -283,6 +283,17 @@ public class CacheService implements CacheServiceMBean
keyCache.clear();
}
public void invalidateKeyCacheForCf(UUID cfId)
{
Iterator<KeyCacheKey> keyCacheIterator = keyCache.getKeySet().iterator();
while (keyCacheIterator.hasNext())
{
KeyCacheKey key = keyCacheIterator.next();
if (key.cfId.equals(cfId))
keyCacheIterator.remove();
}
}
public void invalidateRowCache()
{
rowCache.clear();

View File

@ -22,9 +22,11 @@ import java.io.IOException;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import org.apache.cassandra.OrderedJUnit4ClassRunner;
import org.apache.cassandra.Util;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.apache.cassandra.SchemaLoader;
import org.apache.cassandra.db.commitlog.CommitLog;
@ -34,6 +36,7 @@ import static org.apache.cassandra.Util.column;
import static org.apache.cassandra.db.KeyspaceTest.assertColumns;
import static org.apache.cassandra.Util.cellname;
@RunWith(OrderedJUnit4ClassRunner.class)
public class RecoveryManagerTest extends SchemaLoader
{
@Test

View File

@ -0,0 +1,77 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.cassandra.serializers;
import java.util.List;
import java.util.ArrayList;
import org.junit.Test;
import static org.junit.Assert.assertTrue;
import org.apache.cassandra.serializers.MarshalException;
import org.apache.cassandra.serializers.TimestampSerializer;
public class TimestampSerializerTest
{
private String dates[] = new String[]
{
"2014-04-01",
"2014-04-01+0000",
"2014-04-01 20:30",
"2014-04-01 20:30:35",
"2014-04-01 20:30:35Z",
"2014-04-01 20:30+07",
"2014-04-01 20:30+0700",
"2014-04-01 20:30+07:00",
"2014-04-01 20:30:35+07",
"2014-04-01 20:30:35+0700",
"2014-04-01 20:30:35+07:00",
"2014-04-01 20:30:35.898",
"2014-04-01 20:30:35.898Z",
"2014-04-01 20:30:35.898+07",
"2014-04-01 20:30:35.898+0700",
"2014-04-01 20:30:35.898+07:00",
"2014-04-01T20:30",
"2014-04-01T20:30:25",
"2014-04-01T20:30:35Z",
"2014-04-01T20:30:35+00:00",
"2014-04-01T20:30:35+0700",
"2014-04-01T20:30:35+07:00",
"2014-04-01T20:30:35.898",
"2014-04-01T20:30:35.898+00:00"
};
@Test
public void testDateStringToTimestamp()
{
List<String> unparsedDates = new ArrayList<>();
for (String date: dates)
{
try
{
long millis = TimestampSerializer.dateStringToTimestamp(date);
}
catch (MarshalException e)
{
unparsedDates.add(date);
}
}
assertTrue("Unable to parse: " + unparsedDates, unparsedDates.isEmpty());
}
}