Merge pull request #819 from corda/chrisr3-os-merge

Merge from OS up to fe88e99
This commit is contained in:
Chris Rankin 2018-05-09 20:21:19 +01:00 committed by GitHub
commit 4b3ddc3946
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 105 additions and 86 deletions

View File

@ -68,7 +68,6 @@ import kotlin.reflect.KClass
import kotlin.reflect.full.createInstance
val Throwable.rootCause: Throwable get() = cause?.rootCause ?: this
fun Throwable.getStackTraceAsString() = StringWriter().also { printStackTrace(PrintWriter(it)) }.toString()
infix fun Temporal.until(endExclusive: Temporal): Duration = Duration.between(this, endExclusive)

View File

@ -475,47 +475,48 @@ existing object relational mapper. For example, we can update:
.. sourcecode:: java
public class ObligationSchemaV1 extends MappedSchema {
public IOUSchemaV1() {
public ObligationSchemaV1() {
super(Obligation.class, 1, ImmutableList.of(ObligationEntity.class));
}
}
@Entity
@Table(name = "obligations")
public static class ObligationEntity extends PersistentState {
@Column(name = "currency") private final String currency;
@Column(name = "amount") private final Long amount;
@Column(name = "lender") @Lob private final Byte[] lender;
@Column(name = "borrower") @Lob private final Byte[] borrower;
@Column(name = "linear_id") private final UUID linearId;
@Entity
@Table(name = "obligations")
public class ObligationEntity extends PersistentState {
@Column(name = "currency") private String currency;
@Column(name = "amount") private Long amount;
@Column(name = "lender") @Lob private byte[] lender;
@Column(name = "borrower") @Lob private byte[] borrower;
@Column(name = "linear_id") private UUID linearId;
protected ObligationEntity(){}
public ObligationEntity(String currency, Long amount, Byte[] lender, Byte[] borrower, UUID linearId) {
this.currency = currency;
this.amount = amount;
this.lender = lender;
this.borrower = borrower;
this.linearId = linearId;
}
public ObligationEntity(String currency, Long amount, byte[] lender, byte[] borrower, UUID linearId) {
this.currency = currency;
this.amount = amount;
this.lender = lender;
this.borrower = borrower;
this.linearId = linearId;
}
public String getCurrency() {
return currency;
}
public String getCurrency() {
return currency;
}
public Long getAmount() {
return amount;
}
public Long getAmount() {
return amount;
}
public ByteArray getLender() {
return lender;
}
public byte[] getLender() {
return lender;
}
public ByteArray getBorrower() {
return borrower;
}
public byte[] getBorrower() {
return borrower;
}
public UUID getId() {
return linearId;
}
public UUID getLinearId() {
return linearId;
}
}
@ -540,53 +541,54 @@ To:
.. sourcecode:: java
public class ObligationSchemaV1 extends MappedSchema {
public IOUSchemaV1() {
public ObligationSchemaV1() {
super(Obligation.class, 1, ImmutableList.of(ObligationEntity.class));
}
}
@Entity
@Table(name = "obligations")
public static class ObligationEntity extends PersistentState {
@Column(name = "currency") private final String currency;
@Column(name = "amount") private final Long amount;
@Column(name = "lender") @Lob private final Byte[] lender;
@Column(name = "borrower") @Lob private final Byte[] borrower;
@Column(name = "linear_id") private final UUID linearId;
@Column(name = "defaulted") private final Boolean defaulted; // NEW COLUMN!
@Entity
@Table(name = "obligations")
public class ObligationEntity extends PersistentState {
@Column(name = "currency") private String currency;
@Column(name = "amount") private Long amount;
@Column(name = "lender") @Lob private byte[] lender;
@Column(name = "borrower") @Lob private byte[] borrower;
@Column(name = "linear_id") private UUID linearId;
@Column(name = "defaulted") private Boolean defaulted; // NEW COLUMN!
protected ObligationEntity(){}
public ObligationEntity(String currency, Long amount, Byte[] lender, Byte[] borrower, UUID linearId, Boolean defaulted) {
this.currency = currency;
this.amount = amount;
this.lender = lender;
this.borrower = borrower;
this.linearId = linearId;
this.defaulted = defaulted;
}
public ObligationEntity(String currency, Long amount, byte[] lender, byte[] borrower, UUID linearId, Boolean defaulted) {
this.currency = currency;
this.amount = amount;
this.lender = lender;
this.borrower = borrower;
this.linearId = linearId;
this.defaulted = defaulted;
}
public String getCurrency() {
return currency;
}
public String getCurrency() {
return currency;
}
public Long getAmount() {
return amount;
}
public Long getAmount() {
return amount;
}
public ByteArray getLender() {
return lender;
}
public byte[] getLender() {
return lender;
}
public ByteArray getBorrower() {
return borrower;
}
public byte[] getBorrower() {
return borrower;
}
public UUID getId() {
return linearId;
}
public UUID getLinearId() {
return linearId;
}
public Boolean isDefaulted() {
return defaulted;
}
public Boolean isDefaulted() {
return defaulted;
}
}

View File

@ -134,10 +134,8 @@ class CordaPersistence(
* @param isolationLevel isolation level for the transaction.
* @param statement to be executed in the scope of this transaction.
*/
fun <T> transaction(isolationLevel: TransactionIsolationLevel, statement: DatabaseTransaction.() -> T): T {
_contextDatabase.set(this)
return transaction(isolationLevel, 2, statement)
}
fun <T> transaction(isolationLevel: TransactionIsolationLevel, statement: DatabaseTransaction.() -> T): T =
transaction(isolationLevel, 2, false, statement)
/**
* Executes given statement in the scope of transaction with the transaction level specified at the creation time.
@ -145,16 +143,26 @@ class CordaPersistence(
*/
fun <T> transaction(statement: DatabaseTransaction.() -> T): T = transaction(defaultIsolationLevel, statement)
private fun <T> transaction(isolationLevel: TransactionIsolationLevel, recoverableFailureTolerance: Int, statement: DatabaseTransaction.() -> T): T {
/**
* Executes given statement in the scope of transaction, with the given isolation level.
* @param isolationLevel isolation level for the transaction.
* @param recoverableFailureTolerance number of transaction commit retries for SQL while SQL exception is encountered.
* @param recoverAnyNestedSQLException retry transaction on any SQL Exception wrapped as a cause of [Throwable].
* @param statement to be executed in the scope of this transaction.
*/
fun <T> transaction(isolationLevel: TransactionIsolationLevel, recoverableFailureTolerance: Int,
recoverAnyNestedSQLException: Boolean, statement: DatabaseTransaction.() -> T): T {
_contextDatabase.set(this)
val outer = contextTransactionOrNull
return if (outer != null) {
outer.statement()
} else {
inTopLevelTransaction(isolationLevel, recoverableFailureTolerance, statement)
inTopLevelTransaction(isolationLevel, recoverableFailureTolerance, recoverAnyNestedSQLException, statement)
}
}
private fun <T> inTopLevelTransaction(isolationLevel: TransactionIsolationLevel, recoverableFailureTolerance: Int, statement: DatabaseTransaction.() -> T): T {
private fun <T> inTopLevelTransaction(isolationLevel: TransactionIsolationLevel, recoverableFailureTolerance: Int,
recoverAnyNestedSQLException: Boolean, statement: DatabaseTransaction.() -> T): T {
var recoverableFailureCount = 0
fun <T> quietly(task: () -> T) = try {
task()
@ -167,13 +175,14 @@ class CordaPersistence(
val answer = transaction.statement()
transaction.commit()
return answer
} catch (e: SQLException) {
quietly(transaction::rollback)
if (++recoverableFailureCount > recoverableFailureTolerance) throw e
log.warn("Caught failure, will retry:", e)
} catch (e: Throwable) {
quietly(transaction::rollback)
throw e
if (e is SQLException || (recoverAnyNestedSQLException && e.hasSQLExceptionCause())) {
if (++recoverableFailureCount > recoverableFailureTolerance) throw e
log.warn("Caught failure, will retry $recoverableFailureCount/$recoverableFailureTolerance:", e)
} else {
throw e
}
} finally {
quietly(transaction::close)
}
@ -277,4 +286,14 @@ fun parserTransactionIsolationLevel(property: String?): Int =
}
}
fun isH2Database(jdbcUrl: String) = jdbcUrl.startsWith("jdbc:h2:")
fun isH2Database(jdbcUrl: String) = jdbcUrl.startsWith("jdbc:h2:")
/** Check if any nested cause is of [SQLException] type. */
private fun Throwable.hasSQLExceptionCause(): Boolean =
if (cause == null)
false
else if (cause is SQLException)
true
else
cause?.hasSQLExceptionCause() ?: false

View File

@ -12,7 +12,6 @@ package net.corda.nodeapi.internal.serialization.amqp
import com.esotericsoftware.kryo.io.ByteBufferInputStream
import net.corda.core.internal.VisibleForTesting
import net.corda.core.internal.getStackTraceAsString
import net.corda.core.serialization.EncodingWhitelist
import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.SerializedBytes
@ -105,7 +104,7 @@ class DeserializationInput @JvmOverloads constructor(private val serializerFacto
@Throws(NotSerializableException::class)
fun getEnvelope(byteSequence: ByteSequence) = Companion.getEnvelope(byteSequence, encodingWhitelist)
fun getEnvelope(byteSequence: ByteSequence) = getEnvelope(byteSequence, encodingWhitelist)
@Throws(NotSerializableException::class)
inline fun <reified T : Any> deserialize(bytes: SerializedBytes<T>, context: SerializationContext): T =
@ -119,7 +118,7 @@ class DeserializationInput @JvmOverloads constructor(private val serializerFacto
} catch (nse: NotSerializableException) {
throw nse
} catch (t: Throwable) {
throw NotSerializableException("Unexpected throwable: ${t.message} ${t.getStackTraceAsString()}")
throw NotSerializableException("Unexpected throwable: ${t.message}").apply { initCause(t) }
} finally {
objectHistory.clear()
}
@ -173,7 +172,7 @@ class DeserializationInput @JvmOverloads constructor(private val serializerFacto
if (!objectRetrieved::class.java.isSubClassOf(type.asClass()!!)) {
throw NotSerializableException(
"Existing reference type mismatch. Expected: '$type', found: '${objectRetrieved::class.java}' " +
"@ ${objectIndex}")
"@ $objectIndex")
}
objectRetrieved
} else {

View File

@ -497,7 +497,7 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi
copy[valueIndex] = 0x00
assertThatExceptionOfType(NotSerializableException::class.java).isThrownBy {
des.deserialize(OpaqueBytes(copy), NonZeroByte::class.java, testSerializationContext)
}.withMessageContaining("Zero not allowed")
}.withStackTraceContaining("Zero not allowed")
}
@Test