GithubHelp home page GithubHelp logo

corfudb / corfudb Goto Github PK

View Code? Open in Web Editor NEW
627.0 51.0 121.0 516.88 MB

A cluster consistency platform

License: Other

Shell 0.12% Java 98.76% Clojure 0.74% Dockerfile 0.03% Python 0.35% Makefile 0.01%
distributed-database database nosql datastore distributed-systems streaming consensus

corfudb's Introduction

logo

Join the chat at https://gitter.im/CorfuDB/CorfuDB Github Actions Codacy Badge Codacy Badge

Corfu is a consistency platform designed around the abstraction of a shared log. CorfuDB objects are in-memory, highly available data structures providing linearizable read/write operations and strictly serializable transactions. CorfuDB is based on peer-reviewed research, see References.

Check the Corfu Wiki for a detailed overview of the software architecture and example usage.

Table of Contents

System Requirements

Corfu Basics

Corfu Quick Start

Developing with Corfu

What do I need to run Corfu?

The Corfu infrastructure can run on any system which has Java 11 support. We do not impose any requirements on the kind of storage used - Corfu works with any device that your operating system will allow Java to work with: traditional hard disks, SSDs, and even NVM. We also provide an in-memory mode for nodes which do not require persistence.

Even though Corfu is a distributed system, you can start working with Corfu using just a single machine. In addition, you can easily simulate a distributed Corfu system on a single machine using just a few commands.

So how does Corfu work?

Corfu is built upon the abstraction of a distributed shared log. The Corfu infrastructure provides this log to clients, which use the log for coordination, communication and storage. The log is a highly available, dynamic and high performance scalable fabric: it is resilient to failures and can be reconfigured at any time.

The Corfu infrastructure consists of three components: a layout server, which helps Corfu clients locate the rest of the Corfu infrastructure, a sequencer server, which is used to order updates to the log, and a log server, which stores updates to the log. At minimum a Corfu infrastructure must have one of each server type, but for scalability and high availability a real-world deployment will have many. An administrator need not worry about installing each role separately as they are provided as a single monolithic binary.

Corfu clients interact with the infrastructure through the Corfu runtime. The runtime is currently only available in Java, but we plan on providing it in several other languages in the future. Given the address to a layout server in a Corfu infrastructure, the runtime enables clients to access distributed high-level data structures as if they were local data structures. We provide a mechanism to automatically distribute most Java objects as well.

For more details on the inner workings of Corfu, see the Corfu wiki.

Ok, great - get me started running Corfu!

Building Corfu From Source

To build Corfu, you will need the Java JDK 11 as well as Apache Maven 3.3 or later to invoke the build system.

Your major release number of Debian/Ubuntu will determine whether the simple command below is sufficient to install Maven 3.3 or later.

$ sudo apt-get install maven

Use the command mvn --version to confirm that Maven 3.3 or later is installed. If an older version is installed, then use the instructions at Installing maven 3.3 on Ubuntu to install manually. PLEASE NOTE: Please substitute the version number 3.3.9 in place of this blog's instructions for an older & unavailable 3.3.3.

On Mac OS X, the homebrew package manager should help. After installing homebrew, run:

$ brew install maven 

The OS X package manager MacPorts can also install Maven 3 via sudo port install maven3.

Double-check Java and Maven prerequisites

Use the command mvn --version to confirm that Maven 3.3 or later is installed. Output should look like:

% mvn --version
Apache Maven 3.3.9 (bb52d8502b132ec0a5a3f4c09453c07478323dc5; 2015-11-10T08:41:47-08:00)
Maven home: /opt/local/share/java/maven3
Java version: 1.8.0_91, vendor: Oracle Corporation
Java home: /Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "mac os x", version: "10.11.6", arch: "x86_64", family: "mac"

Some OS X users have had problems where the version of Maven installed by MacPorts uses a different Java version than expected. Java version 11 or later is required.
If Java 1.7 or earlier is reported, then refer to this StackOverflow Maven JDK mismatch question.

Building Corfu

Once you've installed the prerequisites, you can build Corfu.

$ mvn clean install

The binaries which will be referenced in the following sections will be located in the bin directory.

Running Corfu for the first time

The Corfu infrastructure is provided by the monolithic binary corfu_server. For testing purposes, you will want to run the server in in-memory, single-server mode. To do this, run:

$ ./CorfuDB/bin/corfu_server -ms 9000

This starts an in-memory single node Corfu infrastructure on port 9000. To point clients at this infrastructure, point them at localhost:9000.

How do I make sure it works?

To test your Corfu infrastructure, you can use the Corfu utilities. One of the first things you might want to do is check is the layout, which described the configuration of servers in the Corfu infrastructure. To run this, try:

$ ./CorfuDB/bin/corfu_layouts -c localhost:9000 query

You should get output similar to this:

{
  "layoutServers": [
    "localhost:9000"
  ],
  "sequencers": [
    "localhost:9000"
  ],
  "segments": [
    {
      "replicationMode": "CHAIN_REPLICATION",
      "start": 0,
      "end": -1,
      "stripes": [
        {
          "logServers": [
            "localhost:9000"
          ]
        }
      ]
    }
  ],
  "unresponsiveServers": [],
  "epoch": 0,
  "clusterId": "fd3802dc-9db4-4a7c-98d6-1aecfbc964ae"
}

This means that the infrastructure is currently configured with a single layout server, a single sequencer, and a single replica which is replicated using chain replication.

Now we can try writing to the instance. The stream utility can be used to write to the instance:

$ echo "hello world" | ./CorfuDB/bin/corfu_stream append -c localhost:9000 -i test

This utility takes input from stdin and writes it into the log. This command invocation writes a entry named "hello world" to a stream called "test". Streams are a kind of virtualized log in Corfu - think of them as append-only files.

Next, we can try reading back that stream. This can be done by running:

$ ./CorfuDB/bin/corfu_stream read -c localhost:9000 -i test

The utility should print back "hello world".

Cool, it works! But how do I make it distributed?

Now that you have a working Corfu deployment, you'll probably want to make it distributed.

Let's start by adding 2 non-provisioned Corfu server instances. We'll start these on ports 9000 and 9001 respectively.

$ ./CorfuDB/bin/corfu_server -m 9000 &
$ ./CorfuDB/bin/corfu_server -m 9001 &

Now let's bootstrap these corfu_server instances into a cluster. To do that edit the json obtained from the layouts query above in a file called, say layout.json and add in the second server:

{
  "layoutServers": [
    "localhost:9000",
    "localhost:9001"
  ],
  "sequencers": [
    "localhost:9000",
    "localhost:9001"
  ],
  "segments": [
    {
      "replicationMode": "CHAIN_REPLICATION",
      "start": 0,
      "end": -1,
      "stripes": [
        {
          "logServers": [
            "localhost:9000",
            "localhost:9001"
          ]
        }
      ]
    }
  ],
  "epoch": 0
}

Note that we are adding the second server in port 9001 as a layoutServer, a sequencer and a logServer all in one. Once you have edited the file layout.json add it to the cluster using the following command:

$ ./CorfuDB/bin/corfu_bootstrap_cluster -l layout.json

If you check the current layout using the query command:

$ ./CorfuDB/bin/corfu_layouts query -c localhost:9000,localhost:9001

You will see that you now have two servers in the layout. Recall that corfu_server is a monolithic binary containing all servers. The above layout.json provisions the second server as another replica so the cluster can tolerate a single failure.

To learn more about segments, see the Corfu wiki.

To add more nodes, begin by starting a new corfu_server on port 9002:

./CorfuDB/bin/corfu_server -m 9002

The server can be added to the existing cluster:

./CorfuDB/bin/corfu_add_node -c localhost:9000,localhost:9001 -n localhost:9002

If you now check the layout of the cluster:

./CorfuDB/bin/corfu_layouts query -c localhost:9000,localhost:9001,localhost:9002

You will see that the cluster contains the new node.

To remove the added node from the cluster:

./CorfuDB/bin/corfu_remove_node -c localhost:9000,localhost:9001,localhost:9002 -n localhost:9002

Now I want to write a program that uses Corfu!

To write your first program that uses Corfu, you will want to add all Corfu dependencies from the Corfu Package Page.

For instructions on how to add the dependency from GitHub, refer to this page.

Once you have Corfu added as a dependency, you can start writing Corfu code. Let's start with a map:

    CorfuRuntime rt = new CorfuRuntime("localhost:9000")
                            .connect();

    Map<String,Integer> map = rt.getObjectsView()
                .build()
                .setStreamName("A")
                .setType(CorfuTable.class)
                .open();

    Integer previous = map.get("a");
    if (previous == null) {
        System.out.println("This is the first time we were run!");
        map.put("a", 1);
    }
    else {
        map.put("a", ++previous);
        System.out.println("This is the " + previous + " time we were run!");
    }

You can run this code multiple times from many clients, and each client should display a unique "run".

Documentation

In addition to the github wiki more documentation can be found in the docs folder. An API spec and class diagrams can be generated by running doxygen in the parent directory, the output will be in docs/doxygen.

corfudb's People

Contributors

amytai avatar annym avatar bitmingw avatar chetangudisagar avatar dahliamalkhi avatar hisundar avatar kspirov avatar lujie1996 avatar maheshba avatar maithem avatar medhavidhawan avatar no2chem avatar pankti-m avatar pavelzaytsev avatar rogermichoud avatar rossbach avatar rtremblay avatar shama358 avatar shreayp avatar slfritchie avatar sravanthiashokkumar avatar strikingthirteen avatar vjeko avatar wenbinzhu avatar xcchang avatar xiaoqin2012 avatar xnull avatar zalokhan avatar zfrenette avatar zhangn49 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

corfudb's Issues

Support Sequencer Failover

If the user includes multiple sequencers in the configuration file, sequencers after the first should be used as hot spares.

This will require polling each logunit to determine the highest token (if supported), and bringing up the new sequencer with the latest token.

deserialize lambda that was already serialized in the log fails

  • CorfuDB cluster setup
    1 configmaster + 1 sequencer + 1 logunit, launched using bin/corfuStreamingSingle.sh

  • Test case code used to report issue:
    A unit test case as below (line number is included to cross-reference with the exception stack.

    24 public class L2DeferredTxTest implements Serializable {
    25 /**
    26 * It is weird to make a test case class to implement Serializable, but
    27 * without this defined lambda won't work
    28 /
    29 private static final long serialVersionUID = 1L;
    30
    31 private static final Logger logger = LoggerFactory
    32 .getLogger(L2DeferredTxTest.class);
    33
    34 /*
    35 * make CorfuDBRuntime be transient otherwise there will be an attempt to
    36 * serialize it because the current test case class defines the lambda in it
    37 /
    38 private transient CorfuDBRuntime cdr;
    39
    40 /*
    41 * This must not be transient as the proposed transactions refers to it
    42 /
    43 private CDBSimpleMap table;
    44
    45 private void putTableTransactionally() throws Exception {
    46 ITransactionCommand writeCommand = (ITransactionCommand) (opts) -> {
    47 UUID newKey = UUID.randomUUID();
    48 String newValue = "dummy";
    49 table.put(newKey, newValue);
    50 String msg = "PUT into table : key = " + newKey + ", value = "
    51 + newValue;
    52 System.out.println(msg);
    53 return msg;
    54 };
    55 ITimestamp t = new DeferredTransaction<>(cdr.getLocalInstance(),
    56 writeCommand).propose();
    57 logger.info("PUT transaction is proposed at {}", t);
    58 }
    59
    60 private int countTableTransactionally() throws Exception {
    61 ITransactionCommand countCommand = (ITransactionCommand) (opts) -> {
    62 int count = table.size();
    63 String msg = "SHOWCOUNT = " + count;
    64 System.out.println(msg);
    65 return count;
    66 };
    67 ITimestamp t = null;
    68 t = new DeferredTransaction<>(cdr.getLocalInstance(), countCommand)
    69 .propose();
    70 logger.info("SHOWCOUNT transaction is proposed at {}", t);
    71 table.sync(t);
    72 return table.size();
    73 }
    74
    75 @test
    76 public void testDeferredTx() throws Exception {
    77 /*
    78 * create table as a CDBSimpleMap instance
    79 /
    80 UUID mapuuid = UUID.fromString("1442df14-7220-11e5-9d70-feff819cdc9f");
    81 Map options = new HashMap();
    82 options.put("--master", "http://localhost:8002/corfu");
    83 options.put("--stream-impl", "NewStream");
    84 CorfuDBFactory cdf = new CorfuDBFactory(options);
    85 cdr = cdf.getRuntime();
    86 IStream stream = cdr.getLocalInstance().openStream(mapuuid);
    87 table = (CDBSimpleMap) cdr.getLocalInstance().openObject(
    88 mapuuid, CDBSimpleMap.class);
    89 logger.info("Done initializing map instance.");
    90
    91 /*
    92 * tests:
    93 *
    94 * 1. issue a transaction to put a new key-value pair to table
    95 *
    96 * 2. issue a transaction to show the size of the table, sync the table
    97 * immediately to commit the write/read tx
    98 */
    99 putTableTransactionally();
    100 int count = countTableTransactionally();
    101 logger.info("after counting, count = {}", count);
    102
    103 cdr.close();
    104 logger.info("Test finished.");
    105 }
    106 }

  • Steps to reproduce this issue:
    Reset (or restart) the CorfuDB cluster, run the test case twice to see the issue happen on the 2nd run of the test case.

Test behaves normally in the 1st run of the test, see logs:

[main] INFO com.vmware.nsx.demo.test.l2.L2DeferredTxTest - PUT transaction is proposed at 0

[main] INFO com.vmware.nsx.demo.test.l2.L2DeferredTxTest - SHOWCOUNT transaction is proposed at 1

[main] INFO org.corfudb.runtime.view.LocalCorfuDBInstance - got cached stream

[ForkJoinPool.commonPool-worker-2] INFO org.corfudb.runtime.smr.DeferredTransaction - Executing transaction.

PUT into table : key = 2f7865a6-fd5c-4eab-9a40-9663963d7571, value = dummy

[ForkJoinPool.commonPool-worker-2] INFO org.corfudb.runtime.smr.DeferredTransaction - Executing transaction.

SHOWCOUNT = 1

[main] INFO com.vmware.nsx.demo.test.l2.L2DeferredTxTest - after counting, count = 1

[main] INFO com.vmware.nsx.demo.test.l2.L2DeferredTxTest - Test finished.

On the 2nd run of the test, these errors are seen below:

[main] INFO com.vmware.nsx.demo.test.l2.L2DeferredTxTest - PUT transaction is proposed at 2

[main] INFO com.vmware.nsx.demo.test.l2.L2DeferredTxTest - SHOWCOUNT transaction is proposed at 3

[main] INFO org.corfudb.runtime.view.LocalCorfuDBInstance - got cached stream

[org.corfudb.runtime.protocols.AbstractNettyProtocol$2-event-1] ERROR org.corfudb.runtime.protocols.NettyRPCChannelInboundHandlerAdapter - Exception during channel handling.

java.lang.ClassCastException: cannot assign instance of java.lang.invoke.SerializedLambda to field org.corfudb.runtime.smr.DeferredTransaction.transaction of type org.corfudb.runtime.smr.ITransactionCommand in instance of org.corfudb.runtime.smr.DeferredTransaction

at java.io.ObjectStreamClass$FieldReflector.setObjFieldValues(ObjectStreamClass.java:2089)

at java.io.ObjectStreamClass.setObjFieldValues(ObjectStreamClass.java:1261)

at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2006)

at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1924)

at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801)

at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)

at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)

at org.corfudb.util.serializer.JavaSerializer.deserialize(JavaSerializer.java:29)

at org.corfudb.runtime.smr.smrprotocol.TransactionalLambdaSMRCommand.fromBuffer(TransactionalLambdaSMRCommand.java:78)

at org.corfudb.runtime.smr.smrprotocol.SMRCommand.deserialize(SMRCommand.java:86)

at org.corfudb.util.serializer.CorfuSerializer.deserialize(CorfuSerializer.java:80)

at org.corfudb.infrastructure.wireprotocol.NettyLogUnitPayloadMsg.getPayload(NettyLogUnitPayloadMsg.java:36)

at org.corfudb.runtime.protocols.logunits.INewWriteOnceLogUnit$ReadResult.(INewWriteOnceLogUnit.java:80)

at org.corfudb.runtime.protocols.logunits.NettyLogUnitProtocol$NettyLogUnitHandler.handleMessage(NettyLogUnitProtocol.java:158)

at org.corfudb.runtime.protocols.NettyRPCChannelInboundHandlerAdapter.channelRead(NettyRPCChannelInboundHandlerAdapter.java:138)

at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:308)

at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:294)

at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:244)

at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:308)

at io.netty.channel.AbstractChannelHandlerContext.access$600(AbstractChannelHandlerContext.java:32)

at io.netty.channel.AbstractChannelHandlerContext$7.run(AbstractChannelHandlerContext.java:299)

at io.netty.util.concurrent.DefaultEventExecutor.run(DefaultEventExecutor.java:36)

at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:112)

at java.lang.Thread.run(Thread.java:745)

[org.corfudb.runtime.protocols.AbstractNettyProtocol$2-event-1] ERROR org.corfudb.runtime.protocols.NettyRPCChannelInboundHandlerAdapter - Exception during channel handling.

java.lang.ClassCastException: cannot assign instance of java.lang.invoke.SerializedLambda to field org.corfudb.runtime.smr.DeferredTransaction.transaction of type org.corfudb.runtime.smr.ITransactionCommand in instance of org.corfudb.runtime.smr.DeferredTransaction

at java.io.ObjectStreamClass$FieldReflector.setObjFieldValues(ObjectStreamClass.java:2089)

at java.io.ObjectStreamClass.setObjFieldValues(ObjectStreamClass.java:1261)

at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2006)

at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1924)

at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801)

at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)

at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)

at org.corfudb.util.serializer.JavaSerializer.deserialize(JavaSerializer.java:29)

at org.corfudb.runtime.smr.smrprotocol.TransactionalLambdaSMRCommand.fromBuffer(TransactionalLambdaSMRCommand.java:78)

at org.corfudb.runtime.smr.smrprotocol.SMRCommand.deserialize(SMRCommand.java:86)

at org.corfudb.util.serializer.CorfuSerializer.deserialize(CorfuSerializer.java:80)

at org.corfudb.infrastructure.wireprotocol.NettyLogUnitPayloadMsg.getPayload(NettyLogUnitPayloadMsg.java:36)

at org.corfudb.runtime.protocols.logunits.INewWriteOnceLogUnit$ReadResult.(INewWriteOnceLogUnit.java:80)

at org.corfudb.runtime.protocols.logunits.NettyLogUnitProtocol$NettyLogUnitHandler.handleMessage(NettyLogUnitProtocol.java:158)

at org.corfudb.runtime.protocols.NettyRPCChannelInboundHandlerAdapter.channelRead(NettyRPCChannelInboundHandlerAdapter.java:138)

at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:308)

at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:294)

at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:244)

at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:308)

at io.netty.channel.AbstractChannelHandlerContext.access$600(AbstractChannelHandlerContext.java:32)

at io.netty.channel.AbstractChannelHandlerContext$7.run(AbstractChannelHandlerContext.java:299)

at io.netty.util.concurrent.DefaultEventExecutor.run(DefaultEventExecutor.java:36)

at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:112)

at java.lang.Thread.run(Thread.java:745)

deserialize lambda that was already serialized in the log fails

  • CorfuDB cluster setup
    1 configmaster + 1 sequencer + 1 logunit, launched using bin/corfuStreamingSingle.sh

  • Test case code used to report issue:
    A unit test case as below (line number is included to cross-reference with the exception stack.

    24 public class L2DeferredTxTest implements Serializable {
    25 /**
    26 * It is weird to make a test case class to implement Serializable, but
    27 * without this defined lambda won't work
    28 /
    29 private static final long serialVersionUID = 1L;
    30
    31 private static final Logger logger = LoggerFactory
    32 .getLogger(L2DeferredTxTest.class);
    33
    34 /
    *
    35 * make CorfuDBRuntime be transient otherwise there will be an attempt to
    36 * serialize it because the current test case class defines the lambda in it
    37 /
    38 private transient CorfuDBRuntime cdr;
    39
    40 /
    *
    41 * This must not be transient as the proposed transactions refers to it
    42 /
    43 private CDBSimpleMap<UUID, String> table;
    44
    45 private void putTableTransactionally() throws Exception {
    46 ITransactionCommand writeCommand = (ITransactionCommand) (opts) -> {
    47 UUID newKey = UUID.randomUUID();
    48 String newValue = "dummy";
    49 table.put(newKey, newValue);
    50 String msg = "PUT into table : key = " + newKey + ", value = "
    51 + newValue;
    52 System.out.println(msg);
    53 return msg;
    54 };
    55 ITimestamp t = new DeferredTransaction<>(cdr.getLocalInstance(),
    56 writeCommand).propose();
    57 logger.info("PUT transaction is proposed at {}", t);
    58 }
    59
    60 private int countTableTransactionally() throws Exception {
    61 ITransactionCommand countCommand = (ITransactionCommand) (opts) -> {
    62 int count = table.size();
    63 String msg = "SHOWCOUNT = " + count;
    64 System.out.println(msg);
    65 return count;
    66 };
    67 ITimestamp t = null;
    68 t = new DeferredTransaction<>(cdr.getLocalInstance(), countCommand)
    69 .propose();
    70 logger.info("SHOWCOUNT transaction is proposed at {}", t);
    71 table.sync(t);
    72 return table.size();
    73 }
    74
    75 @test
    76 public void testDeferredTx() throws Exception {
    77 /
    *
    78 * create table as a CDBSimpleMap instance
    79 /
    80 UUID mapuuid = UUID.fromString("1442df14-7220-11e5-9d70-feff819cdc9f");
    81 Map<String, Object> options = new HashMap<String, Object>();
    82 options.put("--master", "http://localhost:8002/corfu");
    83 options.put("--stream-impl", "NewStream");
    84 CorfuDBFactory cdf = new CorfuDBFactory(options);
    85 cdr = cdf.getRuntime();
    86 IStream stream = cdr.getLocalInstance().openStream(mapuuid);
    87 table = (CDBSimpleMap<UUID, String>) cdr.getLocalInstance().openObject(
    88 mapuuid, CDBSimpleMap.class);
    89 logger.info("Done initializing map instance.");
    90
    91 /
    *
    92 * tests:
    93 *
    94 * 1. issue a transaction to put a new key-value pair to table
    95 *
    96 * 2. issue a transaction to show the size of the table, sync the table
    97 * immediately to commit the write/read tx
    98 */
    99 putTableTransactionally();
    100 int count = countTableTransactionally();
    101 logger.info("after counting, count = {}", count);
    102
    103 cdr.close();
    104 logger.info("Test finished.");
    105 }
    106 }

  • steps to reproduce this issue:
    Reset (or restart) the CorfuDB cluster, run the test case twice to see the issue happen on the 2nd run of the test case.

Test behaves normally in the 1st run of the test, see logs:

[main] INFO com.vmware.nsx.demo.test.l2.L2DeferredTxTest - PUT transaction is proposed at 0

[main] INFO com.vmware.nsx.demo.test.l2.L2DeferredTxTest - SHOWCOUNT transaction is proposed at 1

[main] INFO org.corfudb.runtime.view.LocalCorfuDBInstance - got cached stream

[ForkJoinPool.commonPool-worker-2] INFO org.corfudb.runtime.smr.DeferredTransaction - Executing transaction.

PUT into table : key = 2f7865a6-fd5c-4eab-9a40-9663963d7571, value = dummy

[ForkJoinPool.commonPool-worker-2] INFO org.corfudb.runtime.smr.DeferredTransaction - Executing transaction.

SHOWCOUNT = 1

[main] INFO com.vmware.nsx.demo.test.l2.L2DeferredTxTest - after counting, count = 1

[main] INFO com.vmware.nsx.demo.test.l2.L2DeferredTxTest - Test finished.

On the 2nd run of the test, these errors are seen below:

[main] INFO com.vmware.nsx.demo.test.l2.L2DeferredTxTest - PUT transaction is proposed at 2

[main] INFO com.vmware.nsx.demo.test.l2.L2DeferredTxTest - SHOWCOUNT transaction is proposed at 3

[main] INFO org.corfudb.runtime.view.LocalCorfuDBInstance - got cached stream

[org.corfudb.runtime.protocols.AbstractNettyProtocol$2-event-1] ERROR org.corfudb.runtime.protocols.NettyRPCChannelInboundHandlerAdapter - Exception during channel handling.

java.lang.ClassCastException: cannot assign instance of java.lang.invoke.SerializedLambda to field org.corfudb.runtime.smr.DeferredTransaction.transaction of type org.corfudb.runtime.smr.ITransactionCommand in instance of org.corfudb.runtime.smr.DeferredTransaction

at java.io.ObjectStreamClass$FieldReflector.setObjFieldValues(ObjectStreamClass.java:2089)

at java.io.ObjectStreamClass.setObjFieldValues(ObjectStreamClass.java:1261)

at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2006)

at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1924)

at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801)

at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)

at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)

at org.corfudb.util.serializer.JavaSerializer.deserialize(JavaSerializer.java:29)

at org.corfudb.runtime.smr.smrprotocol.TransactionalLambdaSMRCommand.fromBuffer(TransactionalLambdaSMRCommand.java:78)

at org.corfudb.runtime.smr.smrprotocol.SMRCommand.deserialize(SMRCommand.java:86)

at org.corfudb.util.serializer.CorfuSerializer.deserialize(CorfuSerializer.java:80)

at org.corfudb.infrastructure.wireprotocol.NettyLogUnitPayloadMsg.getPayload(NettyLogUnitPayloadMsg.java:36)

at org.corfudb.runtime.protocols.logunits.INewWriteOnceLogUnit$ReadResult.(INewWriteOnceLogUnit.java:80)

at org.corfudb.runtime.protocols.logunits.NettyLogUnitProtocol$NettyLogUnitHandler.handleMessage(NettyLogUnitProtocol.java:158)

at org.corfudb.runtime.protocols.NettyRPCChannelInboundHandlerAdapter.channelRead(NettyRPCChannelInboundHandlerAdapter.java:138)

at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:308)

at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:294)

at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:244)

at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:308)

at io.netty.channel.AbstractChannelHandlerContext.access$600(AbstractChannelHandlerContext.java:32)

at io.netty.channel.AbstractChannelHandlerContext$7.run(AbstractChannelHandlerContext.java:299)

at io.netty.util.concurrent.DefaultEventExecutor.run(DefaultEventExecutor.java:36)

at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:112)

at java.lang.Thread.run(Thread.java:745)

[org.corfudb.runtime.protocols.AbstractNettyProtocol$2-event-1] ERROR org.corfudb.runtime.protocols.NettyRPCChannelInboundHandlerAdapter - Exception during channel handling.

java.lang.ClassCastException: cannot assign instance of java.lang.invoke.SerializedLambda to field org.corfudb.runtime.smr.DeferredTransaction.transaction of type org.corfudb.runtime.smr.ITransactionCommand in instance of org.corfudb.runtime.smr.DeferredTransaction

at java.io.ObjectStreamClass$FieldReflector.setObjFieldValues(ObjectStreamClass.java:2089)

at java.io.ObjectStreamClass.setObjFieldValues(ObjectStreamClass.java:1261)

at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2006)

at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1924)

at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801)

at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)

at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)

at org.corfudb.util.serializer.JavaSerializer.deserialize(JavaSerializer.java:29)

at org.corfudb.runtime.smr.smrprotocol.TransactionalLambdaSMRCommand.fromBuffer(TransactionalLambdaSMRCommand.java:78)

at org.corfudb.runtime.smr.smrprotocol.SMRCommand.deserialize(SMRCommand.java:86)

at org.corfudb.util.serializer.CorfuSerializer.deserialize(CorfuSerializer.java:80)

at org.corfudb.infrastructure.wireprotocol.NettyLogUnitPayloadMsg.getPayload(NettyLogUnitPayloadMsg.java:36)

at org.corfudb.runtime.protocols.logunits.INewWriteOnceLogUnit$ReadResult.(INewWriteOnceLogUnit.java:80)

at org.corfudb.runtime.protocols.logunits.NettyLogUnitProtocol$NettyLogUnitHandler.handleMessage(NettyLogUnitProtocol.java:158)

at org.corfudb.runtime.protocols.NettyRPCChannelInboundHandlerAdapter.channelRead(NettyRPCChannelInboundHandlerAdapter.java:138)

at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:308)

at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:294)

at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:244)

at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:308)

at io.netty.channel.AbstractChannelHandlerContext.access$600(AbstractChannelHandlerContext.java:32)

at io.netty.channel.AbstractChannelHandlerContext$7.run(AbstractChannelHandlerContext.java:299)

