diff --git a/.gitignore b/.gitignore index b629cecf1..434887534 100644 --- a/.gitignore +++ b/.gitignore @@ -52,3 +52,4 @@ local.properties ### Queue files *.cq4t *.cq4 + diff --git a/JCACHE.pdf b/JCACHE.pdf new file mode 100644 index 000000000..5772099e3 Binary files /dev/null and b/JCACHE.pdf differ diff --git a/Santos.pdf b/Santos.pdf new file mode 100644 index 000000000..5772099e3 Binary files /dev/null and b/Santos.pdf differ diff --git a/basEC.png b/basEC.png new file mode 100644 index 000000000..07e203b45 Binary files /dev/null and b/basEC.png differ diff --git a/capTradeoffs=Chronicle=BasEC.png b/capTradeoffs=Chronicle=BasEC.png new file mode 100644 index 000000000..cc5627d08 Binary files /dev/null and b/capTradeoffs=Chronicle=BasEC.png differ diff --git a/cp.txt b/cp.txt new file mode 100644 index 000000000..14bc72482 --- /dev/null +++ b/cp.txt @@ -0,0 +1 @@ +C:\Users\buddy\.m2\repository\com\intellij\annotations\12.0\annotations-12.0.jar;C:\Users\buddy\.m2\repository\net\openhft\chronicle-core\2.19.72-SNAPSHOT\chronicle-core-2.19.72-SNAPSHOT.jar;C:\Users\buddy\.m2\repository\org\jetbrains\annotations\19.0.0\annotations-19.0.0.jar;C:\Users\buddy\.m2\repository\net\openhft\chronicle-values\2.19.42\chronicle-values-2.19.42.jar;C:\Users\buddy\.m2\repository\net\openhft\chronicle-bytes\2.19.72-SNAPSHOT\chronicle-bytes-2.19.72-SNAPSHOT.jar;C:\Users\buddy\.m2\repository\com\squareup\javapoet\1.12.1\javapoet-1.12.1.jar;C:\Users\buddy\.m2\repository\net\openhft\chronicle-threads\2.19.70\chronicle-threads-2.19.70.jar;C:\Users\buddy\.m2\repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;C:\Users\buddy\.m2\repository\net\openhft\chronicle-wire\2.19.74-SNAPSHOT\chronicle-wire-2.19.74-SNAPSHOT.jar;C:\Users\buddy\.m2\repository\net\openhft\compiler\2.3.6\compiler-2.3.6.jar;C:\Users\buddy\.m2\repository\net\openhft\chronicle-algorithms\2.19.42\chronicle-algorithms-2.19.42.jar;C:\Users\buddy\.m2\repository\net\java\dev\jna\jna\5.5.0\jna-5.5.0.jar;C:\Users\buddy\.m2\repository\net\java\dev\jna\jna-platform\5.5.0\jna-platform-5.5.0.jar;C:\Users\buddy\.m2\repository\com\thoughtworks\xstream\xstream\1.4.12\xstream-1.4.12.jar;C:\Users\buddy\.m2\repository\xmlpull\xmlpull\1.1.3.1\xmlpull-1.1.3.1.jar;C:\Users\buddy\.m2\repository\xpp3\xpp3_min\1.1.4c\xpp3_min-1.1.4c.jar;C:\Users\buddy\.m2\repository\org\codehaus\jettison\jettison\1.4.1\jettison-1.4.1.jar;C:\Users\buddy\.m2\repository\org\ops4j\pax\url\pax-url-aether\2.6.2\pax-url-aether-2.6.2.jar;C:\Users\buddy\.m2\repository\org\ops4j\pax\url\pax-url-aether-support\2.6.2\pax-url-aether-support-2.6.2.jar;C:\Users\buddy\.m2\repository\org\apache\maven\resolver\maven-resolver-impl\1.3.1\maven-resolver-impl-1.3.1.jar;C:\Users\buddy\.m2\repository\org\apache\maven\resolver\maven-resolver-api\1.3.1\maven-resolver-api-1.3.1.jar;C:\Users\buddy\.m2\repository\org\apache\maven\resolver\maven-resolver-spi\1.3.1\maven-resolver-spi-1.3.1.jar;C:\Users\buddy\.m2\repository\org\apache\maven\resolver\maven-resolver-util\1.3.1\maven-resolver-util-1.3.1.jar;C:\Users\buddy\.m2\repository\org\slf4j\jcl-over-slf4j\1.6.6\jcl-over-slf4j-1.6.6.jar;C:\Users\buddy\.m2\repository\net\openhft\jlbh\1.19.30\jlbh-1.19.30.jar;C:\Users\buddy\.m2\repository\junit\junit\4.13\junit-4.13.jar;C:\Users\buddy\.m2\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;C:\Users\buddy\.m2\repository\org\slf4j\slf4j-simple\1.7.30\slf4j-simple-1.7.30.jar;C:\Users\buddy\.m2\repository\org\mockito\mockito-core\3.3.3\mockito-core-3.3.3.jar;C:\Users\buddy\.m2\repository\net\bytebuddy\byte-buddy\1.10.5\byte-buddy-1.10.5.jar;C:\Users\buddy\.m2\repository\net\bytebuddy\byte-buddy-agent\1.10.5\byte-buddy-agent-1.10.5.jar;C:\Users\buddy\.m2\repository\org\objenesis\objenesis\2.6\objenesis-2.6.jar;C:\Users\buddy\.m2\repository\org\powermock\powermock-module-junit4\2.0.7\powermock-module-junit4-2.0.7.jar;C:\Users\buddy\.m2\repository\org\powermock\powermock-module-junit4-common\2.0.7\powermock-module-junit4-common-2.0.7.jar;C:\Users\buddy\.m2\repository\org\powermock\powermock-reflect\2.0.7\powermock-reflect-2.0.7.jar;C:\Users\buddy\.m2\repository\org\powermock\powermock-core\2.0.7\powermock-core-2.0.7.jar;C:\Users\buddy\.m2\repository\org\javassist\javassist\3.27.0-GA\javassist-3.27.0-GA.jar;C:\Users\buddy\.m2\repository\org\powermock\powermock-api-mockito\1.7.4\powermock-api-mockito-1.7.4.jar;C:\Users\buddy\.m2\repository\org\powermock\powermock-api-mockito-common\1.7.4\powermock-api-mockito-common-1.7.4.jar;C:\Users\buddy\.m2\repository\org\powermock\powermock-api-support\1.7.4\powermock-api-support-1.7.4.jar;C:\Users\buddy\.m2\repository\net\openhft\affinity\3.2.4-SNAPSHOT\affinity-3.2.4-SNAPSHOT.jar;C:\Users\buddy\.m2\repository\com\google\guava\guava-testlib\19.0\guava-testlib-19.0.jar;C:\Users\buddy\.m2\repository\com\google\code\findbugs\jsr305\1.3.9\jsr305-1.3.9.jar;C:\Users\buddy\.m2\repository\com\google\errorprone\error_prone_annotations\2.0.2\error_prone_annotations-2.0.2.jar;C:\Users\buddy\.m2\repository\com\google\guava\guava\19.0\guava-19.0.jar;C:\Users\buddy\.m2\repository\net\openhft\zero-allocation-hashing\0.8\zero-allocation-hashing-0.8.jar;C:\Users\buddy\.m2\repository\com\samskivert\samskivert\1.9\samskivert-1.9.jar;C:\Users\buddy\.m2\repository\org\apache\commons\commons-lang3\3.10\commons-lang3-3.10.jar;C:\Users\buddy\.m2\repository\io\hawt\hawtio-embedded\2.7.1\hawtio-embedded-2.7.1.jar;C:\Users\buddy\.m2\repository\org\eclipse\jetty\jetty-webapp\9.4.6.v20170531\jetty-webapp-9.4.6.v20170531.jar;C:\Users\buddy\.m2\repository\org\eclipse\jetty\jetty-xml\9.4.6.v20170531\jetty-xml-9.4.6.v20170531.jar;C:\Users\buddy\.m2\repository\org\eclipse\jetty\jetty-util\9.4.6.v20170531\jetty-util-9.4.6.v20170531.jar;C:\Users\buddy\.m2\repository\org\eclipse\jetty\jetty-servlet\9.4.6.v20170531\jetty-servlet-9.4.6.v20170531.jar;C:\Users\buddy\.m2\repository\org\eclipse\jetty\jetty-security\9.4.6.v20170531\jetty-security-9.4.6.v20170531.jar;C:\Users\buddy\.m2\repository\org\eclipse\jetty\jetty-server\9.4.6.v20170531\jetty-server-9.4.6.v20170531.jar;C:\Users\buddy\.m2\repository\javax\servlet\javax.servlet-api\3.1.0\javax.servlet-api-3.1.0.jar;C:\Users\buddy\.m2\repository\org\eclipse\jetty\jetty-http\9.4.6.v20170531\jetty-http-9.4.6.v20170531.jar;C:\Users\buddy\.m2\repository\org\eclipse\jetty\jetty-io\9.4.6.v20170531\jetty-io-9.4.6.v20170531.jar;C:\Users\buddy\.m2\repository\org\skyscreamer\jsonassert\1.5.0\jsonassert-1.5.0.jar;C:\Users\buddy\.m2\repository\com\vaadin\external\google\android-json\0.0.20131108.vaadin1\android-json-0.0.20131108.vaadin1.jar;C:\Users\buddy\.m2\repository\net\openhft\stage-compiler\1.11\stage-compiler-1.11.jar;C:\Users\buddy\.m2\repository\net\openhft\spoon-core\4.4.1\spoon-core-4.4.1.jar;C:\Users\buddy\.m2\repository\org\eclipse\jdt\core\compiler\ecj\4.4.2\ecj-4.4.2.jar;C:\Users\buddy\.m2\repository\com\martiansoftware\jsap\2.1\jsap-2.1.jar;C:\Users\buddy\.m2\repository\log4j\log4j\1.2.17\log4j-1.2.17.jar;C:\Users\buddy\.m2\repository\commons-io\commons-io\1.3.2\commons-io-1.3.2.jar;C:\Users\buddy\.m2\repository\it\unimi\dsi\fastutil\7.0.6\fastutil-7.0.6.jar;C:\Users\buddy\.m2\repository\org\junit\jupiter\junit-jupiter\5.7.0-M1\junit-jupiter-5.7.0-M1.jar;C:\Users\buddy\.m2\repository\org\junit\jupiter\junit-jupiter-api\5.7.0-M1\junit-jupiter-api-5.7.0-M1.jar;C:\Users\buddy\.m2\repository\org\apiguardian\apiguardian-api\1.1.0\apiguardian-api-1.1.0.jar;C:\Users\buddy\.m2\repository\org\opentest4j\opentest4j\1.2.0\opentest4j-1.2.0.jar;C:\Users\buddy\.m2\repository\org\junit\platform\junit-platform-commons\1.7.0-M1\junit-platform-commons-1.7.0-M1.jar;C:\Users\buddy\.m2\repository\org\junit\jupiter\junit-jupiter-params\5.7.0-M1\junit-jupiter-params-5.7.0-M1.jar;C:\Users\buddy\.m2\repository\org\junit\jupiter\junit-jupiter-engine\5.7.0-M1\junit-jupiter-engine-5.7.0-M1.jar;C:\Users\buddy\.m2\repository\org\junit\platform\junit-platform-engine\1.7.0-M1\junit-platform-engine-1.7.0-M1.jar;C:\Java\jre\..\lib\tools.jar \ No newline at end of file diff --git a/cp2.txt b/cp2.txt new file mode 100644 index 000000000..b8b0ddf47 --- /dev/null +++ b/cp2.txt @@ -0,0 +1 @@ +/C//Users/buddy/.m2/repository/com/intellij/annotations/12.0/annotations-12.0.jar:/C//Users/buddy/.m2/repository/net/openhft/chronicle-core/2.19.72-SNAPSHOT/chronicle-core-2.19.72-SNAPSHOT.jar:/C//Users/buddy/.m2/repository/org/jetbrains/annotations/19.0.0/annotations-19.0.0.jar:/C//Users/buddy/.m2/repository/net/openhft/chronicle-values/2.19.42/chronicle-values-2.19.42.jar:/C//Users/buddy/.m2/repository/net/openhft/chronicle-bytes/2.19.72-SNAPSHOT/chronicle-bytes-2.19.72-SNAPSHOT.jar:/C//Users/buddy/.m2/repository/com/squareup/javapoet/1.12.1/javapoet-1.12.1.jar:/C//Users/buddy/.m2/repository/net/openhft/chronicle-threads/2.19.70/chronicle-threads-2.19.70.jar:/C//Users/buddy/.m2/repository/org/slf4j/slf4j-api/1.7.30/slf4j-api-1.7.30.jar:/C//Users/buddy/.m2/repository/net/openhft/chronicle-wire/2.19.74-SNAPSHOT/chronicle-wire-2.19.74-SNAPSHOT.jar:/C//Users/buddy/.m2/repository/net/openhft/compiler/2.3.6/compiler-2.3.6.jar:/C//Users/buddy/.m2/repository/net/openhft/chronicle-algorithms/2.19.42/chronicle-algorithms-2.19.42.jar:/C//Users/buddy/.m2/repository/net/java/dev/jna/jna/5.5.0/jna-5.5.0.jar:/C//Users/buddy/.m2/repository/net/java/dev/jna/jna-platform/5.5.0/jna-platform-5.5.0.jar:/C//Users/buddy/.m2/repository/com/thoughtworks/xstream/xstream/1.4.12/xstream-1.4.12.jar:/C//Users/buddy/.m2/repository/xmlpull/xmlpull/1.1.3.1/xmlpull-1.1.3.1.jar:/C//Users/buddy/.m2/repository/xpp3/xpp3_min/1.1.4c/xpp3_min-1.1.4c.jar:/C//Users/buddy/.m2/repository/org/codehaus/jettison/jettison/1.4.1/jettison-1.4.1.jar:/C//Users/buddy/.m2/repository/org/ops4j/pax/url/pax-url-aether/2.6.2/pax-url-aether-2.6.2.jar:/C//Users/buddy/.m2/repository/org/ops4j/pax/url/pax-url-aether-support/2.6.2/pax-url-aether-support-2.6.2.jar:/C//Users/buddy/.m2/repository/org/apache/maven/resolver/maven-resolver-impl/1.3.1/maven-resolver-impl-1.3.1.jar:/C//Users/buddy/.m2/repository/org/apache/maven/resolver/maven-resolver-api/1.3.1/maven-resolver-api-1.3.1.jar:/C//Users/buddy/.m2/repository/org/apache/maven/resolver/maven-resolver-spi/1.3.1/maven-resolver-spi-1.3.1.jar:/C//Users/buddy/.m2/repository/org/apache/maven/resolver/maven-resolver-util/1.3.1/maven-resolver-util-1.3.1.jar:/C//Users/buddy/.m2/repository/org/slf4j/jcl-over-slf4j/1.6.6/jcl-over-slf4j-1.6.6.jar:/C//Users/buddy/.m2/repository/net/openhft/jlbh/1.19.30/jlbh-1.19.30.jar:/C//Users/buddy/.m2/repository/junit/junit/4.13/junit-4.13.jar:/C//Users/buddy/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar:/C//Users/buddy/.m2/repository/org/slf4j/slf4j-simple/1.7.30/slf4j-simple-1.7.30.jar:/C//Users/buddy/.m2/repository/org/mockito/mockito-core/3.3.3/mockito-core-3.3.3.jar:/C//Users/buddy/.m2/repository/net/bytebuddy/byte-buddy/1.10.5/byte-buddy-1.10.5.jar:/C//Users/buddy/.m2/repository/net/bytebuddy/byte-buddy-agent/1.10.5/byte-buddy-agent-1.10.5.jar:/C//Users/buddy/.m2/repository/org/objenesis/objenesis/2.6/objenesis-2.6.jar:/C//Users/buddy/.m2/repository/org/powermock/powermock-module-junit4/2.0.7/powermock-module-junit4-2.0.7.jar:/C//Users/buddy/.m2/repository/org/powermock/powermock-module-junit4-common/2.0.7/powermock-module-junit4-common-2.0.7.jar:/C//Users/buddy/.m2/repository/org/powermock/powermock-reflect/2.0.7/powermock-reflect-2.0.7.jar:/C//Users/buddy/.m2/repository/org/powermock/powermock-core/2.0.7/powermock-core-2.0.7.jar:/C//Users/buddy/.m2/repository/org/javassist/javassist/3.27.0-GA/javassist-3.27.0-GA.jar:/C//Users/buddy/.m2/repository/org/powermock/powermock-api-mockito/1.7.4/powermock-api-mockito-1.7.4.jar:/C//Users/buddy/.m2/repository/org/powermock/powermock-api-mockito-common/1.7.4/powermock-api-mockito-common-1.7.4.jar:/C//Users/buddy/.m2/repository/org/powermock/powermock-api-support/1.7.4/powermock-api-support-1.7.4.jar:/C//Users/buddy/.m2/repository/net/openhft/affinity/3.2.4-SNAPSHOT/affinity-3.2.4-SNAPSHOT.jar:/C//Users/buddy/.m2/repository/com/google/guava/guava-testlib/19.0/guava-testlib-19.0.jar:/C//Users/buddy/.m2/repository/com/google/code/findbugs/jsr305/1.3.9/jsr305-1.3.9.jar:/C//Users/buddy/.m2/repository/com/google/errorprone/error_prone_annotations/2.0.2/error_prone_annotations-2.0.2.jar:/C//Users/buddy/.m2/repository/com/google/guava/guava/19.0/guava-19.0.jar:/C//Users/buddy/.m2/repository/net/openhft/zero-allocation-hashing/0.8/zero-allocation-hashing-0.8.jar:/C//Users/buddy/.m2/repository/com/samskivert/samskivert/1.9/samskivert-1.9.jar:/C//Users/buddy/.m2/repository/org/apache/commons/commons-lang3/3.10/commons-lang3-3.10.jar:/C//Users/buddy/.m2/repository/io/hawt/hawtio-embedded/2.7.1/hawtio-embedded-2.7.1.jar:/C//Users/buddy/.m2/repository/org/eclipse/jetty/jetty-webapp/9.4.6.v20170531/jetty-webapp-9.4.6.v20170531.jar:/C//Users/buddy/.m2/repository/org/eclipse/jetty/jetty-xml/9.4.6.v20170531/jetty-xml-9.4.6.v20170531.jar:/C//Users/buddy/.m2/repository/org/eclipse/jetty/jetty-util/9.4.6.v20170531/jetty-util-9.4.6.v20170531.jar:/C//Users/buddy/.m2/repository/org/eclipse/jetty/jetty-servlet/9.4.6.v20170531/jetty-servlet-9.4.6.v20170531.jar:/C//Users/buddy/.m2/repository/org/eclipse/jetty/jetty-security/9.4.6.v20170531/jetty-security-9.4.6.v20170531.jar:/C//Users/buddy/.m2/repository/org/eclipse/jetty/jetty-server/9.4.6.v20170531/jetty-server-9.4.6.v20170531.jar:/C//Users/buddy/.m2/repository/javax/servlet/javax.servlet-api/3.1.0/javax.servlet-api-3.1.0.jar:/C//Users/buddy/.m2/repository/org/eclipse/jetty/jetty-http/9.4.6.v20170531/jetty-http-9.4.6.v20170531.jar:/C//Users/buddy/.m2/repository/org/eclipse/jetty/jetty-io/9.4.6.v20170531/jetty-io-9.4.6.v20170531.jar:/C//Users/buddy/.m2/repository/org/skyscreamer/jsonassert/1.5.0/jsonassert-1.5.0.jar:/C//Users/buddy/.m2/repository/com/vaadin/external/google/android-json/0.0.20131108.vaadin1/android-json-0.0.20131108.vaadin1.jar:/C//Users/buddy/.m2/repository/net/openhft/stage-compiler/1.11/stage-compiler-1.11.jar:/C//Users/buddy/.m2/repository/net/openhft/spoon-core/4.4.1/spoon-core-4.4.1.jar:/C//Users/buddy/.m2/repository/org/eclipse/jdt/core/compiler/ecj/4.4.2/ecj-4.4.2.jar:/C//Users/buddy/.m2/repository/com/martiansoftware/jsap/2.1/jsap-2.1.jar:/C//Users/buddy/.m2/repository/log4j/log4j/1.2.17/log4j-1.2.17.jar:/C//Users/buddy/.m2/repository/commons-io/commons-io/1.3.2/commons-io-1.3.2.jar:/C//Users/buddy/.m2/repository/it/unimi/dsi/fastutil/7.0.6/fastutil-7.0.6.jar:/C//Users/buddy/.m2/repository/org/junit/jupiter/junit-jupiter/5.7.0-M1/junit-jupiter-5.7.0-M1.jar:/C//Users/buddy/.m2/repository/org/junit/jupiter/junit-jupiter-api/5.7.0-M1/junit-jupiter-api-5.7.0-M1.jar:/C//Users/buddy/.m2/repository/org/apiguardian/apiguardian-api/1.1.0/apiguardian-api-1.1.0.jar:/C//Users/buddy/.m2/repository/org/opentest4j/opentest4j/1.2.0/opentest4j-1.2.0.jar:/C//Users/buddy/.m2/repository/org/junit/platform/junit-platform-commons/1.7.0-M1/junit-platform-commons-1.7.0-M1.jar:/C//Users/buddy/.m2/repository/org/junit/jupiter/junit-jupiter-params/5.7.0-M1/junit-jupiter-params-5.7.0-M1.jar:/C//Users/buddy/.m2/repository/org/junit/jupiter/junit-jupiter-engine/5.7.0-M1/junit-jupiter-engine-5.7.0-M1.jar:/C//Users/buddy/.m2/repository/org/junit/platform/junit-platform-engine/1.7.0-M1/junit-platform-engine-1.7.0-M1.jar:/C//Java/jre/../lib/tools.jar \ No newline at end of file diff --git a/dr.csv b/dr.csv new file mode 100644 index 000000000..5c45fe3d7 --- /dev/null +++ b/dr.csv @@ -0,0 +1,17 @@ +DirtyReadOffender,chrAig[DIRTY_READ_OPTIMISTIC]coupon=3.50,DirtyReadVictim +,Established chm, + ,,@t=1593597010401 DirtyReadVictim CALLING offHeapLock.tryOptimisticRead() + ,,@t=1593597010402 DirtyReadVictim CALLED offHeapLock.tryOptimisticRead() + ,,@t=1593597010803 DirtyReadVictim calling chm.get('369604101').getCoupon() + ,,@t=1593597010805 DirtyReadVictim coupon=[4.096316014939393] read. + ,,@t=1593597010805 DirtyReadVictim sleeping 60 seconds + @t=1593597010821 DirtyReadOffender sleeping 10 seconds + @t=1593597020822 DirtyReadOffender awakening + @t=1593597020822 DirtyReadOffender ACQUIRING offHeapLock.writeLock(); + @t=1593597020822 DirtyReadOffender ACQUIRED offHeapLock.writeLock(); + @t=1593597020823 DirtyReadOffender calling chm.put('369604101',3.5085267913490994) + @t=1593597020827 DirtyReadOffender coupon=[3.5085267913490994] written. + @t=1593597020828 DirtyReadOffender called offHeapLock.unlockWrite(stamp); + ,,@t=1593597070806 DirtyReadVictim FAILED offHeapLock.validate(stamp) must apply PESSIMISTIC_POLICY (dirty read endured) coupon=[4.096316014939393] is *DIRTY*. + ,,@t=1593597070806 DirtyReadVictim got() coupon=4.096316014939393 + ,,@t=1593597070806 DirtyReadVictim COMMITTED diff --git a/intolerant.csv b/intolerant.csv new file mode 100644 index 000000000..0403e927e --- /dev/null +++ b/intolerant.csv @@ -0,0 +1,23 @@ +DirtyReadOffender,chrAig[DIRTY_READ_INTOLERANT]coupon=3.50,DirtyReadVictim +,Established chrAig, + ,,@t=1588854013435 DirtyReadVictim sleeping 10 seconds + @t=1588854013450 DirtyReadOffender calling chrAig.put('369604101'/3.85) ,, + , @t=1588854013450 Tx=Thread[Thread-4.5.main] inside chrAig.put('369604101'/null) BEGIN, + , @t=1588854013450 Tx=Thread[Thread-4.5.main] inside chrAig.put('369604101'/3.85) DONE, + @t=1588854013450 DirtyReadOffender sleeping 1 minute. ,, + ,,@t=1588854023448 DirtyReadVictim calling chrAig.get('369604101') + , @t=1588854023448 Tx=Thread[Thread-5.5.main] inside chrAig.get('369604101') BEGIN, +, @t=1588854023448 Tx=Thread[Thread-5.5.main] inside chrAig.get() WAITING , + @t=1588854073452 DirtyReadOffender calling chrAig.rollback() ,, + , @t=1588854073452 Tx=Thread[Thread-4.5.main] chrAig.rollback() BEGIN , + ,@t=1588854073452 Tx=Thread[Thread-4.5.main] chrAig.rollback() COMPLETE coupon=3.50, +, @t=1588854073452 Tx=Thread[Thread-4.5.main] chrAig.rollback() completed notifyAll() to waiting Tx Threads, + , @t=1588854073452 Tx=Thread[Thread-5.5.main] inside chrAig.get() RESUMING, + , @t=1588854073452 Tx=Thread[Thread-5.5.main] inside chrAig.get() DONE , + ,,@t=1588854073452 DirtyReadVictim got() coupon=3.5 + @t=1588854073452 DirtyReadOffender ROLLED BACK ,, + ,,@t=1588854073452 DirtyReadVictim calling chrAig.commmit() + ,@t=1588854073452 Tx=Thread[Thread-5.5.main] chrAig.commit() BEGIN , + , @t=1588854073452 Tx=Thread[Thread-5.5.main] chrAig.commit() END , +, @t=1588854073452 Tx=Thread[Thread-5.5.main] chrAig.commit() complete notifyAll() to waiting Tx Threads , + ,,@t=1588854073452 DirtyReadVictim COMMITTED diff --git a/optimistic.csv b/optimistic.csv new file mode 100644 index 000000000..1374a93f1 --- /dev/null +++ b/optimistic.csv @@ -0,0 +1,16 @@ +DirtyReadOffender,chrAig[DIRTY_READ_OPTIMISTIC]coupon=3.50,DirtyReadVictim +,Established chrAig, + ,,@t=1593467845991 DirtyReadVictim sleeping 10 seconds + @t=1593467846072 DirtyReadOffender calling chrAig.put('369604101'/3.85) + , @t=1593467846079 Tx=Thread[Thread-2.5.main] inside chrAig.put('369604101'/null) BEGIN, + , @t=1593467846083 Tx=Thread[Thread-2.5.main] inside chrAig.put('369604101'/3.85) DONE, + @t=1593467846083 DirtyReadOffender sleeping 1 minute. + ,,@t=1593467856000 DirtyReadVictim calling chrAig.get('369604101') + , @t=1593467856002 Tx=Thread[Thread-3.5.main] inside chrAig.get('369604101') BEGIN, + , @t=1593467856036 Tx=Thread[Thread-3.5.main] inside chrAig.get() DONE , + ,,@t=1593467856036 DirtyReadVictim OPTIMISTICALLY_READ coupon=3.85 + ,,@t=1593467856036 DirtyReadVictim calling chrAig.rollback() + , @t=1593467856036 Tx=Thread[Thread-3.5.main] chrAig.rollback() BEGIN , + ,@t=1593467856037 Tx=Thread[Thread-3.5.main] chrAig.rollback() COMPLETE coupon=3.50, +, @t=1593467856037 Tx=Thread[Thread-3.5.main] chrAig.rollback() completed notifyAll() to waiting Tx Threads, + ,,@t=1593467856037 DirtyReadVictim ROLLED BACK diff --git a/pom.xml b/pom.xml index a0d6c6685..e49cc518f 100755 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,7 @@ + 4.0.0 @@ -11,6 +12,7 @@ chronicle-map + 3.19.43-SNAPSHOT OpenHFT/Chronicle-Map Chronicle-Map @@ -225,6 +227,24 @@ 1.11 provided + + org.junit.jupiter + junit-jupiter + RELEASE + test + + + org.junit.jupiter + junit-jupiter + RELEASE + test + + + org.junit.jupiter + junit-jupiter + RELEASE + test + diff --git a/pwd b/pwd new file mode 100644 index 000000000..e69de29bb diff --git a/src/test/java/net/openhft/chronicle/map/CHMTest5.java b/src/test/java/net/openhft/chronicle/map/CHMTest5.java deleted file mode 100644 index 69514a96c..000000000 --- a/src/test/java/net/openhft/chronicle/map/CHMTest5.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright 2012-2018 Chronicle Map Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.openhft.chronicle.map; - -import net.openhft.chronicle.algo.locks.AcquisitionStrategies; -import net.openhft.chronicle.algo.locks.ReadWriteLockingStrategy; -import net.openhft.chronicle.algo.locks.TryAcquireOperations; -import net.openhft.chronicle.algo.locks.VanillaReadWriteWithWaitsLockingStrategy; -import net.openhft.chronicle.bytes.Byteable; -import net.openhft.chronicle.map.utility.ProcessInstanceLimiter; -import net.openhft.chronicle.values.Array; -import net.openhft.chronicle.values.Group; -import net.openhft.chronicle.values.Values; - -import java.io.File; -import java.io.IOException; -import java.util.concurrent.TimeUnit; - -import static net.openhft.chronicle.algo.bytes.Access.checkedBytesStoreAccess; -import static org.junit.Assert.assertEquals; - -/** - * @author jack shirazi - */ -public class CHMTest5 { - public static final String TEST_KEY = "whatever"; - public static int NUMBER_OF_PROCESSES_ALLOWED = 2; - - public static void main(String[] args) throws IOException { - //First create (or access if already created) the shared map - ChronicleMapBuilder builder = - ChronicleMapBuilder.of(String.class, CHMTest5Data.class) - .entries(1000); - - //// don't include this, just to check it is as expected. - assertEquals(8, builder.minSegments()); - //// end of test - - String chmPath = System.getProperty("java.io.tmpdir") + System.getProperty("file.separator") + "CHMTest5"; - - ChronicleMap theSharedMap = - builder.createPersistedTo(new File(chmPath)); - - //Now get the shared data object, auto-creating if it's not there - CHMTest5Data data = Values.newNativeReference(CHMTest5Data.class); - theSharedMap.acquireUsing(TEST_KEY, data); - //if this was newly created, we need to set the max allowed - //Note, the object is pointing at shared memory and writes - //directly to it, so no need to put() it back into the map - if (data.getMaxNumberOfProcessesAllowed() != NUMBER_OF_PROCESSES_ALLOWED) { - //it's either a new object, set to 0, or - //another process set it to an invalid value - if (data.compareAndSwapMaxNumberOfProcessesAllowed(0, NUMBER_OF_PROCESSES_ALLOWED)) { - //What we expected, everything's good - } else { - //something else set a value, if it's not 2 we've got a conflict - if (data.getMaxNumberOfProcessesAllowed() != NUMBER_OF_PROCESSES_ALLOWED) { - System.out.println("Incorrect configuration found, expected " + - NUMBER_OF_PROCESSES_ALLOWED + " slots, instead found " + - data.getMaxNumberOfProcessesAllowed() + " - exiting"); - System.exit(0); - } - } - } - - //Now, we look for an empty slot in the "time" array. - //Because this initial implementation of the data object - //is directly accessing the shared memory, we just operate - //on it as a shared object - - // There would be no need to lock the MaxNumberOfProcessesAllowed field - // as we used CAS to update and it's read-only after that - // but we need to lock access to the Time array - long[] times1 = new long[NUMBER_OF_PROCESSES_ALLOWED]; - getTimes(data, times1); - pause(300L); - long[] times2 = new long[NUMBER_OF_PROCESSES_ALLOWED]; - getTimes(data, times2); - //look for a slot that hasn't changed in that 300ms pause - int slotindex = 0; - long lastUpdateTime = -1; - for (; slotindex < times1.length; slotindex++) { - if (times2[slotindex] == times1[slotindex]) { - //we have an index which has not been updated by anything else - //in the 300ms pause, so we have a spare slot - we use this slot - long timenow = System.currentTimeMillis(); - tryLock1Sec(data); - try { - data.setTimeAt(slotindex, timenow); - } finally { - //and release the lock - releaseLock(data); - } - - //Now we have successfully acquired a slot - lastUpdateTime = timenow; - System.out.println("We have started on slot " + slotindex); - break; - } - } - - if (lastUpdateTime == -1) { - System.out.println("We failed to find a free slot, so terminating now"); - System.exit(0); - } - - //Now let's run for 60 seconds, updating the slot every 100ms - for (int count = 0; count < 600; count++) { - pause(100L); - long timenow = System.currentTimeMillis(); - tryLock1Sec(data); - try { - if (lastUpdateTime == data.getTimeAt(slotindex)) { - //That's what we expect so just update the slot - data.setTimeAt(slotindex, timenow); - lastUpdateTime = timenow; - } else { - //Some other process has hijacked our slot - so - //the only thing we can do is terminate - System.out.println("Another process has hijacked our slot " + slotindex + ", so terminating now"); - System.exit(0); - } - } finally { - releaseLock(data); - } - } - System.out.println("Exiting slot " + slotindex + " after completing the full test."); - } - - private static void releaseLock(CHMTest5Data data) { - //and release the lock - try { - data.unlockEntry(); - } catch (IllegalMonitorStateException e) { - //odd, but we'll be unlocked either way - System.out.println("Unexpected state: " + e); - e.printStackTrace(); - } - } - - private static void tryLock1Sec(CHMTest5Data data) { - boolean locked = false; - for (int i = 0; i < 1000000; i++) { - //try up to 1 second - if (data.tryLockNanosEntry(1000L)) { - locked = true; - break; - } - } - if (!locked) { - System.out.println("Unable to acquire a lock on the time array - exiting"); - System.exit(0); - } - } - - private static void getTimes(CHMTest5Data data, long[] times1) { - tryLock1Sec(data); - try { - //we've got the lock, now copy the array - for (int i = 0; i < times1.length; i++) { - times1[i] = data.getTimeAt(i); - } - } finally { - //and release the lock - releaseLock(data); - } - } - - public static void pause(long pause) { - ProcessInstanceLimiter.pause(pause); - } - - public interface CHMTest5Data { - - @Group(0) - long getEntryLockState(); - - void setEntryLockState(long entryLockState); - - @Group(1) - int getMaxNumberOfProcessesAllowed(); - - void setMaxNumberOfProcessesAllowed(int max); - - boolean compareAndSwapMaxNumberOfProcessesAllowed(int expected, int value); - - @Group(1) - @Array(length = 4) - void setTimeAt(int index, long time); - - long getTimeAt(int index); - - @Deprecated() - default boolean tryLockNanosEntry(long nanos) { - return AcquisitionStrategies - .spinLoop(nanos, TimeUnit.NANOSECONDS).acquire( - TryAcquireOperations.writeLock(), - VanillaReadWriteWithWaitsLockingStrategy.instance(), - checkedBytesStoreAccess(), ((Byteable) this).bytesStore(), - ((Byteable) this).offset()); - } - - @Deprecated() - default void unlockEntry() throws IllegalMonitorStateException { - VanillaReadWriteWithWaitsLockingStrategy.instance() - .writeUnlock(checkedBytesStoreAccess(), - ((Byteable) this).bytesStore(), ((Byteable) this).offset()); - } - } -} \ No newline at end of file diff --git a/src/test/java/net/openhft/chronicle/map/ExitHookTest.java b/src/test/java/net/openhft/chronicle/map/ExitHookTest.java index 8480d5682..72eec6530 100644 --- a/src/test/java/net/openhft/chronicle/map/ExitHookTest.java +++ b/src/test/java/net/openhft/chronicle/map/ExitHookTest.java @@ -18,6 +18,7 @@ package net.openhft.chronicle.map; import com.google.common.base.Preconditions; import net.openhft.chronicle.core.Jvm; + import net.openhft.chronicle.core.OS; import org.junit.Rule; import org.junit.Test; @@ -35,7 +36,8 @@ import static org.junit.Assert.*; public class ExitHookTest { private static final int KEY = 1; - private static final int JVM_STARTUP_WAIT_TIME_MS = 2_000; + private static final int JVM_STARTUP_WAIT_TIME_MS = 5_000; + private static final String PRE_SHUTDOWN_ACTION_EXECUTED = "PRE_SHUTDOWN_ACTION_EXECUTED"; private static final String USER_SHUTDOWN_HOOK_EXECUTED = "USER_SHUTDOWN_HOOK_EXECUTED"; @@ -92,7 +94,7 @@ public class ExitHookTest { mapReference.set(mapBuilder.createPersistedTo(mapFile)); try (ExternalMapQueryContext c = mapReference.get().queryContext(KEY)) { c.writeLock().lock(); - Thread.sleep(8_000); + Thread.sleep(30_000); } } diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/acid/ChronicleAcidIsolation.java b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/ChronicleAcidIsolation.java new file mode 100644 index 000000000..cc827a738 --- /dev/null +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/ChronicleAcidIsolation.java @@ -0,0 +1,13 @@ +package net.openhft.chronicle.map.fromdocs.acid; + + +public interface ChronicleAcidIsolation extends java.sql.Connection{ + + int LOWEST_LATENCY = ChronicleAcidIsolation.TRANSACTION_NONE; + int DIRTY_READ_OPTIMISTIC = ChronicleAcidIsolation.TRANSACTION_READ_UNCOMMITTED; + int DIRTY_READ_INTOLERANT = ChronicleAcidIsolation.TRANSACTION_READ_COMMITTED; + int REPEATABLE_READS_MANDATORY = ChronicleAcidIsolation.TRANSACTION_REPEATABLE_READ; + int PHANTOM_READ_INTOLERANT = ChronicleAcidIsolation.TRANSACTION_SERIALIZABLE; + +} + diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/acid/ChronicleAcidIsolationGovernor.java b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/ChronicleAcidIsolationGovernor.java new file mode 100644 index 000000000..e5b52ccbe --- /dev/null +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/ChronicleAcidIsolationGovernor.java @@ -0,0 +1,436 @@ +package net.openhft.chronicle.map.fromdocs.acid; + +//import net.openhft.affinity.AffinitySupport; + +import net.openhft.chronicle.map.ChronicleMap; +import net.openhft.chronicle.map.fromdocs.BondVOInterface; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +public class ChronicleAcidIsolationGovernor implements ChronicleAcidIsolation { + + private ChronicleMap transactionIsolationMap; + private ChronicleMap compositeChronicleMap; //hacked in, not generic + private String priorCusip; + private Double aCoupon; + + + public synchronized void put(String cusip, BondVOInterface bond) throws Exception { + + System.out.println( + " , @t="+System.currentTimeMillis()+ + " Tx="+Thread.currentThread().toString().replaceAll(",",".")+ + " inside chrAig.put('"+cusip+"'/"+aCoupon+") BEGIN"+ + ", " + ); + ChronicleMap cMap = this.getCompositeChronicleMap(); + this.aCoupon = cMap.get(cusip).getCoupon(); + + bond.setCoupon(aCoupon); + cMap.put(cusip, bond); + System.out.println( + " , @t="+System.currentTimeMillis()+ + " Tx="+Thread.currentThread().toString().replaceAll(",",".")+ + " inside chrAig.put('"+cusip+"'/"+aCoupon+") DONE"+ + ", " + ); + } + + + //here is where the drama happens + public synchronized BondVOInterface get(String cusip) throws Exception { + System.out.println( + " , @t="+System.currentTimeMillis()+ + " Tx="+Thread.currentThread().toString().replaceAll(",",".")+ + " inside chrAig.get('"+cusip+"') BEGIN"+ + ", " + ); + BondVOInterface b = null; + String tx = Thread.currentThread().toString(); + ChronicleMap txMap = this.getTransactionIsolationMap(); + if (txMap.size() > 1) { //other ACID transactions are active + if (txMap.get(tx) <= ChronicleAcidIsolation.DIRTY_READ_OPTIMISTIC) { + b = this.compositeChronicleMap.get(cusip); + } else if (txMap.get(tx) >= ChronicleAcidIsolation.DIRTY_READ_INTOLERANT) { + System.out.println( + ", @t="+System.currentTimeMillis()+ + " Tx="+Thread.currentThread().toString().replaceAll(",",".")+ + " inside chrAig.get() WAITING"+ + " ," + ); + this.wait(); + System.out.println( + " , @t="+System.currentTimeMillis()+ + " Tx="+Thread.currentThread().toString().replaceAll(",",".")+ + " inside chrAig.get() RESUMING"+ + ", " + ); + b = this.compositeChronicleMap.get(cusip); + } + } else { + b = this.compositeChronicleMap.get(cusip); + } + System.out.println( + " , @t="+System.currentTimeMillis()+ + " Tx="+Thread.currentThread().toString().replaceAll(",",".")+ + " inside chrAig.get() DONE"+ + " ," + ); + return b; + } + + public ChronicleMap getTransactionIsolationMap() { + + return transactionIsolationMap; + } + + public void setTransactionIsolationMap(ChronicleMap txMap) { + this.transactionIsolationMap = txMap; + } + + public ChronicleMap getCompositeChronicleMap() { + + return compositeChronicleMap; + } + + public void setCompositeChronicleMap(ChronicleMap ccm) { + + this.compositeChronicleMap = ccm; + } + + @Override + public synchronized void setTransactionIsolation(int level) throws SQLException { + + this.getTransactionIsolationMap().put( + Thread.currentThread().toString(), + level + ); + } + + @Override + public synchronized int getTransactionIsolation() throws SQLException { + + int iL = this.getTransactionIsolationMap().get(Thread.currentThread()); + return(iL); + } + + @Override + public synchronized void commit() throws SQLException { + System.out.println( + " ,@t="+System.currentTimeMillis()+ + " Tx="+Thread.currentThread().toString().replaceAll(",",".")+ + " chrAig.commit() BEGIN "+ + ", " + ); + this.getTransactionIsolationMap().remove(Thread.currentThread().toString()); + System.out.println( + " , @t="+System.currentTimeMillis()+ + " Tx="+Thread.currentThread().toString().replaceAll(",",".")+ + " chrAig.commit() END "+ + ", " + ); + this.notifyAll(); + System.out.println( + ", @t="+System.currentTimeMillis()+ + " Tx="+Thread.currentThread().toString().replaceAll(",",".")+ + " chrAig.commit() complete notifyAll() to waiting Tx Threads "+ + "," + ); + + } + + @Override + public synchronized void rollback() throws SQLException { + BondVOInterface priorBond = this.getCompositeChronicleMap().get("369604101"); + if (priorBond != null) { + priorBond.setCoupon(3.50); + this.getCompositeChronicleMap().put("369604101", priorBond); + } + System.out.println( + " , @t="+System.currentTimeMillis()+ + " Tx="+Thread.currentThread().toString().replaceAll(",",".")+ + " chrAig.rollback() BEGIN "+ + ", " + ); + this.getTransactionIsolationMap().remove(Thread.currentThread().toString()); + System.out.println( + " ,@t="+System.currentTimeMillis()+ + " Tx="+Thread.currentThread().toString().replaceAll(",",".")+ + " chrAig.rollback() COMPLETE coupon=3.50"+ + ", " + ); + this.notifyAll(); + System.out.println( + ", @t="+System.currentTimeMillis()+ + " Tx="+Thread.currentThread().toString().replaceAll(",",".")+ + " chrAig.rollback() completed notifyAll() to waiting Tx Threads"+ + ", " + ); + } + // rest of these java.sql.Connection methods remain unimplemented ... + // pedantics are too + // intense. In the real world, even in Captital Markets 'dirty read' intolerance + // is likely the only isolation level Chronicle would accommodate. + + + @Override + public void setAutoCommit(boolean autoCommit) throws SQLException { + + } + + @Override + public boolean getAutoCommit() throws SQLException { + return false; + } + + + @Override + public void rollback(Savepoint savepoint) throws SQLException { + + } + + @Override + public void close() throws SQLException { + + } + + + + @Override + public Statement createStatement() throws SQLException { + return null; + } + + @Override + public PreparedStatement prepareStatement(String sql) throws SQLException { + return null; + } + + @Override + public CallableStatement prepareCall(String sql) throws SQLException { + return null; + } + + @Override + public String nativeSQL(String sql) throws SQLException { + return null; + } + + + @Override + public boolean isClosed() throws SQLException { + return false; + } + + @Override + public DatabaseMetaData getMetaData() throws SQLException { + return null; + } + + @Override + public void setReadOnly(boolean readOnly) throws SQLException { + + } + + @Override + public boolean isReadOnly() throws SQLException { + return false; + } + + @Override + public void setCatalog(String catalog) throws SQLException { + + } + + @Override + public String getCatalog() throws SQLException { + return null; + } + + + @Override + public SQLWarning getWarnings() throws SQLException { + return null; + } + + @Override + public void clearWarnings() throws SQLException { + + } + + @Override + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return null; + } + + @Override + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + return null; + } + + @Override + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + return null; + } + + @Override + public Map> getTypeMap() throws SQLException { + return null; + } + + @Override + public void setTypeMap(Map> map) throws SQLException { + + } + + @Override + public void setHoldability(int holdability) throws SQLException { + + } + + @Override + public int getHoldability() throws SQLException { + return 0; + } + + @Override + public Savepoint setSavepoint() throws SQLException { + return null; + } + + @Override + public Savepoint setSavepoint(String name) throws SQLException { + return null; + } + + + @Override + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + + } + + @Override + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return null; + } + + @Override + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return null; + } + + @Override + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return null; + } + + @Override + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + return null; + } + + @Override + public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { + return null; + } + + @Override + public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { + return null; + } + + @Override + public Clob createClob() throws SQLException { + return null; + } + + @Override + public Blob createBlob() throws SQLException { + return null; + } + + @Override + public NClob createNClob() throws SQLException { + return null; + } + + @Override + public SQLXML createSQLXML() throws SQLException { + return null; + } + + @Override + public boolean isValid(int timeout) throws SQLException { + return false; + } + + @Override + public void setClientInfo(String name, String value) throws SQLClientInfoException { + + } + + @Override + public void setClientInfo(Properties properties) throws SQLClientInfoException { + + } + + @Override + public String getClientInfo(String name) throws SQLException { + return null; + } + + @Override + public Properties getClientInfo() throws SQLException { + return null; + } + + @Override + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return null; + } + + @Override + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return null; + } + + @Override + public void setSchema(String schema) throws SQLException { + + } + + @Override + public String getSchema() throws SQLException { + return null; + } + + @Override + public void abort(Executor executor) throws SQLException { + + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + + } + + @Override + public int getNetworkTimeout() throws SQLException { + return 0; + } + + @Override + public T unwrap(Class iface) throws SQLException { + return null; + } + + @Override + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } + + +} diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/acid/ChronicleStampedLock.pptx b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/ChronicleStampedLock.pptx new file mode 100644 index 000000000..c2059c97d Binary files /dev/null and b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/ChronicleStampedLock.pptx differ diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/acid/ChronicleStampedLock=WANTED.png b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/ChronicleStampedLock=WANTED.png new file mode 100644 index 000000000..bf163925d Binary files /dev/null and b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/ChronicleStampedLock=WANTED.png differ diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/acid/ReadMe.adoc b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/ReadMe.adoc new file mode 100644 index 000000000..07b43e7fb --- /dev/null +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/ReadMe.adoc @@ -0,0 +1 @@ +image::ChronicleStampedLock=WANTED.png[] \ No newline at end of file diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/acid/exodus/DirtyReadOffender.java b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/exodus/DirtyReadOffender.java new file mode 100644 index 000000000..0920ebe35 --- /dev/null +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/exodus/DirtyReadOffender.java @@ -0,0 +1,105 @@ +package net.openhft.chronicle.map.fromdocs.acid.exodus; + + +import net.openhft.chronicle.map.ChronicleMap; +import net.openhft.chronicle.map.fromdocs.BondVOInterface; + +import java.util.Scanner; +import java.util.concurrent.locks.StampedLock; + +import static net.openhft.chronicle.values.Values.newNativeReference; + +public class DirtyReadOffender implements Runnable { + private int isoLevel; + private ChronicleMap chm; + private StampedLock offHeapLock; + + @Override + public void run() { + Scanner sc = new Scanner(System.in); + + try { + BondVOInterface bond = newNativeReference(BondVOInterface.class); + this.chm.acquireUsing("369604101", bond); + System.out.println( + " @t=" + System.currentTimeMillis() + + " DirtyReadOffender sleeping 10 seconds " + ); + Thread.sleep(10 * 1_000); + System.out.println( + " @t=" + System.currentTimeMillis() + + " DirtyReadOffender awakening " + ); + /** + * ben.cotton@rutgers.edu ... anticipate Chronicle (www.OpenHFT.net) + * providing a j.u.c.l.StampedLock API for off-heap enthusiasts + * + * START + * + */ + + long stamp = 0; + System.out.println( + " @t=" + System.currentTimeMillis() + + " DirtyReadOffender ACQUIRING offHeapLock.writeLock();" + ); + while ((stamp = this.offHeapLock.writeLock()) == 0) { + ; + } + System.out.println( + " @t=" + System.currentTimeMillis() + + " DirtyReadOffender ACQUIRED offHeapLock.writeLock();" + ); + try { + double newCoupon = 3.5 + Math.random(); + System.out.println( + " @t=" + System.currentTimeMillis() + + " DirtyReadOffender "+ + " calling chm.put('369604101',"+newCoupon+") " + ); + bond.setCoupon(newCoupon); + chm.put("369604101", bond); + System.out.println( + " @t=" + System.currentTimeMillis() + + " DirtyReadOffender coupon=["+ + bond.getCoupon()+ + "] written. " + ); + } finally { + this.offHeapLock.unlockWrite(stamp); + System.out.println( + " @t=" + System.currentTimeMillis() + + " DirtyReadOffender called offHeapLock.unlockWrite(stamp);" + ); + } + /** + * ben.cotton@rutgers.edu + * + * END + * + */ + } catch (Exception throwables) { + throwables.printStackTrace(); + } + } + + public ChronicleMap getCraig() { + return this.chm; + } + + public void setCraig(ChronicleMap craig) { + this.chm = craig; + } + + public int getIsoLevel() { + return isoLevel; + } + + public void setIsoLevel(int isoLevel) { + this.isoLevel = isoLevel; + } + + public void setStampedLock(StampedLock _sLock) { + this.offHeapLock = _sLock; + } +} diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/acid/exodus/DirtyReadTolerance.java b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/exodus/DirtyReadTolerance.java new file mode 100644 index 000000000..6b5a77e2b --- /dev/null +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/exodus/DirtyReadTolerance.java @@ -0,0 +1,52 @@ +package net.openhft.chronicle.map.fromdocs.acid.exodus; + +import net.openhft.affinity.AffinitySupport; +import net.openhft.chronicle.map.ChronicleMap; +import net.openhft.chronicle.map.ChronicleMapBuilder; +import net.openhft.chronicle.map.fromdocs.BondVOInterface; + +import java.io.File; +import java.io.IOException; +import java.util.concurrent.locks.StampedLock; + + +public class DirtyReadTolerance { + + public static void main(String args[]) throws Exception { + System.out.println("DirtyReadOffender,chrAig["+args[0]+"]coupon=3.50,DirtyReadVictim"); + String isoLevel = args[0]; + + ChronicleMap chm = + DirtyReadTolerance.offHeap( + "C:\\Users\\buddy\\dev\\shm\\OPERAND_CHRONICLE_MAP" + ); + System.out.println(",Established chm,"); + + StampedLock sLock = new StampedLock(); + DirtyReadOffender offender = new DirtyReadOffender(); + offender.setCraig(chm); + offender.setStampedLock(sLock); + + DirtyReadVictim victim = new DirtyReadVictim(isoLevel); + victim.setCraig(chm); + victim.setStampedLock(sLock); + + (new Thread(offender)).start(); + (new Thread(victim)).start(); + } + + static ChronicleMap offHeap(String operand) throws IOException { + // ensure thread ids are globally unique. + AffinitySupport.setThreadId(); + return ChronicleMapBuilder.of(String.class, BondVOInterface.class) + .entries(16) + .averageKeySize("123456789".length()) + .createPersistedTo( + new File( + operand + // "C:\\Users\\buddy\\dev\\shm\\OPERAND_CHRONICLE_MAP" + ) + ); + //.create(); + } +} \ No newline at end of file diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/acid/exodus/DirtyReadVictim.java b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/exodus/DirtyReadVictim.java new file mode 100644 index 000000000..c3dfe2d6c --- /dev/null +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/exodus/DirtyReadVictim.java @@ -0,0 +1,115 @@ +package net.openhft.chronicle.map.fromdocs.acid.exodus; + + +import net.openhft.chronicle.map.ChronicleMap; +import net.openhft.chronicle.map.fromdocs.BondVOInterface; +import net.openhft.chronicle.map.fromdocs.acid.ChronicleAcidIsolation; + +import java.util.Scanner; +import java.util.concurrent.locks.StampedLock; + +import static net.openhft.chronicle.values.Values.newNativeReference; + +public class DirtyReadVictim implements Runnable { + private int isoLevel = ChronicleAcidIsolation.LOWEST_LATENCY; + private ChronicleMap chm; + private StampedLock offHeapLock; + + DirtyReadVictim(String isoL) { + if (isoL.equals("DIRTY_READ_INTOLERANT")) + this.isoLevel = ChronicleAcidIsolation.DIRTY_READ_INTOLERANT; + else if (isoL.equals("DIRTY_READ_OPTIMISTIC")) + this.isoLevel = ChronicleAcidIsolation.DIRTY_READ_OPTIMISTIC; + } + + @Override + public void run() { + Scanner sc = new Scanner(System.in); + try { + + + /** + * ben.cotton@rutgers.edu START + */ + Double coupon = 0.00; + BondVOInterface bond = newNativeReference(BondVOInterface.class); + long stamp = 0; + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim CALLING offHeapLock.tryOptimisticRead()" + ); + while ((stamp = this.offHeapLock.tryOptimisticRead()) == 0) { + ; + } + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim CALLED offHeapLock.tryOptimisticRead()" + ); + + try { + chm.acquireUsing("369604101", bond); + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim calling chm.get('369604101').getCoupon()" + ); + bond = (BondVOInterface) chm.get("369604101"); + coupon = bond.getCoupon(); + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim coupon=[" +coupon+"] read." + ); + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim sleeping 60 seconds" + ); + Thread.sleep( 60_000); + } finally { + if (this.offHeapLock.validate(stamp)) { + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim OPTIMISTICALLY_READ coupon=" + + coupon + " " + ); + } else { + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim FAILED offHeapLock.validate(stamp) " + + " must apply PESSIMISTIC_POLICY (dirty read endured)" + + " coupon=[" + coupon + "] is *DIRTY*. " + ); + } + } + + /** + * ben.cotton@rutgers.edu END + */ + + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim got() coupon=" + + coupon + " " + ); + + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim COMMITTED" + ); + } catch (Exception throwables) { + throwables.printStackTrace(); + } + } + + + public ChronicleMap getCraig() { + return this.chm; + } + + public void setCraig(ChronicleMap craig) { + this.chm = craig; + } + + public void setStampedLock(StampedLock _sLock) { + this.offHeapLock = _sLock; + } +} + diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/acid/genesis/DirtyReadOffender.java b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/genesis/DirtyReadOffender.java new file mode 100644 index 000000000..2e5125267 --- /dev/null +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/genesis/DirtyReadOffender.java @@ -0,0 +1,105 @@ +package net.openhft.chronicle.map.fromdocs.acid.genesis; + + +import net.openhft.chronicle.map.ChronicleMap; +import net.openhft.chronicle.map.fromdocs.BondVOInterface; + +import java.util.Scanner; +import java.util.concurrent.locks.StampedLock; + +import static net.openhft.chronicle.values.Values.newNativeReference; + +public class DirtyReadOffender implements Runnable { + private int isoLevel; + private ChronicleMap chm; + private StampedLock offHeapLock; + + @Override + public void run() { + Scanner sc = new Scanner(System.in); + + try { + BondVOInterface bond = newNativeReference(BondVOInterface.class); + this.chm.acquireUsing("369604101", bond); + System.out.println( + " @t=" + System.currentTimeMillis() + + " DirtyReadOffender sleeping 60 seconds " + ); + Thread.sleep(60 * 1_000); + System.out.println( + " @t=" + System.currentTimeMillis() + + " DirtyReadOffender awakening " + ); + /** + * ben.cotton@rutgers.edu ... anticipate Chronicle (www.OpenHFT.net) + * providing a j.u.c.l.StampedLock API for off-heap enthusiasts + * + * START + * + */ + + long stamp = 0; + System.out.println( + " @t=" + System.currentTimeMillis() + + " DirtyReadOffender ACQUIRING offHeapLock.writeLock();" + ); + while ((stamp = this.offHeapLock.writeLock()) == 0) { + ; + } + System.out.println( + " @t=" + System.currentTimeMillis() + + " DirtyReadOffender ACQUIRED offHeapLock.writeLock();" + ); + try { + double newCoupon = 3.5 + Math.random(); + System.out.println( + " @t=" + System.currentTimeMillis() + + " DirtyReadOffender "+ + " calling chm.put('369604101',"+newCoupon+") " + ); + bond.setCoupon(newCoupon); + chm.put("369604101", bond); + System.out.println( + " @t=" + System.currentTimeMillis() + + " DirtyReadOffender coupon=["+ + bond.getCoupon()+ + "] written. " + ); + } finally { + this.offHeapLock.unlockWrite(stamp); + System.out.println( + " @t=" + System.currentTimeMillis() + + " DirtyReadOffender called offHeapLock.unlockWrite(stamp);" + ); + } + /** + * ben.cotton@rutgers.edu + * + * END + * + */ + } catch (Exception throwables) { + throwables.printStackTrace(); + } + } + + public ChronicleMap getCraig() { + return this.chm; + } + + public void setCraig(ChronicleMap craig) { + this.chm = craig; + } + + public int getIsoLevel() { + return isoLevel; + } + + public void setIsoLevel(int isoLevel) { + this.isoLevel = isoLevel; + } + + public void setStampedLock(StampedLock _sLock) { + this.offHeapLock = _sLock; + } +} diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/acid/genesis/DirtyReadTolerance.java b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/genesis/DirtyReadTolerance.java new file mode 100644 index 000000000..4fbd115a8 --- /dev/null +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/genesis/DirtyReadTolerance.java @@ -0,0 +1,52 @@ +package net.openhft.chronicle.map.fromdocs.acid.genesis; + +import net.openhft.affinity.AffinitySupport; +import net.openhft.chronicle.map.ChronicleMap; +import net.openhft.chronicle.map.ChronicleMapBuilder; +import net.openhft.chronicle.map.fromdocs.BondVOInterface; + +import java.io.File; +import java.io.IOException; +import java.util.concurrent.locks.StampedLock; + + +public class DirtyReadTolerance { + + public static void main(String args[]) throws Exception { + System.out.println("DirtyReadOffender,chrAig["+args[0]+"]coupon=3.50,DirtyReadVictim"); + String isoLevel = args[0]; + + ChronicleMap chm = + DirtyReadTolerance.offHeap( + "C:\\Users\\buddy\\dev\\shm\\OPERAND_CHRONICLE_MAP" + ); + System.out.println(",Established chm,"); + + StampedLock sLock = new StampedLock(); + DirtyReadOffender offender = new DirtyReadOffender(); + offender.setCraig(chm); + offender.setStampedLock(sLock); + + DirtyReadVictim victim = new DirtyReadVictim(isoLevel); + victim.setCraig(chm); + victim.setStampedLock(sLock); + + (new Thread(offender)).start(); + (new Thread(victim)).start(); + } + + static ChronicleMap offHeap(String operand) throws IOException { + // ensure thread ids are globally unique. + AffinitySupport.setThreadId(); + return ChronicleMapBuilder.of(String.class, BondVOInterface.class) + .entries(16) + .averageKeySize("123456789".length()) + .createPersistedTo( + new File( + operand + // "C:\\Users\\buddy\\dev\\shm\\OPERAND_CHRONICLE_MAP" + ) + ); + //.create(); + } +} \ No newline at end of file diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/acid/genesis/DirtyReadVictim.java b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/genesis/DirtyReadVictim.java new file mode 100644 index 000000000..753d8de94 --- /dev/null +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/genesis/DirtyReadVictim.java @@ -0,0 +1,115 @@ +package net.openhft.chronicle.map.fromdocs.acid.genesis; + + +import net.openhft.chronicle.map.ChronicleMap; +import net.openhft.chronicle.map.fromdocs.BondVOInterface; +import net.openhft.chronicle.map.fromdocs.acid.ChronicleAcidIsolation; + +import java.util.Scanner; +import java.util.concurrent.locks.StampedLock; + +import static net.openhft.chronicle.values.Values.newNativeReference; + +public class DirtyReadVictim implements Runnable { + private int isoLevel = ChronicleAcidIsolation.LOWEST_LATENCY; + private ChronicleMap chm; + private StampedLock offHeapLock; + + DirtyReadVictim(String isoL) { + if (isoL.equals("DIRTY_READ_INTOLERANT")) + this.isoLevel = ChronicleAcidIsolation.DIRTY_READ_INTOLERANT; + else if (isoL.equals("DIRTY_READ_OPTIMISTIC")) + this.isoLevel = ChronicleAcidIsolation.DIRTY_READ_OPTIMISTIC; + } + + @Override + public void run() { + Scanner sc = new Scanner(System.in); + try { + + + /** + * ben.cotton@rutgers.edu START + */ + Double coupon = 0.00; + BondVOInterface bond = newNativeReference(BondVOInterface.class); + long stamp = 0; + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim CALLING offHeapLock.tryOptimisticRead()" + ); + while ((stamp = this.offHeapLock.tryOptimisticRead()) == 0) { + ; + } + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim CALLED offHeapLock.tryOptimisticRead()" + ); + + try { + chm.acquireUsing("369604101", bond); + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim calling chm.get('369604101').getCoupon()" + ); + bond = (BondVOInterface) chm.get("369604101"); + coupon = bond.getCoupon(); + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim coupon=[" +coupon+"] read." + ); + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim sleeping 10 seconds" + ); + Thread.sleep( 10_000); + } finally { + if (this.offHeapLock.validate(stamp)) { + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim OPTIMISTICALLY_READ coupon=" + + coupon + " " + ); + } else { + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim FAILED offHeapLock.validate(stamp) " + + " must apply PESSIMISTIC_POLICY (dirty read endured)" + + " coupon=[" + coupon + "] is *DIRTY*. " + ); + } + } + + /** + * ben.cotton@rutgers.edu END + */ + + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim got() coupon=" + + coupon + " " + ); + + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim COMMITTED" + ); + } catch (Exception throwables) { + throwables.printStackTrace(); + } + } + + + public ChronicleMap getCraig() { + return this.chm; + } + + public void setCraig(ChronicleMap craig) { + this.chm = craig; + } + + public void setStampedLock(StampedLock _sLock) { + this.offHeapLock = _sLock; + } +} + diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/ChronicleStampedLock.java b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/ChronicleStampedLock.java new file mode 100644 index 000000000..5ffd5f141 --- /dev/null +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/ChronicleStampedLock.java @@ -0,0 +1,296 @@ +package net.openhft.chronicle.map.fromdocs.acid.revelations; + +import net.openhft.affinity.AffinitySupport; +import net.openhft.chronicle.core.values.LongValue; +import net.openhft.chronicle.map.ChronicleMap; +import net.openhft.chronicle.map.ChronicleMapBuilder; +import net.openhft.chronicle.values.Values; + +import java.io.File; +import java.io.IOException; +import java.util.concurrent.locks.StampedLock; + +import static net.openhft.chronicle.values.Values.newNativeReference; + +/** + * ben.cotton@rutgers.edu + *

