Merge branch 'cassandra-2.2' into cassandra-3.0

Conflicts:
	CHANGES.txt
This commit is contained in:
Tyler Hobbs 2016-02-11 10:29:46 -06:00
commit 9b5af911c9
8 changed files with 77 additions and 16 deletions

View File

@ -9,7 +9,8 @@
* Hadoop integration is incompatible with Cassandra Driver 3.0.0 (CASSANDRA-11001)
* Add dropped_columns to the list of schema table so it gets handled
properly (CASSANDRA-11050)
Merged from 2.2.6:
Merged from 2.2:
* Make SELECT JSON and toJson() threadsafe (CASSANDRA-11048)
* Fix SELECT on tuple relations for mixed ASC/DESC clustering order (CASSANDRA-7281)
* (cqlsh) Support utf-8/cp65001 encoding on Windows (CASSANDRA-11030)
* Fix paging on DISTINCT queries repeats result when first row in partition changes (CASSANDRA-10010)

View File

@ -35,10 +35,16 @@ public class Json
{
public static final ObjectMapper JSON_OBJECT_MAPPER = new ObjectMapper();
public static final JsonStringEncoder JSON_STRING_ENCODER = new JsonStringEncoder();
public static final ColumnIdentifier JSON_COLUMN_ID = new ColumnIdentifier("[json]", true);
/**
* Quotes string contents using standard JSON quoting.
*/
public static String quoteAsJsonString(String s)
{
return new String(JsonStringEncoder.getInstance().quoteAsString(s));
}
public static Object decodeJson(String json)
{
try

View File

@ -386,7 +386,7 @@ public abstract class Selection
ByteBuffer buffer = row.get(i);
sb.append('"');
sb.append(Json.JSON_STRING_ENCODER.quoteAsString(columnName));
sb.append(Json.quoteAsJsonString(columnName));
sb.append("\": ");
if (buffer == null)
sb.append("null");

View File

@ -83,7 +83,7 @@ public class AsciiType extends AbstractType<String>
{
try
{
return '"' + new String(Json.JSON_STRING_ENCODER.quoteAsString(ByteBufferUtil.string(buffer, Charset.forName("US-ASCII")))) + '"';
return '"' + Json.quoteAsJsonString(ByteBufferUtil.string(buffer, Charset.forName("US-ASCII"))) + '"';
}
catch (CharacterCodingException exc)
{

View File

@ -245,7 +245,7 @@ public class MapType<K, V> extends CollectionType<Map<K, V>>
if (key.startsWith("\""))
sb.append(key);
else
sb.append('"').append(Json.JSON_STRING_ENCODER.quoteAsString(key)).append('"');
sb.append('"').append(Json.quoteAsJsonString(key)).append('"');
sb.append(": ");
sb.append(values.toJSONString(CollectionSerializer.readValue(buffer, protocolVersion), protocolVersion));

View File

@ -62,7 +62,7 @@ public class UTF8Type extends AbstractType<String>
{
try
{
return '"' + new String(Json.JSON_STRING_ENCODER.quoteAsString(ByteBufferUtil.string(buffer, Charset.forName("UTF-8")))) + '"';
return '"' + Json.quoteAsJsonString(ByteBufferUtil.string(buffer, Charset.forName("UTF-8"))) + '"';
}
catch (CharacterCodingException exc)
{

View File

@ -206,7 +206,7 @@ public class UserType extends TupleType
name = "\"" + name + "\"";
sb.append('"');
sb.append(Json.JSON_STRING_ENCODER.quoteAsString(name));
sb.append(Json.quoteAsJsonString(name));
sb.append("\": ");
ByteBuffer valueBuffer = buffers[i];

View File

@ -25,6 +25,7 @@ import org.apache.cassandra.serializers.SimpleDateSerializer;
import org.apache.cassandra.serializers.TimeSerializer;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
@ -32,11 +33,12 @@ import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.InetAddress;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class JsonTest extends CQLTester
@ -927,11 +929,11 @@ public class JsonTest extends CQLTester
// map<set<text>, text> keys
String innerKey1 = "[\"0\", \"1\"]";
String fullKey1 = String.format("{\"%s\": \"%s\"}", new String(Json.JSON_STRING_ENCODER.quoteAsString(innerKey1)), "a");
String stringKey1 = new String(Json.JSON_STRING_ENCODER.quoteAsString(fullKey1));
String fullKey1 = String.format("{\"%s\": \"%s\"}", Json.quoteAsJsonString(innerKey1), "a");
String stringKey1 = Json.quoteAsJsonString(fullKey1);
String innerKey2 = "[\"3\", \"4\"]";
String fullKey2 = String.format("{\"%s\": \"%s\"}", new String(Json.JSON_STRING_ENCODER.quoteAsString(innerKey2)), "b");
String stringKey2 = new String(Json.JSON_STRING_ENCODER.quoteAsString(fullKey2));
String fullKey2 = String.format("{\"%s\": \"%s\"}", Json.quoteAsJsonString(innerKey2), "b");
String stringKey2 = Json.quoteAsJsonString(fullKey2);
execute("INSERT INTO %s JSON ?", "{\"k\": 0, \"nestedsetmap\": {\"" + stringKey1 + "\": true, \"" + stringKey2 + "\": false}}");
assertRows(execute("SELECT JSON k, nestedsetmap FROM %s"), row("{\"k\": 0, \"nestedsetmap\": {\"" + stringKey1 + "\": true, \"" + stringKey2 + "\": false}}"));
@ -955,4 +957,56 @@ public class JsonTest extends CQLTester
execute("INSERT INTO %s JSON ?", "{\"k\": 0, \"a\": {\"a\": 0, \"b\": [1, 2, 3], \"c\": null}, \"b\": null}");
assertRows(execute("SELECT k, a.a, a.b, a.c, b FROM %s"), row(0, 0, set(1, 2, 3), null, null));
}
// done for CASSANDRA-11048
@Test
public void testJsonTreadSafety() throws Throwable
{
int numThreads = 10;
final int numRows = 10000;
createTable("CREATE TABLE %s (" +
"k text PRIMARY KEY, " +
"v text)");
for (int i = 0; i < numRows; i++)
execute("INSERT INTO %s (k, v) VALUES (?, ?)", "" + i, "" + i);
long seed = System.nanoTime();
System.out.println("Seed " + seed);
final Random rand = new Random(seed);
final Runnable worker = new Runnable()
{
@Override
public void run()
{
try
{
for (int i = 0; i < numRows; i++)
{
String key = "" + rand.nextInt(numRows);
assertRows(execute("SELECT JSON * FROM %s WHERE k = ?", key),
row(String.format("{\"k\": \"%s\", \"v\": \"%s\"}", key, key)));
}
}
catch (Throwable exc)
{
exc.printStackTrace();
fail(exc.getMessage());
}
}
};
ExecutorService executor = Executors.newFixedThreadPool(numThreads);
List<Future> futures = new ArrayList<>();
for (int i = 0; i < numThreads; i++)
futures.add(executor.submit(worker));
for (Future future : futures)
future.get(10, TimeUnit.SECONDS);
executor.shutdown();
Assert.assertTrue(executor.awaitTermination(10, TimeUnit.SECONDS));
}
}