├── keystorepassword.txt ├── .gitignore ├── dblocking.apk ├── res ├── drawable-hdpi │ └── icon.png ├── drawable-ldpi │ └── icon.png ├── drawable-mdpi │ └── icon.png ├── values │ └── strings.xml └── layout │ └── main.xml ├── default.properties ├── src └── co │ └── touchlab │ └── dblocking │ ├── SqliteTransactionEndListener.java │ ├── TransactionEndListener.java │ ├── EventTimer.java │ ├── TickerBar.java │ ├── DatabaseHelper.java │ └── SqliteDbX.java ├── AndroidManifest.xml ├── proguard.cfg ├── dblocking.iml ├── README └── dblocking.ipr /keystorepassword.txt: -------------------------------------------------------------------------------- 1 | flapjack -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.iml 3 | .idea/* 4 | 5 | bin 6 | gen 7 | target 8 | out 9 | -------------------------------------------------------------------------------- /dblocking.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2point0/Android-Database-Locking-Collisions-Example/HEAD/dblocking.apk -------------------------------------------------------------------------------- /res/drawable-hdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2point0/Android-Database-Locking-Collisions-Example/HEAD/res/drawable-hdpi/icon.png -------------------------------------------------------------------------------- /res/drawable-ldpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2point0/Android-Database-Locking-Collisions-Example/HEAD/res/drawable-ldpi/icon.png -------------------------------------------------------------------------------- /res/drawable-mdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2point0/Android-Database-Locking-Collisions-Example/HEAD/res/drawable-mdpi/icon.png -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | SQLite DB Example, by touchlab 4 | 5 | -------------------------------------------------------------------------------- /default.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system use, 7 | # "build.properties", and override values to adapt the script to your 8 | # project structure. 9 | 10 | # Project target. 11 | target=Google Inc.:Google APIs:10 12 | -------------------------------------------------------------------------------- /src/co/touchlab/dblocking/SqliteTransactionEndListener.java: -------------------------------------------------------------------------------- 1 | package co.touchlab.dblocking; 2 | 3 | import android.database.sqlite.SQLiteTransactionListener; 4 | 5 | /** 6 | * Created with IntelliJ IDEA. 7 | * User: qui 8 | * Date: 10/10/12 9 | * Time: 5:34 PM 10 | * To change this template use File | Settings | File Templates. 11 | */ 12 | public interface SqliteTransactionEndListener extends SQLiteTransactionListener { 13 | 14 | public static final int BEGIN = 0; 15 | public static final int COMMIT = BEGIN + 1; 16 | public static final int ROLLBACK = COMMIT + 1; 17 | public static final int END = ROLLBACK + 1; 18 | 19 | public void onEnd(); 20 | } 21 | -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /proguard.cfg: -------------------------------------------------------------------------------- 1 | -optimizationpasses 5 2 | -dontusemixedcaseclassnames 3 | -dontskipnonpubliclibraryclasses 4 | -dontpreverify 5 | -verbose 6 | -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* 7 | 8 | -keep public class * extends android.app.Activity 9 | -keep public class * extends android.app.Application 10 | -keep public class * extends android.app.Service 11 | -keep public class * extends android.content.BroadcastReceiver 12 | -keep public class * extends android.content.ContentProvider 13 | -keep public class * extends android.app.backup.BackupAgentHelper 14 | -keep public class * extends android.preference.Preference 15 | -keep public class com.android.vending.licensing.ILicensingService 16 | 17 | -keepclasseswithmembernames class * { 18 | native ; 19 | } 20 | 21 | -keepclasseswithmembers class * { 22 | public (android.content.Context, android.util.AttributeSet); 23 | } 24 | 25 | -keepclasseswithmembers class * { 26 | public (android.content.Context, android.util.AttributeSet, int); 27 | } 28 | 29 | -keepclassmembers class * extends android.app.Activity { 30 | public void *(android.view.View); 31 | } 32 | 33 | -keepclassmembers enum * { 34 | public static **[] values(); 35 | public static ** valueOf(java.lang.String); 36 | } 37 | 38 | -keep class * implements android.os.Parcelable { 39 | public static final android.os.Parcelable$Creator *; 40 | } 41 | -------------------------------------------------------------------------------- /src/co/touchlab/dblocking/TransactionEndListener.java: -------------------------------------------------------------------------------- 1 | package co.touchlab.dblocking; 2 | 3 | import android.util.Log; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * Created with IntelliJ IDEA. 10 | * User: qui 11 | * Date: 10/10/12 12 | * Time: 4:58 PM 13 | * To change this template use File | Settings | File Templates. 14 | */ 15 | public class TransactionEndListener implements SqliteTransactionEndListener { 16 | private static final String TAG = TransactionEndListener.class.getSimpleName(); 17 | 18 | protected final List mEvents; 19 | 20 | protected final EventTimer mEventTimer; 21 | 22 | public TransactionEndListener(EventTimer eventTimer) { 23 | mEvents = new ArrayList(); 24 | mEventTimer = eventTimer; 25 | } 26 | 27 | @Override public void onBegin() {} 28 | 29 | // @debug Counts commits to compare to ends 30 | private int mCommitCount = 0; 31 | 32 | @Override 33 | public void onCommit() { 34 | // @reminder Comparison of commits vs ends 35 | Log.i(TAG, String.format("onCommit: %1$d, events: %2$d", ++mCommitCount, mEvents.size())); 36 | } 37 | 38 | // @Override 39 | public void onEnd() { 40 | mEvents.add(END); 41 | 42 | if(mEvents.size() == mEventTimer.expectedEvents) { 43 | mEventTimer.stop(); 44 | } 45 | } 46 | 47 | @Override public void onRollback() {} 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/co/touchlab/dblocking/EventTimer.java: -------------------------------------------------------------------------------- 1 | package co.touchlab.dblocking; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created with IntelliJ IDEA. 7 | * User: qui 8 | * Date: 10/10/12 9 | * Time: 4:51 PM 10 | * To change this template use File | Settings | File Templates. 11 | */ 12 | public final class EventTimer { 13 | 14 | public final int expectedEvents; 15 | 16 | private long mStartTime; 17 | private List mTickTimes; 18 | private long mEndTime; 19 | 20 | public EventTimer(int expectedEvents) { 21 | this.expectedEvents = expectedEvents; 22 | mStartTime = 0; 23 | mEndTime = 0; 24 | } 25 | 26 | public long start() { 27 | mStartTime = System.currentTimeMillis(); 28 | return mStartTime; 29 | } 30 | 31 | public long tick() { 32 | long tick = System.currentTimeMillis(); 33 | mTickTimes.add(tick); 34 | return tick; 35 | } 36 | 37 | public long stop() { 38 | mEndTime = System.currentTimeMillis(); 39 | 40 | if(mOnEventListener != null) { 41 | mOnEventListener.onStop(mEndTime - mStartTime); 42 | } 43 | 44 | return mEndTime; 45 | } 46 | 47 | public long delta() { 48 | return mEndTime - mStartTime; 49 | } 50 | 51 | public long[] tickDeltas() { 52 | final int S = mTickTimes.size(); 53 | long[] deltas = new long[S]; 54 | for(int i=0; i 2 | 3 | 4 | 5 | 6 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Example app showing how you can cause DB collisions pretty easily with multiple SQLiteHelper instances. 2 | 3 | Also demonstrate dramatic time difference using transactions. 4 | 5 | Button :Description 6 | 1 Write :Perform writes from multiple threads using only one instance of a DatabaseHelper. This should never cause a failure 7 | + Write :Perform writes from multiple threads, each thread with its own DatabaseHelper. First failure in a thread will end that thread leaving only one thread able to complete it's process. The ticker bar should have one dominant color [blue,white,yellow,red] (red at beginning and end signify start and end of run) 8 | 1 Write + Read :One thread performs writes while other threads perform reads. All threads have their own copy of DatabaseHelper. Failures can occur but if you're lucky, they won't. 9 | + Read :All threads perform reads with their own copy of DatabaseHelper. Failures can occur but if you're lucky, they won't. 10 | Test Transaction Isolation :Interleaving reads and writes with the same copy of DatabaseHelper will not fail but transactions are exclusive and cannot be disturbed. 11 | No Transaction :Perform a timed series of writes individually 12 | Transaction :Perform a timed series of writes in a transaction 13 | Exclusive No Yielding :One long running transaction and many short running transactions are performed. Each transaction is exclusive and must complete before another transaction/operation is allowed. The ticker bar should show the long transaction finishing before trailing short transactions run. 14 | Safely Contended Yield :One long running transaction yielding at times to allow short running transactions to perform their operations. The ticker bar should show short transactions finishing before the long transaction finishes. 15 | No Yield Read :A thread performing writes in a transaction is followed by other threads performing reads. The write transaction must complete before reads can be made 16 | Yield and Read :A thread performing writes in a transaction yields to following threads performing reads. The yielding allows a few reads to execute before waiting for the entire write transaction to complete. 17 | -------------------------------------------------------------------------------- /res/layout/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 |