+ * A totally hacked impl, awaiting OpenHFT's official ChronicleStampedLock API + *

+ * A usable impl will more properly belong in the Chronicle-Algorithms repo + */ +public class ChronicleStampedLock extends StampedLock { + + ChronicleMap chm; + ChronicleMap chmR; + + ChronicleStampedLockVOInterface offHeapLock = + newNativeReference(ChronicleStampedLockVOInterface.class); + ChronicleStampedLockVOInterface lastWriterT = + newNativeReference(ChronicleStampedLockVOInterface.class); + LongValue readLockHolderCount = Values.newNativeReference(LongValue.class); + + + ChronicleStampedLock(String chronicelStampedLockLocality) { + try { + chm = offHeapLock(chronicelStampedLockLocality); + chmR = offHeapLockReaderCount(chronicelStampedLockLocality+"=ReaderCount"); + chm.acquireUsing("Stamp ", offHeapLock); + chm.acquireUsing("LastWriterTime ", lastWriterT); + chmR.acquireUsing("ReaderCount ", readLockHolderCount); + //readLockHolderCount.setValue(0L); + System.out.println( + " ,@t=" + System.currentTimeMillis() + + " ChronicleStampedLock constructed" + + "," + ); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public long tryOptimisticRead() { + long l = 0; + + offHeapLock = chm.get("Stamp "); + //do { + l = (offHeapLock = chm.get("Stamp ")).getEntryLockState(); +// System.out.println( +// " ,,@t=" + System.currentTimeMillis() + +// " ChronicleStampedLock waiting for unlockWrite()... " + +// "" +// ); +// try { +// Thread.sleep(1000); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } + // } while ( /*l < 0L*/); // do not loop! @vgrazi confirms that in JCA rebooted app. + + offHeapLock.setEntryLockState(0L); + long t = System.currentTimeMillis(); + chm.put("Stamp ", offHeapLock); + System.out.println( + " ,@t=" + System.currentTimeMillis() + + " ChronicleStampedLock saw stamp=["+l+"]"+ + " tryOptmisticRead() returning stamp=" + + t + + "," + ); + + return (t); + } + + @Override + public boolean validate(long stamp) { + offHeapLock = chm.get("Stamp "); + lastWriterT = chm.get("LastWriterTime "); + boolean ret = false; + if (lastWriterT.getEntryLockState() > stamp || offHeapLock.getEntryLockState() <0L) { + ret = Boolean.FALSE; + } else { + ret = Boolean.TRUE; + } + System.out.println( + " ,@t=" + System.currentTimeMillis() + + " ChronicleStampedLock validate(" + + stamp + ") returned =[" + + ret + "] " + + "," + ); + System.out.println( + " ,@t=" + System.currentTimeMillis() + + " ChronicleStampedLock LastWriterT=[" + + lastWriterT.getEntryLockState() + "] " + + "," + ); + return ret; + } + + @Override + public long tryWriteLock() { + long l = 0; + + offHeapLock = chm.get("Stamp "); + lastWriterT = chm.get("LastWriterTime "); + + do { + System.out.println( + " ,@t=" + System.currentTimeMillis() + + " ChronicleStampedLock tryWriterLock() WAITING " + + " on offHeapLock.unlock(" + + offHeapLock.getEntryLockState() + + ") ," + ); + offHeapLock = chm.get("Stamp "); + l = offHeapLock.getEntryLockState(); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } while (l != 0L || readLockHolderCount.getValue() > 0); + System.out.println( + " ,@t=" + System.currentTimeMillis() + + " ChronicleStampedLock tryWriterLock() RESUMING " + + " ," + ); + long t = System.currentTimeMillis(); + try { + Thread.sleep((long) (Math.random() * 1000)); //sleep up to 1 second + } catch (InterruptedException e) { + e.printStackTrace(); + } + offHeapLock.setEntryLockState(-t); //negative ==> Writer holds StampedLock + lastWriterT.setEntryLockState(t); + chm.put("Stamp ", offHeapLock); + chm.put("LastWriterTime ", lastWriterT); + System.out.println( + " ,@t=" + t + + " ChronicleStampedLock tryWriteLock() returned stamp=" + + offHeapLock.getEntryLockState() + + "," + ); + return (offHeapLock.getEntryLockState()); + } + + @Override + public long tryReadLock() { + long l = 0; + + offHeapLock = chm.get("Stamp "); + readLockHolderCount = chmR.get("ReaderCount "); + + do { + System.out.println( + " ,@t=" + System.currentTimeMillis() + + " ChronicleStampedLock tryReadLock() WAITING on Writer.unlock(" + + offHeapLock.getEntryLockState() + + ") ," + ); + l = (offHeapLock = chm.get("Stamp ")).getEntryLockState(); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } while (l < 0L); + try { + Thread.sleep((long) (Math.random() * 2000)); //sleep up to 1 second + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println( + " ,@t=" + System.currentTimeMillis() + + " ChronicleStampedLock tryReadLock() RESUMING " + + //" readerCount=[" + readerCount.getReaderCount() + "]" + + " readerCount=[" + readLockHolderCount.getVolatileValue() + "]" + + " BEFORE addAtomic(1) "+ + "," + ); + + readLockHolderCount.addAtomicValue(1); + + + try { + Thread.sleep((long) (Math.random() * 1000)); //sleep up to 1 second + } catch (InterruptedException e) { + e.printStackTrace(); + } + offHeapLock.setEntryLockState( + readLockHolderCount.getVolatileValue() + ); //negative ==> Writer holds StampedLock + + chm.put("Stamp ", offHeapLock); + + System.out.println( + " ,@t=" + System.currentTimeMillis() + + " ChronicleStampedLock tryReadLock() returned stamp=" + + offHeapLock.getEntryLockState() + + " readerCount=[" + readLockHolderCount.getVolatileValue() + "]" + + " AFTER addAtomic(1) "+ + "," + ); + chmR.put("ReaderCount ", readLockHolderCount); + return (offHeapLock.getEntryLockState()); + } + + @Override + public void unlockRead(long stamp) { + offHeapLock = chm.get("Stamp "); + readLockHolderCount = chmR.get("ReaderCount "); + + System.out.println( + " ,@t=" + System.currentTimeMillis() + + " ChronicleStampedLock unlockRead(" + stamp + ") unlocking.." + + "ReaderCount=[" + readLockHolderCount.getVolatileValue() + "]" + + " BEFORE addAtomic(-1) "+ + "," + ); + readLockHolderCount.addAtomicValue(-1); + System.out.println( + " ,@t=" + System.currentTimeMillis() + + " ChronicleStampedLock unlockRead(" + stamp + ") unlocking.." + + "ReaderCount=[" + readLockHolderCount.getVolatileValue() + "]" + + " AFTER addAtomic(-1) "+ + "," + ); + offHeapLock.setEntryLockState(readLockHolderCount.getVolatileValue()); + + System.out.println( + " ,@t=" + System.currentTimeMillis() + + "offHeapLock=[" + offHeapLock.getEntryLockState() + "]" + + "," + ); + chm.put("Stamp ", offHeapLock); + chmR.put("ReaderCount ", readLockHolderCount); + } + + + @Override + public void unlockWrite(long stamp) { + System.out.println( + " ,@t=" + System.currentTimeMillis() + + " ChronicleStampedLock unlockWrite(" + stamp + ") unlocking..," + ); + offHeapLock = chm.get("Stamp "); + offHeapLock.setEntryLockState(0L); + chm.put("Stamp ", offHeapLock); + System.out.println( + " ,@t=" + System.currentTimeMillis() + + " ChronicleStampedLock unlockWrite(" + + chm.get("Stamp ").getEntryLockState() + + ") unlocked. set to Zero" + + "," + ); + } + + static ChronicleMap offHeapLock(String operand) + throws IOException { + + AffinitySupport.setThreadId(); + return ChronicleMapBuilder.of(String.class, ChronicleStampedLockVOInterface.class) + .entries(16) + .averageKeySize("123456789".length()) + .createPersistedTo( + new File( + operand + ) + ); + } + + static ChronicleMap offHeapLockReaderCount(String operand) + throws IOException { + + AffinitySupport.setThreadId(); + return ChronicleMapBuilder.of(String.class, LongValue.class) + .entries(16) + .averageKeySize("123456789".length()) + .createPersistedTo( + new File( + operand + ) + ); + } +} diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/ChronicleStampedLockVOInterface.java b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/ChronicleStampedLockVOInterface.java new file mode 100644 index 000000000..57b034b3c --- /dev/null +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/ChronicleStampedLockVOInterface.java @@ -0,0 +1,38 @@ +/* + * Copyright 2012-2018 Chronicle Map Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.openhft.chronicle.map.fromdocs.acid.revelations; + +import net.openhft.chronicle.values.Array; +import net.openhft.chronicle.values.Group; +import net.openhft.chronicle.values.MaxUtf8Length; + +interface ChronicleStampedLockVOInterface { + + @Group(0) + long getEntryLockState(); + + void setEntryLockState(long entryLockState); +// +// @Group(1) +// long getReaderCount(); +// +// void setReaderCount(long rc); /* time in millis */ +// +// long addAtomicReaderCount(long toAdd); +// + +} diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/DirtyReadIntolerant.java b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/DirtyReadIntolerant.java new file mode 100644 index 000000000..fb9fa1393 --- /dev/null +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/DirtyReadIntolerant.java @@ -0,0 +1,101 @@ +package net.openhft.chronicle.map.fromdocs.acid.revelations; + +import net.openhft.chronicle.map.ChronicleMap; +import net.openhft.chronicle.map.fromdocs.BondVOInterface; + +import java.util.concurrent.locks.StampedLock; + +import static net.openhft.chronicle.values.Values.newNativeReference; + +public class DirtyReadIntolerant { + public static void main(String args[]) { + try { + String isoLevel = args[0]; + long sleepMock = Long.parseLong(args[1]); + long holdTime = Long.parseLong(args[2]); + /** + * ben.cotton@rutgers.edu START + */ + ChronicleMap chm = + DirtyReadTolerance.offHeap( + args[3] + + "OPERAND_CHRONICLE_MAP" + ); + Double coupon = 0.00; + BondVOInterface bond = newNativeReference(BondVOInterface.class); + //BondVOInterface cslMock = newNativeReference(BondVOInterface.class); //mock'd + long stamp = 0; + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadIntolerant ENTERING offHeapLock.tryReadLock()" + ); + StampedLock offHeapLock = + new ChronicleStampedLock( + args[3] + + "OPERAND_ChronicleStampedLock" + ); + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadIntolerant sleeping " + sleepMock + " seconds" + ); + Thread.sleep(sleepMock * 1_000); + while ((stamp = offHeapLock.tryReadLock()) < 0) { + ; + } + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadIntolerant ENTERED offHeapLock.tryReadLock() " + + " stamp=[" + + stamp + + "]" + ); + try { + chm.acquireUsing("369604101", bond); + //chm.acquireUsing("Offender ", cslMock); //mock'd + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadIntolerant calling chm.get('369604101').getCoupon()" + ); + bond = (BondVOInterface) chm.get("369604101"); + coupon = bond.getCoupon(); + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadIntolerant coupon=[" + coupon + "] read." + ); + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadIntolerant sleeping " + holdTime + " seconds" + ); + + Thread.sleep(holdTime * 1_000); + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadIntolerant awakening" + ); + + } finally { + offHeapLock.unlockRead(stamp); + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadIntolerant offHeapLock.unlockRead(" + + stamp + ") completed." + ); + + } + /** + * ben.cotton@rutgers.edu END + */ + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadIntolerant got() coupon=" + + coupon + " " + ); + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadIntolerant COMMITTED" + ); + } catch (Exception throwables) { + throwables.printStackTrace(); + } + } +} diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/DirtyReadOffender.java b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/DirtyReadOffender.java new file mode 100644 index 000000000..b423875f7 --- /dev/null +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/DirtyReadOffender.java @@ -0,0 +1,111 @@ +package net.openhft.chronicle.map.fromdocs.acid.revelations; + +import net.openhft.chronicle.map.ChronicleMap; +import net.openhft.chronicle.map.fromdocs.BondVOInterface;; + +import java.util.Scanner; +import java.util.concurrent.locks.StampedLock; + +import static net.openhft.chronicle.values.Values.newNativeReference; + +public class DirtyReadOffender { + + public static void main(String args[]) { + Scanner sc = new Scanner(System.in); + + try { + String isoLevel = args[0]; + long sleepT = Long.parseLong(args[1]); + long holdTime = Long.parseLong(args[2]); + + ChronicleMap chm = + DirtyReadTolerance.offHeap( + args[3] + + "OPERAND_CHRONICLE_MAP" + ); + System.out.println( + " @t=" + System.currentTimeMillis() + + " DirtyReadOffender established chm " + ); + StampedLock offHeapLock = new ChronicleStampedLock( + args[3] + + "OPERAND_ChronicleStampedLock" + ); + BondVOInterface bond = newNativeReference(BondVOInterface.class); + //BondVOInterface cslMock = newNativeReference(BondVOInterface.class); + chm.acquireUsing("369604101", bond); + //chm.acquireUsing("Offender ", cslMock); // mock ChronicleStampLock + System.out.println( + " @t=" + System.currentTimeMillis() + + " DirtyReadOffender sleeping " + sleepT + " seconds " + ); + Thread.sleep(sleepT * 1_000); + System.out.println( + " @t=" + System.currentTimeMillis() + + " DirtyReadOffender awakening " + ); + /** + * ben.cotton@rutgers.edu ... anticipate Chronicle (www.OpenHFT.net) + * providing a j.u.c.l.StampedLock API for off-heap enthusiasts + * + * START + * + */ + long stamp = 0; + System.out.println( + " @t=" + System.currentTimeMillis() + + " DirtyReadOffender ACQUIRING offHeapLock.writeLock();" + ); + while ((stamp = offHeapLock.tryWriteLock()) == 0) { + ; + } + System.out.println( + " @t=" + System.currentTimeMillis() + + " DirtyReadOffender ACQUIRED offHeapLock.writeLock();" + ); + try { + double newCoupon = 3.5 + Math.random(); + System.out.println( + " @t=" + System.currentTimeMillis() + + " DirtyReadOffender " + + " calling chm.put('369604101'," + newCoupon + ") " + ); + bond.setCoupon(newCoupon); + chm.put("369604101", bond); + //cslMock.setEntryLockState(System.currentTimeMillis()); //mock'd + // chm.put("Offender ",cslMock); //mock'd + System.out.println( + " @t=" + System.currentTimeMillis() + + " DirtyReadOffender coupon=[" + + bond.getCoupon() + + "] written. " + ); + } finally { + System.out.println( + " @t=" + System.currentTimeMillis() + + " DirtyReadOffender sleeping " + holdTime + " seconds " + ); + Thread.sleep(holdTime * 1_000); + offHeapLock.unlockWrite(stamp); + System.out.println( + " @t=" + System.currentTimeMillis() + + " DirtyReadOffender called " + + "offHeapLock.unlockWrite(" + stamp + ");" + ); + } + /** + * ben.cotton@rutgers.edu + * + * END + * + */ + } catch (Exception throwables) { + throwables.printStackTrace(); + } finally { + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadOffender COMMITTED" + ); + } + } +} \ No newline at end of file diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/DirtyReadTolerance.java b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/DirtyReadTolerance.java new file mode 100644 index 000000000..0c9ebb077 --- /dev/null +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/DirtyReadTolerance.java @@ -0,0 +1,45 @@ +package net.openhft.chronicle.map.fromdocs.acid.revelations; + +import net.openhft.affinity.AffinitySupport; +import net.openhft.chronicle.map.ChronicleMap; +import net.openhft.chronicle.map.ChronicleMapBuilder; +import net.openhft.chronicle.map.fromdocs.BondVOInterface; +import net.openhft.chronicle.map.fromdocs.acid.exodus.DirtyReadOffender; +import net.openhft.chronicle.map.fromdocs.acid.exodus.DirtyReadVictim; + +import java.io.File; +import java.io.IOException; +import java.util.concurrent.locks.StampedLock; + + +public class DirtyReadTolerance { + + public static void main(String args[]) throws Exception { + System.out.println("DirtyReadOffender,chrAig["+args[0]+"]coupon=3.50,DirtyReadVictim"); + String isoLevel = args[0]; + + ChronicleMap chm = + DirtyReadTolerance.offHeap( + args[2] + + "OPERAND_CHRONICLE_MAP" + ); + System.out.println(",Established chm,"); + } + + static ChronicleMap offHeap(String operand) throws IOException { + // ensure thread ids are globally unique. + AffinitySupport.setThreadId(); + return ChronicleMapBuilder.of(String.class, BondVOInterface.class) + .entries(16) + .averageKeySize("123456789".length()) + .createPersistedTo( + new File( + operand + // "C:\\Users\\buddy\\dev\\shm\\OPERAND_CHRONICLE_MAP" + ) + ); + //.create(); + } + + +} \ No newline at end of file diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/DirtyReadVictim.java b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/DirtyReadVictim.java new file mode 100644 index 000000000..28d260ef8 --- /dev/null +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/DirtyReadVictim.java @@ -0,0 +1,125 @@ +package net.openhft.chronicle.map.fromdocs.acid.revelations; + +import net.openhft.chronicle.map.ChronicleMap; +import net.openhft.chronicle.map.fromdocs.BondVOInterface; +import net.openhft.chronicle.map.fromdocs.acid.ChronicleAcidIsolation; + +import java.util.concurrent.locks.StampedLock; + +import static net.openhft.chronicle.values.Values.newNativeReference; + +public class DirtyReadVictim { + + public static void main(String args[]) { + try { + String isoLevel = args[0]; + long sleepMock = Long.parseLong(args[1]); + long holdTime = Long.parseLong(args[2]); + /** + * ben.cotton@rutgers.edu START + */ + ChronicleMap chm = + DirtyReadTolerance.offHeap( + args[3] + + "OPERAND_CHRONICLE_MAP" + ); + Double coupon = 0.00; + BondVOInterface bond = newNativeReference(BondVOInterface.class); + //BondVOInterface cslMock = newNativeReference(BondVOInterface.class); //mock'd + long stamp = 0; + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim ENTERING offHeapLock.tryOptimisticRead()" + ); + StampedLock offHeapLock = + new ChronicleStampedLock( + args[3] + + "OPERAND_ChronicleStampedLock" + ); + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim sleeping " + sleepMock + " seconds" + ); + + Thread.sleep(sleepMock * 1_000); + while ((stamp = offHeapLock.tryOptimisticRead()) < 0) { + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim waiting for unlockWrite()... " + + "" + ); + Thread.sleep(1000); + } + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim ENTERED offHeapLock.tryOptimisticRead() " + + " stamp=[" + + stamp + + "]" + ); + try { + chm.acquireUsing("369604101", bond); + //chm.acquireUsing("Offender ", cslMock); //mock'd + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim calling chm.get('369604101').getCoupon()" + ); + bond = (BondVOInterface) chm.get("369604101"); + coupon = bond.getCoupon(); + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim coupon=[" + coupon + "] read." + ); + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim sleeping " + holdTime + " seconds" + ); + + Thread.sleep(holdTime * 1_000); + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim awakening" + ); + + } finally { + if (offHeapLock.validate(stamp)) { + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim OPTIMISTICALLY_READ coupon=" + + coupon + " " + + "stamp = [" + stamp + "]" + ); + } else { + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim FAILED offHeapLock.validate(stamp) " + + " must apply PESSIMISTIC_POLICY (dirty read endured)" + + " coupon=[" + coupon + "] is *DIRTY*. " + + " stamp = [" + stamp + "]" + ); + + } + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim EXITED offHeapLock.tryOptimisticRead()" + ); + + } + /** + * ben.cotton@rutgers.edu END + */ + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim got() coupon=" + + coupon + " " + ); + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim COMMITTED" + ); + } catch (Exception throwables) { + throwables.printStackTrace(); + } + } +} + diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/DirtyReadVictimTest.java b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/DirtyReadVictimTest.java new file mode 100644 index 000000000..266f2a080 --- /dev/null +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/DirtyReadVictimTest.java @@ -0,0 +1,103 @@ +package net.openhft.chronicle.map.fromdocs.acid.revelations; + +import net.openhft.chronicle.map.ChronicleMap; +import net.openhft.chronicle.map.fromdocs.BondVOInterface; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import static net.openhft.chronicle.values.Values.newNativeReference; +import static org.junit.Assert.*; + +public class DirtyReadVictimTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void main() { + try { + /** + * ben.cotton@rutgers.edu START + */ + ChronicleMap chm = + DirtyReadTolerance.offHeap( + "C:\\Users\\buddy\\dev\\shm\\OPERAND_CHRONICLE_MAP" + ); + Double coupon = 0.00; + BondVOInterface bond = newNativeReference(BondVOInterface.class); + long stamp = 0; + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim CALLING offHeapLock.tryOptimisticRead()" + ); + ChronicleStampedLock offHeapLock = new ChronicleStampedLock( + "C:\\Users\\buddy\\dev\\shm\\OPERAND_ChronicleStampedLock" + ); + while ((stamp = offHeapLock.tryOptimisticRead()) == 0) { + ; + } + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim CALLED offHeapLock.tryOptimisticRead()" + ); + try { + chm.acquireUsing("369604101", bond); + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim calling chm.get('369604101').getCoupon()" + ); + bond = (BondVOInterface) chm.get("369604101"); + coupon = bond.getCoupon(); + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim coupon=[" + coupon + "] read." + ); + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim sleeping 10 seconds" + ); + Thread.sleep(10_000); + } finally { + if (offHeapLock.validate(stamp)) { + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim OPTIMISTICALLY_READ coupon=" + + coupon + " " + ); + // THIS Test will pass when ChronicleStampedLock is GA + Assert.assertFalse(Boolean.TRUE); + } else { + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim FAILED offHeapLock.validate(stamp) " + + " must apply PESSIMISTIC_POLICY (dirty read endured)" + + " coupon=[" + coupon + "] is *DIRTY*. " + ); + // THIS Test will execute pass when ChronicleStampedLock is GA + Assert.assertFalse(Boolean.FALSE); + } + } + /** + * ben.cotton@rutgers.edu END + */ + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim got() coupon=" + + coupon + " " + ); + System.out.println( + " ,,@t=" + System.currentTimeMillis() + + " DirtyReadVictim COMMITTED" + ); + } catch (Exception throwables) { + throwables.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/Weyuker,E.pdf b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/Weyuker,E.pdf new file mode 100644 index 000000000..d05d298b9 Binary files /dev/null and b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/Weyuker,E.pdf differ diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/clrs=Algorithms.pdf b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/clrs=Algorithms.pdf new file mode 100644 index 000000000..74f9efdd7 Binary files /dev/null and b/src/test/java/net/openhft/chronicle/map/fromdocs/acid/revelations/clrs=Algorithms.pdf differ diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/pingpong_latency/PingPongLockLeft.java b/src/test/java/net/openhft/chronicle/map/fromdocs/pingpong_latency/PingPongLockLeft.java index 675c547b3..f4266a414 100644 --- a/src/test/java/net/openhft/chronicle/map/fromdocs/pingpong_latency/PingPongLockLeft.java +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/pingpong_latency/PingPongLockLeft.java @@ -32,68 +32,68 @@ import static net.openhft.chronicle.algo.bytes.Access.checkedBytesStoreAccess; import static net.openhft.chronicle.values.Values.newNativeReference; public class PingPongLockLeft { - public static void main(String... ignored) throws IOException, InterruptedException { - ChronicleMap chm = PingPongCASLeft.acquireCHM(); - - playPingPong(chm, 4, 5, true, "PingPongLockLEFT"); - } - - static void playPingPong(ChronicleMap chm, double _coupon, double _coupon2, boolean setFirst, final String desc) throws InterruptedException { - BondVOInterface bond1 = newNativeReference(BondVOInterface.class); - BondVOInterface bond2 = newNativeReference(BondVOInterface.class); - BondVOInterface bond3 = newNativeReference(BondVOInterface.class); - BondVOInterface bond4 = newNativeReference(BondVOInterface.class); - - chm.acquireUsing("369604101", bond1); - chm.acquireUsing("369604102", bond2); - chm.acquireUsing("369604103", bond3); - chm.acquireUsing("369604104", bond4); - System.out.printf("\n\n" + desc + ": Timing 1 x off-heap operations on " + chm.file() + "\n"); - if (setFirst) { - bond1.setCoupon(_coupon); - bond2.setCoupon(_coupon); - bond3.setCoupon(_coupon); - bond4.setCoupon(_coupon); - } - int timeToCallNanoTime = 30; - int runs = 1000000; - long[] timings = new long[runs]; - for (int j = 0; j < 10; j++) { - for (int i = 0; i < runs; i++) { - long _start = System.nanoTime(); - toggleCoupon(bond1, _coupon, _coupon2); - toggleCoupon(bond2, _coupon, _coupon2); - toggleCoupon(bond3, _coupon, _coupon2); - toggleCoupon(bond4, _coupon, _coupon2); - - timings[i] = (System.nanoTime() - _start - timeToCallNanoTime) / 4; - } - Arrays.sort(timings); - System.out.printf("#%d: lock,compare,set,unlock 50/90/99%%tile was %,d / %,d / %,d%n", - j, timings[runs / 2], timings[runs * 9 / 10], timings[runs * 99 / 100]); - } - } - - private static void toggleCoupon(BondVOInterface bond, double _coupon, double _coupon2) - throws InterruptedException { - for (int i = 0; ; i++) { - AcquisitionStrategies.spinLoopOrFail(5, TimeUnit.SECONDS) - .acquire(TryAcquireOperations.writeLock(), - VanillaReadWriteWithWaitsLockingStrategy.instance(), - checkedBytesStoreAccess(), - ((Byteable) bond).bytesStore(), ((Byteable) bond).offset()); - try { - if (bond.getCoupon() == _coupon) { - bond.setCoupon(_coupon2); - return; - } - if (i > 1000) - Thread.yield(); - } finally { - VanillaReadWriteWithWaitsLockingStrategy.instance() - .writeUnlock(checkedBytesStoreAccess(), - ((Byteable) bond).bytesStore(), ((Byteable) bond).offset()); - } - } - } +// public static void main(String... ignored) throws IOException, InterruptedException { +// ChronicleMap chm = PingPongCASLeft.acquireCHM(); +// +// playPingPong(chm, 4, 5, true, "PingPongLockLEFT"); +// } +// +// static void playPingPong(ChronicleMap chm, double _coupon, double _coupon2, boolean setFirst, final String desc) throws InterruptedException { +// BondVOInterface bond1 = newNativeReference(BondVOInterface.class); +// BondVOInterface bond2 = newNativeReference(BondVOInterface.class); +// BondVOInterface bond3 = newNativeReference(BondVOInterface.class); +// BondVOInterface bond4 = newNativeReference(BondVOInterface.class); +// +// chm.acquireUsing("369604101", bond1); +// chm.acquireUsing("369604102", bond2); +// chm.acquireUsing("369604103", bond3); +// chm.acquireUsing("369604104", bond4); +// System.out.printf("\n\n" + desc + ": Timing 1 x off-heap operations on " + chm.file() + "\n"); +// if (setFirst) { +// bond1.setCoupon(_coupon); +// bond2.setCoupon(_coupon); +// bond3.setCoupon(_coupon); +// bond4.setCoupon(_coupon); +// } +// int timeToCallNanoTime = 30; +// int runs = 1000000; +// long[] timings = new long[runs]; +// for (int j = 0; j < 10; j++) { +// for (int i = 0; i < runs; i++) { +// long _start = System.nanoTime(); +// toggleCoupon(bond1, _coupon, _coupon2); +// toggleCoupon(bond2, _coupon, _coupon2); +// toggleCoupon(bond3, _coupon, _coupon2); +// toggleCoupon(bond4, _coupon, _coupon2); +// +// timings[i] = (System.nanoTime() - _start - timeToCallNanoTime) / 4; +// } +// Arrays.sort(timings); +// System.out.printf("#%d: lock,compare,set,unlock 50/90/99%%tile was %,d / %,d / %,d%n", +// j, timings[runs / 2], timings[runs * 9 / 10], timings[runs * 99 / 100]); +// } +// } +// +// private static void toggleCoupon(BondVOInterface bond, double _coupon, double _coupon2) +// throws InterruptedException { +// for (int i = 0; ; i++) { +// AcquisitionStrategies.spinLoopOrFail(5, TimeUnit.SECONDS) +// .acquire(TryAcquireOperations.writeLock(), +// VanillaReadWriteWithWaitsLockingStrategy.instance(), +// checkedBytesStoreAccess(), +// ((Byteable) bond).bytesStore(), ((Byteable) bond).offset()); +// try { +// if (bond.getCoupon() == _coupon) { +// bond.setCoupon(_coupon2); +// return; +// } +// if (i > 1000) +// Thread.yield(); +// } finally { +// VanillaReadWriteWithWaitsLockingStrategy.instance() +// .writeUnlock(checkedBytesStoreAccess(), +// ((Byteable) bond).bytesStore(), ((Byteable) bond).offset()); +// } +// } +// } } \ No newline at end of file diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/pingpong_latency/PingPongLockRight.java b/src/test/java/net/openhft/chronicle/map/fromdocs/pingpong_latency/PingPongLockRight.java index 41684f614..7e5884fc2 100644 --- a/src/test/java/net/openhft/chronicle/map/fromdocs/pingpong_latency/PingPongLockRight.java +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/pingpong_latency/PingPongLockRight.java @@ -25,6 +25,6 @@ public class PingPongLockRight { public static void main(String... ignored) throws IOException, InterruptedException { ChronicleMap chm = PingPongCASLeft.acquireCHM(); - PingPongLockLeft.playPingPong(chm, 5, 4, false, "PingPongLockRIGHT"); + //PingPongLockLeft.playPingPong(chm, 5, 4, false, "PingPongLockRIGHT"); } } \ No newline at end of file