Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/bitfireAT/vcard4android.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRicki Hirner <hirner@bitfire.at>2021-01-02 17:02:48 +0300
committerRicki Hirner <hirner@bitfire.at>2021-01-02 17:02:48 +0300
commit368898fc0221e65a5cb091a6d4a24c98219ba157 (patch)
tree91dd35c72984ba9e1518e839e98ec004973743a5
parent0b7c8875344f79f0ccdd433daf734dc4f806c5f9 (diff)
BatchOperation: fix back references when the transaction has to be split multiple times
-rw-r--r--src/main/java/at/bitfire/vcard4android/BatchOperation.kt47
1 files changed, 39 insertions, 8 deletions
diff --git a/src/main/java/at/bitfire/vcard4android/BatchOperation.kt b/src/main/java/at/bitfire/vcard4android/BatchOperation.kt
index ce49a11..1c8b936 100644
--- a/src/main/java/at/bitfire/vcard4android/BatchOperation.kt
+++ b/src/main/java/at/bitfire/vcard4android/BatchOperation.kt
@@ -102,6 +102,7 @@ class BatchOperation(
Constants.log.warning("Transaction too large, splitting (losing atomicity)")
val mid = start + (end - start)/2
+
runBatch(start, mid)
runBatch(mid, end)
}
@@ -110,18 +111,25 @@ class BatchOperation(
private fun toCPO(start: Int, end: Int): ArrayList<ContentProviderOperation> {
val cpo = ArrayList<ContentProviderOperation>(end - start)
+ /* Fix back references:
+ * 1. If a back reference points to a row between start and end,
+ * adapt the reference.
+ * 2. If a back reference points to a row outside of start/end,
+ * replace it by the actual result, which has already been calculated. */
+
for ((i, cpoBuilder) in queue.subList(start, end).withIndex()) {
- for ((backrefKey, backrefIdx) in cpoBuilder.valueBackrefs) {
- if (backrefIdx < start) {
+ for ((backrefKey, backref) in cpoBuilder.valueBackrefs) {
+ val originalIdx = backref.originalIndex
+ if (originalIdx < start) {
// back reference is outside of the current batch, get result from previous execution ...
- val resultUri = results[backrefIdx]?.uri ?: throw ContactsStorageException("Referenced operation didn't produce a valid result")
+ val resultUri = results[originalIdx]?.uri ?: throw ContactsStorageException("Referenced operation didn't produce a valid result")
val resultId = ContentUris.parseId(resultUri)
// ... and use result directly instead of using a back reference
cpoBuilder .removeValueBackReference(backrefKey)
.withValue(backrefKey, resultId)
} else
// back reference is in current batch, shift index
- cpoBuilder.withValueBackReference(backrefKey, backrefIdx - start)
+ backref.setIndex(originalIdx - start)
}
if (i % MAX_OPERATIONS_PER_YIELD_POINT == MAX_OPERATIONS_PER_YIELD_POINT - 1)
@@ -133,6 +141,29 @@ class BatchOperation(
}
+ class BackReference(
+ /** index of the referenced row in the original, nonsplitted transaction */
+ val originalIndex: Int
+ ) {
+ /** overriden index, i.e. index within the splitted transaction */
+ private var index: Int? = null
+
+ /**
+ * Sets the index to use in the splitted transaction.
+ * @param newIndex index to be used instead of [originalIndex]
+ */
+ fun setIndex(newIndex: Int) {
+ index = newIndex
+ }
+
+ /**
+ * Gets the index to use in the splitted transaction.
+ * @return [index] if it has been set, [originalIndex] otherwise
+ */
+ fun getIndex() = index ?: originalIndex
+ }
+
+
/**
* Wrapper for [ContentProviderOperation.Builder] that allows to reset previously-set
* value back references.
@@ -157,7 +188,7 @@ class BatchOperation(
var selectionArguments: Array<String>? = null
val values = mutableMapOf<String, Any?>()
- val valueBackrefs = mutableMapOf<String, Int>()
+ val valueBackrefs = mutableMapOf<String, BackReference>()
var yieldAllowed = false
@@ -169,7 +200,7 @@ class BatchOperation(
}
fun withValueBackReference(key: String, index: Int): CpoBuilder {
- valueBackrefs[key] = index
+ valueBackrefs[key] = BackReference(index)
return this
}
@@ -197,8 +228,8 @@ class BatchOperation(
for ((key, value) in values)
builder.withValue(key, value)
- for ((key, index) in valueBackrefs)
- builder.withValueBackReference(key, index)
+ for ((key, backref) in valueBackrefs)
+ builder.withValueBackReference(key, backref.getIndex())
if (yieldAllowed)
builder.withYieldAllowed(true)