at io.netty.util.concurrent.DefaultEventExecutor.run(DefaultEventExecutor.java:36)

at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:112)

at java.lang.Thread.run(Thread.java:745)

Write unit tests for all collections

All the collections need to have some sort of unit test written so we can have some confidence about their correctness. This will probably require all collections to be ported first, see #12

NettyLogUnitMetaDataMsg limits # of streams

NettyLogUnitMetaDataMsg uses one byte for # of streams. This limits a log entry to belong to at most 128 streams. We may want to use a more flexible scheme down the line: use the first bit to indicate a single byte or an integer.

corfuDBTest.sh script doesn't work for CorfuShell

Should remove the < /dev/null on the last line corfuDBTest.sh for the CorfuShell test, because CorfuShell reads input from System.in. Otherwise ./bin/corfuDBTest.sh CorfuShell currently doesn't work.

Submit to Maven Central

We need an artifact in Maven Central so users can quickly get started with using CorfuDB.

Cleanup Script Directory

The scripts in bin contain a lot of leftovers from the SOSP submission. They probably could use some cleaning up.

Switch to containers for Travis-CI

Travis containers should allow for faster build times and allow us to use the Travis caching infrastructure.

This would require manual compilation of thrift-compiler, which we currently pull as a .deb and install using sudo (not available in containers).

Support Configuration Master Failover

When the configuration master fails, a backup configuration master should be able to restore itself using a quorum-based, failure resilient protocol.

remove transactional context semantics

The current method of starting a transaction, which involves creating a transactional context is awkward and error prone. We should switch to using a threadlocal, and make the transactional context transparent to the user.

Unexpose completable futures from commands

Currently, commands return result in getReturnResult().complete. This is a bit of an awkard programming model - we should just have the completable future accept a result supplied by the lambda.

Support Optimistic Transactions

Optimistic transactions work by executing optimistically using the local snapshot, and placing the entry on the log with the set of objects affected by the transaction and the snapshot timestamp.

When an object (SMR engine) encounters the transaction on the log, it executes it only if the snapshot timestamp is valid, otherwise, it fails, since other objects may be touched by the transaction.

Efficient time travel support

Currently, the time traveling implementation relies on oneshotsmrengine, which plays the log from the beginning instead of using a snapshot when there is no reversible command. We need to regularly generate snapshots when a reversible command is not used.

Smarter stream implementation

Currently the simple stream implementation doesn't do much; in fact, it reads every single entry in order to resolve the stream, relying on caching to be efficient.

Compilation error in current master

I just pulled the tip of the master branch. Upon mvn clean install, it stumbled over the following compile error:

[ERROR] /C:/Users/marku_000/Documents/GitHub/CORFU/CORFUAPPS/src/main/java/com/microsoft/corfuapps/CorfuShell.java:[14,33] package com.microsoft.corfu.sunit does not exist
[ERROR] /C:/Users/marku_000/Documents/GitHub/CORFU/CORFUAPPS/src/main/java/com/microsoft/corfuapps/CorfuShell.java:[91,25] cannot find symbol
  symbol: class UnitWrap

Seems like there is a file missing on GitHub?

Trim Support

Trimming the address space should be fully supported, even on streams. This means that trim needs to be stream-aware, and it might need to be a global operation.

Fix Travis-CI random hangs

Sometimes the Travis-CI build hangs during integration testing. Make a note of when this occurs and fix it, since it might indicate a deeper issue in the system...

Bundle

We need a way to insert an entry into multiple streams at the same time. Previously, we had a class called bundle responsible for doing this.

It's time to resurrect that interface for the new APIs.

Isolate log to a CorfuDBInstance

We should create a new CorfuDBInstance class, which represents an "instance" of a log.

This instance would contain a WriteOnceAddressSpace, a Sequencer and a ConfigurationMaster. It would also contain methods to open a stream and bundle.

Code Review

Code Review:
Netty Changes
New Serialization Framework
Client Side
Transactions
Server Side

Type safety for CDB objects

Currently, a CDB object can open a stream which is of the wrong type. We should detect when this happens and throw a runtime error to the user.

Right now, and error doesn't get thrown until the object calls sync, which may be too late to provide meaningful debug information.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.