merge from 1.0

git-svn-id: https://svn.apache.org/repos/asf/cassandra/trunk@1177984 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Jonathan Ellis 2011-10-01 14:06:26 +00:00
commit 73ec0fce81
14 changed files with 423 additions and 90 deletions

View File

@ -1,17 +1,28 @@
1.0.1
* describe_ring should include datacenter/topology information (CASSANDRA-2882)
* fix JDBC driver to compile under JDK 7 (CASSANDRA-3275)
* Thrift sockets are not properly buffered (CASSANDRA-3261)
* performance improvement for bytebufferutil compare function (CASSANDRA-3286)
1.0.0-final
* Log a miningfull warning when a node receive a message for a repair session
that don't exist anymore (CASSANDRA-3256)
* ignore any CF ids sent by client for adding CF/KS (CASSANDRA-3288)
* remove obsolete hints on first startup (CASSANDRA-3291)
1.0.0-rc2
* Log a meaningful warning when a node receives a message for a repair session
that doesn't exist anymore (CASSANDRA-3256)
* test for NUMA policy support as well as numactl presence (CASSANDRA-3245)
* Fix FD leak when internode encryption is enabled (CASSANDRA-3257)
* Remove incorrect assertion in mergeIterator (CASSANDRA-3260)
* FBUtilities.hexToBytes(String) to throw NumberFormatException when string
contains non-hex characters (CASSANDRA-3231)
* Keep SimpleSnitch proximity ordering unchanged from what the Strategy
generates, as intended (CASSANDRA-3262)
* fix counter entry in jdbc TypesMap (CASSANDRA-3268)
* fix full queue scenario for ParallelCompactionIterator (CASSANDRA-3270)
* fix bootstrap process (CASSANDRA-3285)
* CLI documentation change for ColumnFamily `compression_options` (CASSANDRA-3282)
1.0.0-rc1
* Update CQL to generate microsecond timestamps by default (CASSANDRA-3227)

View File

@ -25,7 +25,7 @@
<property name="debuglevel" value="source,lines,vars"/>
<!-- default version and SCM information (we need the default SCM info as people may checkout with git-svn) -->
<property name="base.version" value="1.0.0-rc1"/>
<property name="base.version" value="1.0.0-rc2"/>
<property name="scm.default.path" value="cassandra/branches/cassandra-1.0.0"/>
<property name="scm.default.connection" value="scm:svn:http://svn.apache.org/repos/asf/${scm.default.path}"/>
<property name="scm.default.developerConnection" value="scm:svn:https://svn.apache.org/repos/asf/${scm.default.path}"/>

6
debian/changelog vendored
View File

@ -1,3 +1,9 @@
cassandra (1.0.0~rc2) unstable; urgency=low
* New release candidate
-- Sylvain Lebresne <slebresne@apache.org> Fri, 30 Sep 2011 18:29:44 +0200
cassandra (1.0.0~rc1) unstable; urgency=low
* New release candidate

View File

@ -436,7 +436,7 @@ dropColumnFamilyStatement returns [String cfam]
;
comparatorType
: 'bytea' | 'ascii' | 'text' | 'varchar' | 'int' | 'varint' | 'bigint' | 'uuid' | 'counter' | 'boolean' | 'date' | 'float' | 'double' | 'decimal'
: 'blob' | 'ascii' | 'text' | 'varchar' | 'int' | 'varint' | 'bigint' | 'uuid' | 'counter' | 'boolean' | 'date' | 'float' | 'double' | 'decimal'
;
term returns [Term item]
@ -600,7 +600,7 @@ IDENT
;
COMPIDENT
: IDENT ( ':' IDENT)*
: IDENT ( ':' (IDENT | INTEGER))*
;
UUID

View File

@ -33,7 +33,7 @@ public class TypesMap
map.put("org.apache.cassandra.db.marshal.AsciiType", JdbcAscii.instance);
map.put("org.apache.cassandra.db.marshal.BooleanType", JdbcBoolean.instance);
map.put("org.apache.cassandra.db.marshal.BytesType", JdbcBytes.instance);
map.put("org.apache.cassandra.db.marshal.ColumnCounterType", JdbcCounterColumn.instance);
map.put("org.apache.cassandra.db.marshal.CounterColumnType", JdbcCounterColumn.instance);
map.put("org.apache.cassandra.db.marshal.DateType", JdbcDate.instance);
map.put("org.apache.cassandra.db.marshal.DecimalType", JdbcDecimal.instance);
map.put("org.apache.cassandra.db.marshal.DoubleType", JdbcDouble.instance);

View File

@ -18,8 +18,6 @@
package org.apache.cassandra.db;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOError;
import java.io.IOException;
import java.net.InetAddress;
@ -30,7 +28,6 @@ import java.util.List;
import java.util.ArrayList;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.ExecutionException;
import org.slf4j.Logger;
@ -74,25 +71,24 @@ public class SystemTable
/* if hints become incompatible across versions of cassandra, that logic (and associated purging) is managed here. */
public static void purgeIncompatibleHints() throws IOException
{
// 0.6->0.7
final ByteBuffer hintsPurged6to7 = ByteBufferUtil.bytes("Hints purged as part of upgrading from 0.6.x to 0.7");
ByteBuffer upgradeMarker = ByteBufferUtil.bytes("Pre-1.0 hints purged");
Table table = Table.open(Table.SYSTEM_TABLE);
QueryFilter dotSeven = QueryFilter.getNamesFilter(decorate(COOKIE_KEY), new QueryPath(STATUS_CF), hintsPurged6to7);
ColumnFamily cf = table.getColumnFamilyStore(STATUS_CF).getColumnFamily(dotSeven);
if (cf == null)
QueryFilter filter = QueryFilter.getNamesFilter(decorate(COOKIE_KEY), new QueryPath(STATUS_CF), upgradeMarker);
ColumnFamily cf = table.getColumnFamilyStore(STATUS_CF).getColumnFamily(filter);
if (cf != null)
return;
// marker not found. Snapshot + remove hints and add the marker
ColumnFamilyStore hintsCfs = Table.open(Table.SYSTEM_TABLE).getColumnFamilyStore(HintedHandOffManager.HINTS_CF);
if (hintsCfs.getSSTables().size() > 0)
{
// 0.7+ marker not found. Remove hints and add the marker.
ColumnFamilyStore hintsCfs = Table.open(Table.SYSTEM_TABLE).getColumnFamilyStore(HintedHandOffManager.HINTS_CF);
if (hintsCfs.getSSTables().size() > 0)
{
logger.info("Possible 0.6-format hints found. Snapshotting as 'old-hints' and purging");
hintsCfs.snapshot("old-hints");
hintsCfs.removeAllSSTables();
}
RowMutation rm = new RowMutation(Table.SYSTEM_TABLE, COOKIE_KEY);
rm.add(new QueryPath(STATUS_CF, null, hintsPurged6to7), ByteBufferUtil.bytes("oh yes, it they were purged."), System.currentTimeMillis());
rm.apply();
logger.info("Possible old-format hints found. Snapshotting as 'old-hints' and purging");
hintsCfs.snapshot("old-hints");
hintsCfs.removeAllSSTables();
}
RowMutation rm = new RowMutation(Table.SYSTEM_TABLE, COOKIE_KEY);
rm.add(new QueryPath(STATUS_CF, null, upgradeMarker), ByteBufferUtil.bytes("oh yes, they were purged"), System.currentTimeMillis());
rm.apply();
}
/**

View File

@ -144,21 +144,13 @@ public class ParallelCompactionIterable extends AbstractCompactionIterable
private class Reducer extends MergeIterator.Reducer<RowContainer, CompactedRowContainer>
{
private final List<RowContainer> rows = new ArrayList<RowContainer>();
private final ThreadPoolExecutor executor;
private int row = 0;
private Reducer()
{
super();
executor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),
Runtime.getRuntime().availableProcessors(),
Integer.MAX_VALUE,
TimeUnit.MILLISECONDS,
new SynchronousQueue<Runnable>(),
new NamedThreadFactory("CompactionReducer"));
executor.setRejectedExecutionHandler(DebuggableThreadPoolExecutor.blockingExecutionHandler);
}
private final ThreadPoolExecutor executor = new DebuggableThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),
Integer.MAX_VALUE,
TimeUnit.MILLISECONDS,
new SynchronousQueue<Runnable>(),
new NamedThreadFactory("CompactionReducer"));
public void reduce(RowContainer current)
{

View File

@ -924,6 +924,7 @@ public class CassandraServer implements Cassandra.Iface
try
{
cf_def.unsetId(); // explicitly ignore any id set by client (Hector likes to set zero)
applyMigrationOnStage(new AddColumnFamily(CFMetaData.fromThrift(cf_def)));
return Schema.instance.getVersion().toString();
}
@ -989,6 +990,7 @@ public class CassandraServer implements Cassandra.Iface
Collection<CFMetaData> cfDefs = new ArrayList<CFMetaData>(ks_def.cf_defs.size());
for (CfDef cf_def : ks_def.cf_defs)
{
cf_def.unsetId(); // explicitly ignore any id set by client (same as system_add_column_family)
CFMetaData.addDefaultIndexNames(cf_def);
ThriftValidation.validateCfDef(cf_def, null);
cfDefs.add(CFMetaData.fromThrift(cf_def));

View File

@ -1,4 +1,5 @@
package org.apache.cassandra.thrift;
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
@ -20,8 +21,9 @@ package org.apache.cassandra.thrift;
*
*/
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
@ -29,44 +31,79 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TServerTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransportException;
/**
* Extends Thrift's TServerSocket to allow customization of various desirable
* TCP properties.
* Extends Thrift's TServerSocket to allow customization of various desirable TCP properties.
*/
public class TCustomServerSocket extends TServerSocket
public class TCustomServerSocket extends TServerTransport
{
private static final Logger logger = LoggerFactory.getLogger(TCustomServerSocket.class);
/**
* Underlying serversocket object
*/
private ServerSocket serverSocket_ = null;
private final boolean keepAlive;
private final Integer sendBufferSize;
private final Integer recvBufferSize;
/**
* Allows fine-tuning of the server socket including keep-alive, reuse of addresses, send and receive buffer sizes.
*
* @param bindAddr
* @param keepAlive
* @param sendBufferSize
* @param recvBufferSize
* @throws TTransportException
*/
public TCustomServerSocket(InetSocketAddress bindAddr, boolean keepAlive, Integer sendBufferSize, Integer recvBufferSize)
throws TTransportException
public TCustomServerSocket(InetSocketAddress bindAddr, boolean keepAlive, Integer sendBufferSize,
Integer recvBufferSize)
throws TTransportException
{
super(bindAddr);
try
{
// Make server socket
serverSocket_ = new ServerSocket();
// Prevent 2MSL delay problem on server restarts
serverSocket_.setReuseAddress(true);
// Bind to listening port
serverSocket_.bind(bindAddr);
}
catch (IOException ioe)
{
serverSocket_ = null;
throw new TTransportException("Could not create ServerSocket on address " + bindAddr.toString() + ".");
}
this.keepAlive = keepAlive;
this.sendBufferSize = sendBufferSize;
this.recvBufferSize = recvBufferSize;
}
@Override
protected TSocket acceptImpl() throws TTransportException
protected TCustomSocket acceptImpl() throws TTransportException
{
TSocket tsocket = super.acceptImpl();
Socket socket = tsocket.getSocket();
if (serverSocket_ == null)
throw new TTransportException(TTransportException.NOT_OPEN, "No underlying server socket.");
TCustomSocket tsocket = null;
Socket socket = null;
try
{
socket = serverSocket_.accept();
tsocket = new TCustomSocket(socket);
tsocket.setTimeout(0);
}
catch (IOException iox)
{
throw new TTransportException(iox);
}
try
{
@ -103,4 +140,38 @@ public class TCustomServerSocket extends TServerSocket
return tsocket;
}
@Override
public void listen() throws TTransportException
{
// Make sure not to block on accept
if (serverSocket_ != null)
{
try
{
serverSocket_.setSoTimeout(0);
}
catch (SocketException sx)
{
logger.error("Could not set socket timeout.", sx);
}
}
}
@Override
public void close()
{
if (serverSocket_ != null)
{
try
{
serverSocket_.close();
}
catch (IOException iox)
{
logger.warn("Could not close server socket.", iox);
}
serverSocket_ = null;
}
}
}

View File

@ -0,0 +1,211 @@
/*
* 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.thrift;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import org.apache.thrift.transport.TIOStreamTransport;
import org.apache.thrift.transport.TTransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Socket implementation of the TTransport interface.
*
* Adds socket buffering
*
*/
public class TCustomSocket extends TIOStreamTransport {
private static final Logger LOGGER = LoggerFactory.getLogger(TCustomSocket.class.getName());
/**
* Wrapped Socket object
*/
private Socket socket_ = null;
/**
* Remote host
*/
private String host_ = null;
/**
* Remote port
*/
private int port_ = 0;
/**
* Socket timeout
*/
private int timeout_ = 0;
/**
* Constructor that takes an already created socket.
*
* @param socket Already created socket object
* @throws TTransportException if there is an error setting up the streams
*/
public TCustomSocket(Socket socket) throws TTransportException {
socket_ = socket;
try {
socket_.setSoLinger(false, 0);
socket_.setTcpNoDelay(true);
} catch (SocketException sx) {
LOGGER.warn("Could not configure socket.", sx);
}
if (isOpen()) {
try {
inputStream_ = new BufferedInputStream(socket_.getInputStream(), 1024);
outputStream_ = new BufferedOutputStream(socket_.getOutputStream(), 1024);
} catch (IOException iox) {
close();
throw new TTransportException(TTransportException.NOT_OPEN, iox);
}
}
}
/**
* Creates a new unconnected socket that will connect to the given host
* on the given port.
*
* @param host Remote host
* @param port Remote port
*/
public TCustomSocket(String host, int port) {
this(host, port, 0);
}
/**
* Creates a new unconnected socket that will connect to the given host
* on the given port.
*
* @param host Remote host
* @param port Remote port
* @param timeout Socket timeout
*/
public TCustomSocket(String host, int port, int timeout) {
host_ = host;
port_ = port;
timeout_ = timeout;
initSocket();
}
/**
* Initializes the socket object
*/
private void initSocket() {
socket_ = new Socket();
try {
socket_.setSoLinger(false, 0);
socket_.setTcpNoDelay(true);
socket_.setSoTimeout(timeout_);
} catch (SocketException sx) {
LOGGER.error("Could not configure socket.", sx);
}
}
/**
* Sets the socket timeout
*
* @param timeout Milliseconds timeout
*/
public void setTimeout(int timeout) {
timeout_ = timeout;
try {
socket_.setSoTimeout(timeout);
} catch (SocketException sx) {
LOGGER.warn("Could not set socket timeout.", sx);
}
}
/**
* Returns a reference to the underlying socket.
*/
public Socket getSocket() {
if (socket_ == null) {
initSocket();
}
return socket_;
}
/**
* Checks whether the socket is connected.
*/
public boolean isOpen() {
if (socket_ == null) {
return false;
}
return socket_.isConnected();
}
/**
* Connects the socket, creating a new socket object if necessary.
*/
public void open() throws TTransportException {
if (isOpen()) {
throw new TTransportException(TTransportException.ALREADY_OPEN, "Socket already connected.");
}
if (host_.length() == 0) {
throw new TTransportException(TTransportException.NOT_OPEN, "Cannot open null host.");
}
if (port_ <= 0) {
throw new TTransportException(TTransportException.NOT_OPEN, "Cannot open without port.");
}
if (socket_ == null) {
initSocket();
}
try {
socket_.connect(new InetSocketAddress(host_, port_), timeout_);
inputStream_ = new BufferedInputStream(socket_.getInputStream(), 1024);
outputStream_ = new BufferedOutputStream(socket_.getOutputStream(), 1024);
} catch (IOException iox) {
close();
throw new TTransportException(TTransportException.NOT_OPEN, iox);
}
}
/**
* Closes the socket.
*/
public void close() {
// Close the underlying streams
super.close();
// Close the socket
if (socket_ != null) {
try {
socket_.close();
} catch (IOException iox) {
LOGGER.warn("Could not close socket.", iox);
}
socket_ = null;
}
}
}

View File

@ -83,6 +83,12 @@ public class ByteBufferUtil
assert o1 != null;
assert o2 != null;
if (o1.hasArray() && o2.hasArray())
{
return FBUtilities.compareUnsigned(o1.array(), o2.array(), o1.position() + o1.arrayOffset(),
o2.position() + o2.arrayOffset(), o1.remaining(), o2.remaining());
}
int minLength = Math.min(o1.remaining(), o2.remaining());
for (int x = 0, i = o1.position(), j = o2.position(); x < minLength; x++, i++, j++)
{

View File

@ -47,8 +47,6 @@ import org.apache.cassandra.concurrent.CreationTimeAwareFuture;
import org.apache.cassandra.config.ConfigurationException;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.db.DecoratedKey;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.TypeParser;
import org.apache.cassandra.dht.IPartitioner;
import org.apache.cassandra.dht.Range;
import org.apache.cassandra.dht.Token;
@ -348,7 +346,7 @@ public class FBUtilities
}
if (bytes2 == null) return 1;
int minLength = Math.min(len1 - offset1, len2 - offset2);
int minLength = Math.min(len1, len2);
for (int x = 0, i = offset1, j = offset2; x < minLength; x++, i++, j++)
{
if (bytes1[i] == bytes2[j])
@ -356,8 +354,8 @@ public class FBUtilities
// compare non-equal bytes as unsigned
return (bytes1[i] & 0xFF) < (bytes2[j] & 0xFF) ? -1 : 1;
}
if ((len1 - offset1) == (len2 - offset2)) return 0;
else return ((len1 - offset1) < (len2 - offset2)) ? -1 : 1;
if (len1 == len2) return 0;
else return (len1 < len2) ? -1 : 1;
}
/**
@ -406,10 +404,14 @@ public class FBUtilities
{
if (str.length() % 2 == 1)
str = "0" + str;
byte[] bytes = new byte[str.length()/2];
byte[] bytes = new byte[str.length() / 2];
for (int i = 0; i < bytes.length; i++)
{
bytes[i] = (byte)((charToByte[str.charAt(i * 2)] << 4) | charToByte[str.charAt(i*2 + 1)]);
byte halfByte1 = charToByte[str.charAt(i * 2)];
byte halfByte2 = charToByte[str.charAt(i * 2 + 1)];
if (halfByte1 == -1 || halfByte2 == -1)
throw new NumberFormatException("Non-hex characters in " + str);
bytes[i] = (byte)((halfByte1 << 4) | halfByte2);
}
return bytes;
}

View File

@ -472,14 +472,8 @@ commands:
terms of I/O for the key cache. Row cache saving is much more expensive and
has limited use.
- memtable_operations: Number of operations in millions before the memtable
is flushed. Default is memtable_throughput / 64 * 0.3
- memtable_throughput: Maximum size in MB to let a memtable get to before
it is flushed. Default is to use 1/16 the JVM heap size.
- read_repair_chance: Probability (0.0-1.0) with which to perform read
repairs for any read operation. Default is 1.0 to enable read repair.
repairs for any read operation. Default is 0.1.
Note that disabling read repair entirely means that the dynamic snitch
will not have any latency information from all the replicas to recognize
@ -563,25 +557,20 @@ commands:
more rows in a given memory footprint. And storing the cache off-heap
means you can use smaller heap sizes, reducing the impact of GC pauses.
- compression: Use compression for SSTable data files.
Supported values are:
- null: to disable compression
- SnappyCompressor: compression based on the Snappy algorithm
- DeflateCompressor: compression based on the deflate algorithm
(through Java native support)
It is also valid to specify the fully-qualified class name to a class
that implements org.apache.cassandra.io.ICompressor.
- compression_options: Options related to compression.
Options have the form [{key:value}]. The main recognized option are:
- sstable_compression: the algorithm to use to compress sstables for
this column family. If none is provided, compression will not be
enabled. Supported values are SnappyCompressor, DeflateCompressor or
any custom compressor.
- chunk_length_kb: specify the size of the chunk used by sstable
compression (default to 64, must be a power of 2).
Options have the form {key:value}.
The main recognized options are:
- sstable_compression: the algorithm to use to compress sstables for
this column family. If none is provided, compression will not be
enabled. Supported values are SnappyCompressor, DeflateCompressor or
any custom compressor. It is also valid to specify the fully-qualified
class name to a class that implements org.apache.cassandra.io.ICompressor.
- chunk_length_kb: specify the size of the chunk used by sstable
compression (default to 64, must be a power of 2).
To disable compression just set compression_options to null like this
`compression_options = null`.
Examples:
create column family Super4
@ -744,14 +733,8 @@ commands:
terms of I/O for the key cache. Row cache saving is much more expensive and
has limited use.
- memtable_operations: Number of operations in millions before the memtable
is flushed. Default is memtable_throughput / 64 * 0.3
- memtable_throughput: Maximum size in MB to let a memtable get to before
it is flushed. Default is to use 1/16 the JVM heap size.
- read_repair_chance: Probability (0.0-1.0) with which to perform read
repairs for any read operation. Default is 1.0 to enable read repair.
repairs for any read operation. Default is 0.1.
Note that disabling read repair entirely means that the dynamic snitch
will not have any latency information from all the replicas to recognize
@ -836,7 +819,20 @@ commands:
memory footprint. And storing the cache off-heap means you
can use smaller heap sizes, reducing the impact of GC pauses.
- compression: Use compression for SSTable data files. Accepts the values true and false.
- compression_options: Options related to compression.
Options have the form {key:value}.
The main recognized options are:
- sstable_compression: the algorithm to use to compress sstables for
this column family. If none is provided, compression will not be
enabled. Supported values are SnappyCompressor, DeflateCompressor or
any custom compressor. It is also valid to specify the fully-qualified
class name to a class that implements org.apache.cassandra.io.ICompressor.
- chunk_length_kb: specify the size of the chunk used by sstable
compression (default to 64, must be a power of 2).
To disable compression just set compression_options to null like this
`compression_options = null`.
Examples:
update column family Super4

View File

@ -0,0 +1,40 @@
/**
* 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.db.marshal;
import org.junit.Test;
public class BytesTypeTest
{
private static final String INVALID_HEX = "33AG45F"; // Invalid (has a G)
private static final String VALID_HEX = "33A45F";
@Test (expected = MarshalException.class)
public void testFromStringWithInvalidString()
{
BytesType.instance.fromString(INVALID_HEX);
}
@Test
public void testFromStringWithValidString()
{
BytesType.instance.fromString(VALID_HEX);
}
}