Commit bc41e36c authored by Ricki Hirner's avatar Ricki Hirner 🐑

Handle TransactionTooLargeException correctly when a single operation is too large

parent 32e2966b
Pipeline #4733027 passed with stage
in 11 minutes and 26 seconds
......@@ -21,6 +21,7 @@ import org.junit.Test;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import ezvcard.VCardVersion;
import ezvcard.property.Address;
......@@ -82,9 +83,9 @@ public class AndroidContactTest {
}
@Test
public void testLargeTransaction() throws FileNotFoundException, ContactsStorageException {
public void testLargeTransactionManyRows() throws FileNotFoundException, ContactsStorageException {
Contact vcard = new Contact();
vcard.displayName = "Large Transaction";
vcard.displayName = "Large Transaction (many rows)";
for (int i = 0; i < 4000; i++)
vcard.emails.add(new LabeledProperty<Email>(new Email("test" + i + "@example.com")));
......@@ -96,6 +97,20 @@ public class AndroidContactTest {
assertEquals(4000, vcard2.emails.size());
}
@Test(expected = ContactsStorageException.class)
public void testLargeTransactionSingleRow() throws FileNotFoundException, ContactsStorageException {
Contact vcard = new Contact();
vcard.displayName = "Large Transaction (one row which is too large)";
// 1 MB eTag ... have fun
char data[] = new char[1024*1024];
Arrays.fill(data, 'x');
String eTag = new String(data);
AndroidContact contact = new AndroidContact(addressBook, vcard, null, eTag);
contact.create();
}
@Test
public void testAddressCaretEncoding() throws IOException {
Address address = new Address();
......
......@@ -76,7 +76,18 @@ public class BatchOperation {
}
/**
* Runs a subset of the operations in {@link #queue} using {@link #providerClient} in a transaction.
* Catches {@link TransactionTooLargeException} and splits the operations accordingly.
* @param start index of first operation which will be run (inclusive)
* @param end index of last operation which will be run (exclusive!)
* @throws RemoteException if the provider clients throws a {@link RemoteException}, or
* if the transaction is too large and can't be split
*/
private void runBatch(int start, int end) throws RemoteException, OperationApplicationException, ContactsStorageException {
if (end == start)
return; // nothing to do
try {
Constants.log.fine("Running operations " + start + " to " + (end - 1));
ContentProviderResult partResults[] = providerClient.applyBatch(toCPO(start, end));
......@@ -87,6 +98,10 @@ public class BatchOperation {
System.arraycopy(partResults, 0, results, start, n);
} catch(TransactionTooLargeException e) {
if (end <= start + 1)
// only one operation, can't be split
throw new RemoteException("Can't transfer data to content provider (data row too large)");
Constants.log.warning("Transaction too large, splitting (losing atomicity)");
int mid = start + (end - start)/2;
runBatch(start, mid);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment