Skip to content

Commit

Permalink
prototype write only mode
Browse files Browse the repository at this point in the history
  • Loading branch information
pgpv authored and henriknyman committed Feb 26, 2016
1 parent dcf58f0 commit 61d4f07
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 21 deletions.
Expand Up @@ -66,7 +66,29 @@ public boolean allowsSchemaWrites()
} }
}, },


/** Allows reading data and schema, but not writing. */ /** Allows writing data */
WRITE_ONLY
{
@Override
public boolean allowsReads()
{
return false;
}

@Override
public boolean allowsWrites()
{
return true;
}

@Override
public boolean allowsSchemaWrites()
{
return false;
}
},

/** Allows reading and writing data, but not schema. */
WRITE WRITE
{ {
@Override @Override
Expand Down
Expand Up @@ -58,6 +58,7 @@ public KernelStatement( KernelTransactionImplementation transaction,
@Override @Override
public ReadOperations readOperations() public ReadOperations readOperations()
{ {
transaction.verifyReadTransaction();
return facade; return facade;
} }


Expand All @@ -71,15 +72,15 @@ public TokenWriteOperations tokenWriteOperations()
public DataWriteOperations dataWriteOperations() public DataWriteOperations dataWriteOperations()
throws InvalidTransactionTypeKernelException throws InvalidTransactionTypeKernelException
{ {
transaction.upgradeToDataTransaction(); transaction.verifyDataWriteTransaction();
return facade; return facade;
} }


@Override @Override
public SchemaWriteOperations schemaWriteOperations() public SchemaWriteOperations schemaWriteOperations()
throws InvalidTransactionTypeKernelException throws InvalidTransactionTypeKernelException
{ {
transaction.upgradeToSchemaTransaction(); transaction.verifySchemaWriteTransaction();
return facade; return facade;
} }


Expand Down
Expand Up @@ -74,34 +74,52 @@ public class KernelTransactionImplementation implements KernelTransaction, TxSta


private enum TransactionType private enum TransactionType
{ {
READ, NONE,
DATA READ_ONLY,
READ_AND_DATA_WRITE
{ {
@Override @Override
TransactionType upgradeToSchemaTransaction() throws InvalidTransactionTypeKernelException TransactionType enableSchemaWriteTransaction() throws InvalidTransactionTypeKernelException
{ {
throw new InvalidTransactionTypeKernelException( throw new InvalidTransactionTypeKernelException(
"Cannot perform schema updates in a transaction that has performed data updates." ); "Cannot perform schema updates in a transaction that has performed data updates." );
} }

@Override
TransactionType enableReadTransaction()
{
return READ_AND_DATA_WRITE;
}
}, },
SCHEMA READ_AND_SCHEMA_WRITE
{ {
@Override @Override
TransactionType upgradeToDataTransaction() throws InvalidTransactionTypeKernelException TransactionType enableDataWriteTransaction() throws InvalidTransactionTypeKernelException
{ {
throw new InvalidTransactionTypeKernelException( throw new InvalidTransactionTypeKernelException(
"Cannot perform data updates in a transaction that has performed schema updates." ); "Cannot perform data updates in a transaction that has performed schema updates." );
} }

@Override
TransactionType enableReadTransaction()
{
return READ_AND_SCHEMA_WRITE;
}
}; };


TransactionType upgradeToDataTransaction() throws InvalidTransactionTypeKernelException TransactionType enableReadTransaction() throws IllegalStateException
{ {
return DATA; return READ_ONLY;
} }


TransactionType upgradeToSchemaTransaction() throws InvalidTransactionTypeKernelException TransactionType enableDataWriteTransaction() throws InvalidTransactionTypeKernelException
{ {
return SCHEMA; return READ_AND_DATA_WRITE;
}

TransactionType enableSchemaWriteTransaction() throws InvalidTransactionTypeKernelException
{
return READ_AND_SCHEMA_WRITE;
} }
} }


Expand All @@ -127,11 +145,11 @@ TransactionType upgradeToSchemaTransaction() throws InvalidTransactionTypeKernel
// whereas others, such as timestamp or txId when transaction starts, even locks, needs to be set in #initialize(). // whereas others, such as timestamp or txId when transaction starts, even locks, needs to be set in #initialize().
private TransactionState txState; private TransactionState txState;
private LegacyIndexTransactionState legacyIndexTransactionState; private LegacyIndexTransactionState legacyIndexTransactionState;
private TransactionType transactionType; // Tracks current state of transaction, which will upgrade to WRITE or SCHEMA mode when necessary private TransactionType transactionType; // Tracks current state of transaction, which will upgrade to WRITE or READ_AND_SCHEMA_WRITE mode when necessary
private TransactionHooks.TransactionHooksState hooksState; private TransactionHooks.TransactionHooksState hooksState;
private KernelStatement currentStatement; private KernelStatement currentStatement;
private CloseListener closeListener; private CloseListener closeListener;
private AccessMode accessMode; // Defines whether a transaction is allowed to upgrade to WRITE or SCHEMA mode private AccessMode accessMode; // Defines whether a transaction is allowed to upgrade to WRITE or READ_AND_SCHEMA_WRITE mode
private Locks.Client locks; private Locks.Client locks;
private boolean beforeHookInvoked; private boolean beforeHookInvoked;
private boolean closing, closed; private boolean closing, closed;
Expand Down Expand Up @@ -180,7 +198,7 @@ public KernelTransactionImplementation initialize(
this.type = type; this.type = type;
this.locks = locks; this.locks = locks;
this.closing = closed = failure = success = terminated = beforeHookInvoked = false; this.closing = closed = failure = success = terminated = beforeHookInvoked = false;
this.transactionType = TransactionType.READ; this.transactionType = TransactionType.NONE;
this.startTimeMillis = clock.currentTimeMillis(); this.startTimeMillis = clock.currentTimeMillis();
this.lastTransactionIdWhenStarted = lastCommittedTx; this.lastTransactionIdWhenStarted = lastCommittedTx;
this.transactionEvent = tracer.beginTransaction(); this.transactionEvent = tracer.beginTransaction();
Expand Down Expand Up @@ -252,25 +270,36 @@ public void releaseStatement( Statement statement )
currentStatement = null; currentStatement = null;
} }


public void upgradeToDataTransaction() throws InvalidTransactionTypeKernelException public void verifyReadTransaction()
{
if( !accessMode.allowsReads() )
{
throw new IllegalStateException(
String.format( "Read operations are not allowed for `%s` transactions.", accessMode.name() ) );
}

transactionType.enableReadTransaction();
}

public void verifyDataWriteTransaction() throws InvalidTransactionTypeKernelException
{ {
if( !accessMode.allowsWrites() ) if( !accessMode.allowsWrites() )
{ {
throw new InvalidTransactionTypeKernelException( throw new InvalidTransactionTypeKernelException(
String.format( "Write operations are not allowed for `%s` transactions.", accessMode.name() ) ); String.format( "Write operations are not allowed for `%s` transactions.", accessMode.name() ) );
} }
transactionType = transactionType.upgradeToDataTransaction(); transactionType = transactionType.enableDataWriteTransaction();
} }


public void upgradeToSchemaTransaction() throws InvalidTransactionTypeKernelException public void verifySchemaWriteTransaction() throws InvalidTransactionTypeKernelException
{ {
if( !accessMode.allowsSchemaWrites() ) if( !accessMode.allowsSchemaWrites() )
{ {
throw new InvalidTransactionTypeKernelException( throw new InvalidTransactionTypeKernelException(
String.format( "Schema write operations are not allowed for `%s` transactions.", accessMode.name() ) ); String.format( "Schema write operations are not allowed for `%s` transactions.", accessMode.name() ) );
} }
doUpgradeToSchemaTransaction(); doUpgradeToSchemaTransaction();
transactionType = transactionType.upgradeToSchemaTransaction(); transactionType = transactionType.enableSchemaWriteTransaction();
} }


public void doUpgradeToSchemaTransaction() throws InvalidTransactionTypeKernelException public void doUpgradeToSchemaTransaction() throws InvalidTransactionTypeKernelException
Expand Down
Expand Up @@ -26,6 +26,7 @@
import org.neo4j.kernel.api.AccessMode; import org.neo4j.kernel.api.AccessMode;
import org.neo4j.kernel.api.DataWriteOperations; import org.neo4j.kernel.api.DataWriteOperations;
import org.neo4j.kernel.api.KernelTransactionTestBase; import org.neo4j.kernel.api.KernelTransactionTestBase;
import org.neo4j.kernel.api.ReadOperations;
import org.neo4j.kernel.api.SchemaWriteOperations; import org.neo4j.kernel.api.SchemaWriteOperations;
import org.neo4j.kernel.api.exceptions.KernelException; import org.neo4j.kernel.api.exceptions.KernelException;


Expand All @@ -35,6 +36,19 @@ public class KernelTransactionAccessModeTest extends KernelTransactionTestBase
{ {
@Rule public ExpectedException exception = ExpectedException.none(); @Rule public ExpectedException exception = ExpectedException.none();


@Test
public void shouldAllowReadsInReadMode() throws Throwable
{
// Given
KernelTransactionImplementation tx = newTransaction( AccessMode.READ );

// When
ReadOperations reads = tx.acquireStatement().readOperations();

// Then
assertNotNull( reads );
}

@Test @Test
public void shouldNotAllowWriteAccessInReadMode() throws Throwable public void shouldNotAllowWriteAccessInReadMode() throws Throwable
{ {
Expand Down Expand Up @@ -62,10 +76,36 @@ public void shouldNotAllowSchemaWriteAccessInReadMode() throws Throwable
} }


@Test @Test
public void shouldNotAllowSchemaWriteAccessInWriteMode() throws Throwable public void shouldNotAllowReadAccessInWriteOnlyMode() throws Throwable
{ {
// Given // Given
KernelTransactionImplementation tx = newTransaction( AccessMode.WRITE ); KernelTransactionImplementation tx = newTransaction( AccessMode.WRITE_ONLY );

// Expect
exception.expect( IllegalStateException.class );

// When
tx.acquireStatement().readOperations();
}

@Test
public void shouldAllowWriteAccessInWriteOnlyMode() throws Throwable
{
// Given
KernelTransactionImplementation tx = newTransaction( AccessMode.WRITE_ONLY );

// When
DataWriteOperations writes = tx.acquireStatement().dataWriteOperations();

// Then
assertNotNull( writes );
}

@Test
public void shouldNotAllowSchemaWriteAccessInWriteOnlyMode() throws Throwable
{
// Given
KernelTransactionImplementation tx = newTransaction( AccessMode.WRITE_ONLY );


// Expect // Expect
exception.expect( KernelException.class ); exception.expect( KernelException.class );
Expand All @@ -74,6 +114,19 @@ public void shouldNotAllowSchemaWriteAccessInWriteMode() throws Throwable
tx.acquireStatement().schemaWriteOperations(); tx.acquireStatement().schemaWriteOperations();
} }


@Test
public void shouldAllowReadsInWriteMode() throws Throwable
{
// Given
KernelTransactionImplementation tx = newTransaction( AccessMode.WRITE );

// When
ReadOperations reads = tx.acquireStatement().readOperations();

// Then
assertNotNull( reads );
}

@Test @Test
public void shouldAllowWritesInWriteMode() throws Throwable public void shouldAllowWritesInWriteMode() throws Throwable
{ {
Expand All @@ -87,6 +140,32 @@ public void shouldAllowWritesInWriteMode() throws Throwable
assertNotNull( writes ); assertNotNull( writes );
} }


@Test
public void shouldNotAllowSchemaWriteAccessInWriteMode() throws Throwable
{
// Given
KernelTransactionImplementation tx = newTransaction( AccessMode.WRITE );

// Expect
exception.expect( KernelException.class );

// When
tx.acquireStatement().schemaWriteOperations();
}

@Test
public void shouldAllowReadsInFullMode() throws Throwable
{
// Given
KernelTransactionImplementation tx = newTransaction( AccessMode.FULL );

// When
ReadOperations reads = tx.acquireStatement().readOperations();

// Then
assertNotNull( reads );
}

@Test @Test
public void shouldAllowWritesInFullMode() throws Throwable public void shouldAllowWritesInFullMode() throws Throwable
{ {
Expand Down

0 comments on commit 61d4f07

Please sign in to comment.