Compare commits

..

1 commit

Author SHA1 Message Date
Greg Burd
ad9261fda3 WIP: started with wal idea, shifting to accounting table. 2017-11-09 12:05:09 -05:00
296 changed files with 3476 additions and 4295 deletions

8
NOTES
View file

@ -22,14 +22,6 @@ Operation/
`-- PreparedStreamOperation `-- PreparedStreamOperation
----
@CompoundIndex()
create a new col in the same table called __idx_a_b_c that the hash of the concatenated values in that order is stored, create a normal index for that (CREATE INDEX ...)
if a query matches that set of columns then use that indexed col to fetch the desired results from that table
could also work with .in() query if materialized view exists
----
// TODO(gburd): create a statement that matches one that wasn't prepared // TODO(gburd): create a statement that matches one that wasn't prepared
//String key = //String key =
// "use " + preparedStatement.getQueryKeyspace() + "; " + preparedStatement.getQueryString(); // "use " + preparedStatement.getQueryKeyspace() + "; " + preparedStatement.getQueryString();

View file

@ -1,3 +1,3 @@
#!/usr/bin/env bash #!/bin/bash
mvn clean jar:jar javadoc:jar source:jar deploy -Prelease mvn clean jar:jar javadoc:jar source:jar deploy -Prelease

View file

@ -1,14 +1,7 @@
#!/usr/bin/env bash #!/bin/bash
if [ "X$1" == "Xall" ]; then
for f in $(find ./src -name \*.java); do for f in $(find ./src -name \*.java); do
echo Formatting $f echo Formatting $f
java -jar ./lib/google-java-format-1.3-all-deps.jar --replace $f java -jar ./lib/google-java-format-1.3-all-deps.jar --replace $f
done done
else
for file in $(git status --short | awk '{print $2}'); do
echo $file
java -jar ./lib/google-java-format-1.3-all-deps.jar --replace $file
done
fi

View file

@ -1,3 +1,3 @@
#!/usr/bin/env bash #!/bin/bash
mvn clean jar:jar javadoc:jar source:jar install -Prelease mvn clean jar:jar javadoc:jar source:jar install -Prelease

90
build.gradle Normal file
View file

@ -0,0 +1,90 @@
// gradle wrapper
// ./gradlew clean generateLock saveLock
// ./gradlew compileJava
// ./gradlew run
// ./gradlew run --debug-jvm
// ./gradlew publishToMavenLocal
buildscript {
ext {}
repositories {
jcenter()
mavenLocal()
mavenCentral()
maven { url "https://clojars.org/repo" }
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath 'com.netflix.nebula:gradle-dependency-lock-plugin:4.+'
classpath 'com.uber:okbuck:0.19.0'
}
}
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'eclipse'
apply plugin: 'java-library'
apply plugin: 'maven-publish'
apply plugin: 'com.uber.okbuck'
apply plugin: 'nebula.dependency-lock'
task wrapper(type: Wrapper) {
gradleVersion = '4.0.2'
}
jar {
baseName = 'helenus'
group = 'net.helenus'
version = '2.0.17-SNAPSHOT'
}
description = """helenus"""
sourceCompatibility = 1.8
targetCompatibility = 1.8
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
configurations.all {
}
repositories {
jcenter()
mavenLocal()
mavenCentral()
maven { url "file:///Users/gburd/ws/helenus/lib" }
maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
maven { url "http://repo.maven.apache.org/maven2" }
}
dependencies {
compile group: 'com.datastax.cassandra', name: 'cassandra-driver-core', version: '3.3.0'
compile group: 'org.aspectj', name: 'aspectjrt', version: '1.8.10'
compile group: 'org.aspectj', name: 'aspectjweaver', version: '1.8.10'
compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.6'
compile group: 'org.springframework', name: 'spring-core', version: '4.3.10.RELEASE'
compile group: 'com.google.guava', name: 'guava', version: '20.0'
compile group: 'com.diffplug.durian', name: 'durian', version: '3.+'
compile group: 'io.zipkin.java', name: 'zipkin', version: '1.29.2'
compile group: 'io.zipkin.brave', name: 'brave', version: '4.0.6'
compile group: 'io.dropwizard.metrics', name: 'metrics-core', version: '3.2.2'
compile group: 'javax.validation', name: 'validation-api', version: '2.0.0.CR3'
compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.1'
runtime group: 'org.slf4j', name: 'jcl-over-slf4j', version: '1.7.1'
testCompile group: 'org.codehaus.jackson', name: 'jackson-mapper-asl', version: '1.9.13'
testCompile group: 'com.anthemengineering.mojo', name: 'infer-maven-plugin', version: '0.1.0'
testCompile group: 'org.codehaus.jackson', name: 'jackson-core-asl', version: '1.9.13'
testCompile(group: 'org.cassandraunit', name: 'cassandra-unit', version: '3.1.4.0-SNAPSHOT') {
exclude(module: 'cassandra-driver-core')
}
testCompile group: 'org.apache.cassandra', name: 'cassandra-all', version: '3.11.0'
testCompile group: 'commons-io', name: 'commons-io', version: '2.5'
testCompile group: 'junit', name: 'junit', version: '4.12'
testCompile group: 'com.github.stephenc', name: 'jamm', version: '0.2.5'
testCompile group: 'org.hamcrest', name: 'hamcrest-library', version: '1.3'
testCompile group: 'org.hamcrest', name: 'hamcrest-core', version: '1.3'
testCompile group: 'org.mockito', name: 'mockito-core', version: '2.8.47'
}

648
dependencies.lock Normal file
View file

@ -0,0 +1,648 @@
{
"compile": {
"com.datastax.cassandra:cassandra-driver-core": {
"locked": "3.3.0",
"requested": "3.3.0"
},
"com.diffplug.durian:durian": {
"locked": "3.5.0-SNAPSHOT",
"requested": "3.+"
},
"com.google.guava:guava": {
"locked": "20.0",
"requested": "20.0"
},
"io.dropwizard.metrics:metrics-core": {
"locked": "3.2.2",
"requested": "3.2.2"
},
"io.zipkin.brave:brave": {
"locked": "4.0.6",
"requested": "4.0.6"
},
"io.zipkin.java:zipkin": {
"locked": "1.29.2",
"requested": "1.29.2"
},
"javax.validation:validation-api": {
"locked": "2.0.0.CR3",
"requested": "2.0.0.CR3"
},
"org.apache.commons:commons-lang3": {
"locked": "3.6",
"requested": "3.6"
},
"org.aspectj:aspectjrt": {
"locked": "1.8.10",
"requested": "1.8.10"
},
"org.aspectj:aspectjweaver": {
"locked": "1.8.10",
"requested": "1.8.10"
},
"org.slf4j:slf4j-api": {
"locked": "1.7.25",
"requested": "1.7.1"
},
"org.springframework:spring-core": {
"locked": "4.3.10.RELEASE",
"requested": "4.3.10.RELEASE"
}
},
"compileClasspath": {
"com.datastax.cassandra:cassandra-driver-core": {
"locked": "3.3.0",
"requested": "3.3.0"
},
"com.diffplug.durian:durian": {
"locked": "3.5.0-SNAPSHOT",
"requested": "3.+"
},
"com.google.guava:guava": {
"locked": "20.0",
"requested": "20.0"
},
"io.dropwizard.metrics:metrics-core": {
"locked": "3.2.2",
"requested": "3.2.2"
},
"io.zipkin.brave:brave": {
"locked": "4.0.6",
"requested": "4.0.6"
},
"io.zipkin.java:zipkin": {
"locked": "1.29.2",
"requested": "1.29.2"
},
"javax.validation:validation-api": {
"locked": "2.0.0.CR3",
"requested": "2.0.0.CR3"
},
"org.apache.commons:commons-lang3": {
"locked": "3.6",
"requested": "3.6"
},
"org.aspectj:aspectjrt": {
"locked": "1.8.10",
"requested": "1.8.10"
},
"org.aspectj:aspectjweaver": {
"locked": "1.8.10",
"requested": "1.8.10"
},
"org.slf4j:slf4j-api": {
"locked": "1.7.25",
"requested": "1.7.1"
},
"org.springframework:spring-core": {
"locked": "4.3.10.RELEASE",
"requested": "4.3.10.RELEASE"
}
},
"default": {
"com.datastax.cassandra:cassandra-driver-core": {
"locked": "3.3.0",
"requested": "3.3.0"
},
"com.diffplug.durian:durian": {
"locked": "3.5.0-SNAPSHOT",
"requested": "3.+"
},
"com.google.guava:guava": {
"locked": "20.0",
"requested": "20.0"
},
"io.dropwizard.metrics:metrics-core": {
"locked": "3.2.2",
"requested": "3.2.2"
},
"io.zipkin.brave:brave": {
"locked": "4.0.6",
"requested": "4.0.6"
},
"io.zipkin.java:zipkin": {
"locked": "1.29.2",
"requested": "1.29.2"
},
"javax.validation:validation-api": {
"locked": "2.0.0.CR3",
"requested": "2.0.0.CR3"
},
"org.apache.commons:commons-lang3": {
"locked": "3.6",
"requested": "3.6"
},
"org.aspectj:aspectjrt": {
"locked": "1.8.10",
"requested": "1.8.10"
},
"org.aspectj:aspectjweaver": {
"locked": "1.8.10",
"requested": "1.8.10"
},
"org.slf4j:jcl-over-slf4j": {
"locked": "1.7.1",
"requested": "1.7.1"
},
"org.slf4j:slf4j-api": {
"locked": "1.7.25",
"requested": "1.7.1"
},
"org.springframework:spring-core": {
"locked": "4.3.10.RELEASE",
"requested": "4.3.10.RELEASE"
}
},
"runtime": {
"com.datastax.cassandra:cassandra-driver-core": {
"locked": "3.3.0",
"requested": "3.3.0"
},
"com.diffplug.durian:durian": {
"locked": "3.5.0-SNAPSHOT",
"requested": "3.+"
},
"com.google.guava:guava": {
"locked": "20.0",
"requested": "20.0"
},
"io.dropwizard.metrics:metrics-core": {
"locked": "3.2.2",
"requested": "3.2.2"
},
"io.zipkin.brave:brave": {
"locked": "4.0.6",
"requested": "4.0.6"
},
"io.zipkin.java:zipkin": {
"locked": "1.29.2",
"requested": "1.29.2"
},
"javax.validation:validation-api": {
"locked": "2.0.0.CR3",
"requested": "2.0.0.CR3"
},
"org.apache.commons:commons-lang3": {
"locked": "3.6",
"requested": "3.6"
},
"org.aspectj:aspectjrt": {
"locked": "1.8.10",
"requested": "1.8.10"
},
"org.aspectj:aspectjweaver": {
"locked": "1.8.10",
"requested": "1.8.10"
},
"org.slf4j:jcl-over-slf4j": {
"locked": "1.7.1",
"requested": "1.7.1"
},
"org.slf4j:slf4j-api": {
"locked": "1.7.25",
"requested": "1.7.1"
},
"org.springframework:spring-core": {
"locked": "4.3.10.RELEASE",
"requested": "4.3.10.RELEASE"
}
},
"runtimeClasspath": {
"com.datastax.cassandra:cassandra-driver-core": {
"locked": "3.3.0",
"requested": "3.3.0"
},
"com.diffplug.durian:durian": {
"locked": "3.5.0-SNAPSHOT",
"requested": "3.+"
},
"com.google.guava:guava": {
"locked": "20.0",
"requested": "20.0"
},
"io.dropwizard.metrics:metrics-core": {
"locked": "3.2.2",
"requested": "3.2.2"
},
"io.zipkin.brave:brave": {
"locked": "4.0.6",
"requested": "4.0.6"
},
"io.zipkin.java:zipkin": {
"locked": "1.29.2",
"requested": "1.29.2"
},
"javax.validation:validation-api": {
"locked": "2.0.0.CR3",
"requested": "2.0.0.CR3"
},
"org.apache.commons:commons-lang3": {
"locked": "3.6",
"requested": "3.6"
},
"org.aspectj:aspectjrt": {
"locked": "1.8.10",
"requested": "1.8.10"
},
"org.aspectj:aspectjweaver": {
"locked": "1.8.10",
"requested": "1.8.10"
},
"org.slf4j:jcl-over-slf4j": {
"locked": "1.7.1",
"requested": "1.7.1"
},
"org.slf4j:slf4j-api": {
"locked": "1.7.25",
"requested": "1.7.1"
},
"org.springframework:spring-core": {
"locked": "4.3.10.RELEASE",
"requested": "4.3.10.RELEASE"
}
},
"testCompile": {
"com.anthemengineering.mojo:infer-maven-plugin": {
"locked": "0.1.0",
"requested": "0.1.0"
},
"com.datastax.cassandra:cassandra-driver-core": {
"locked": "3.3.0",
"requested": "3.3.0"
},
"com.diffplug.durian:durian": {
"locked": "3.5.0-SNAPSHOT",
"requested": "3.+"
},
"com.github.stephenc:jamm": {
"locked": "0.2.5",
"requested": "0.2.5"
},
"com.google.guava:guava": {
"locked": "21.0",
"requested": "20.0"
},
"commons-io:commons-io": {
"locked": "2.5",
"requested": "2.5"
},
"io.dropwizard.metrics:metrics-core": {
"locked": "3.2.2",
"requested": "3.2.2"
},
"io.zipkin.brave:brave": {
"locked": "4.0.6",
"requested": "4.0.6"
},
"io.zipkin.java:zipkin": {
"locked": "1.29.2",
"requested": "1.29.2"
},
"javax.validation:validation-api": {
"locked": "2.0.0.CR3",
"requested": "2.0.0.CR3"
},
"junit:junit": {
"locked": "4.12",
"requested": "4.12"
},
"org.apache.cassandra:cassandra-all": {
"locked": "3.11.0",
"requested": "3.11.0"
},
"org.apache.commons:commons-lang3": {
"locked": "3.6",
"requested": "3.6"
},
"org.aspectj:aspectjrt": {
"locked": "1.8.10",
"requested": "1.8.10"
},
"org.aspectj:aspectjweaver": {
"locked": "1.8.10",
"requested": "1.8.10"
},
"org.cassandraunit:cassandra-unit": {
"locked": "3.1.4.0-SNAPSHOT",
"requested": "3.1.4.0-SNAPSHOT"
},
"org.codehaus.jackson:jackson-core-asl": {
"locked": "1.9.13",
"requested": "1.9.13"
},
"org.codehaus.jackson:jackson-mapper-asl": {
"locked": "1.9.13",
"requested": "1.9.13"
},
"org.hamcrest:hamcrest-core": {
"locked": "1.3",
"requested": "1.3"
},
"org.hamcrest:hamcrest-library": {
"locked": "1.3",
"requested": "1.3"
},
"org.mockito:mockito-core": {
"locked": "2.8.47",
"requested": "2.8.47"
},
"org.slf4j:slf4j-api": {
"locked": "1.7.25",
"requested": "1.7.1"
},
"org.springframework:spring-core": {
"locked": "4.3.10.RELEASE",
"requested": "4.3.10.RELEASE"
}
},
"testCompileClasspath": {
"com.anthemengineering.mojo:infer-maven-plugin": {
"locked": "0.1.0",
"requested": "0.1.0"
},
"com.datastax.cassandra:cassandra-driver-core": {
"locked": "3.3.0",
"requested": "3.3.0"
},
"com.diffplug.durian:durian": {
"locked": "3.5.0-SNAPSHOT",
"requested": "3.+"
},
"com.github.stephenc:jamm": {
"locked": "0.2.5",
"requested": "0.2.5"
},
"com.google.guava:guava": {
"locked": "21.0",
"requested": "20.0"
},
"commons-io:commons-io": {
"locked": "2.5",
"requested": "2.5"
},
"io.dropwizard.metrics:metrics-core": {
"locked": "3.2.2",
"requested": "3.2.2"
},
"io.zipkin.brave:brave": {
"locked": "4.0.6",
"requested": "4.0.6"
},
"io.zipkin.java:zipkin": {
"locked": "1.29.2",
"requested": "1.29.2"
},
"javax.validation:validation-api": {
"locked": "2.0.0.CR3",
"requested": "2.0.0.CR3"
},
"junit:junit": {
"locked": "4.12",
"requested": "4.12"
},
"org.apache.cassandra:cassandra-all": {
"locked": "3.11.0",
"requested": "3.11.0"
},
"org.apache.commons:commons-lang3": {
"locked": "3.6",
"requested": "3.6"
},
"org.aspectj:aspectjrt": {
"locked": "1.8.10",
"requested": "1.8.10"
},
"org.aspectj:aspectjweaver": {
"locked": "1.8.10",
"requested": "1.8.10"
},
"org.cassandraunit:cassandra-unit": {
"locked": "3.1.4.0-SNAPSHOT",
"requested": "3.1.4.0-SNAPSHOT"
},
"org.codehaus.jackson:jackson-core-asl": {
"locked": "1.9.13",
"requested": "1.9.13"
},
"org.codehaus.jackson:jackson-mapper-asl": {
"locked": "1.9.13",
"requested": "1.9.13"
},
"org.hamcrest:hamcrest-core": {
"locked": "1.3",
"requested": "1.3"
},
"org.hamcrest:hamcrest-library": {
"locked": "1.3",
"requested": "1.3"
},
"org.mockito:mockito-core": {
"locked": "2.8.47",
"requested": "2.8.47"
},
"org.slf4j:slf4j-api": {
"locked": "1.7.25",
"requested": "1.7.1"
},
"org.springframework:spring-core": {
"locked": "4.3.10.RELEASE",
"requested": "4.3.10.RELEASE"
}
},
"testRuntime": {
"com.anthemengineering.mojo:infer-maven-plugin": {
"locked": "0.1.0",
"requested": "0.1.0"
},
"com.datastax.cassandra:cassandra-driver-core": {
"locked": "3.3.0",
"requested": "3.3.0"
},
"com.diffplug.durian:durian": {
"locked": "3.5.0-SNAPSHOT",
"requested": "3.+"
},
"com.github.stephenc:jamm": {
"locked": "0.2.5",
"requested": "0.2.5"
},
"com.google.guava:guava": {
"locked": "21.0",
"requested": "20.0"
},
"commons-io:commons-io": {
"locked": "2.5",
"requested": "2.5"
},
"io.dropwizard.metrics:metrics-core": {
"locked": "3.2.2",
"requested": "3.2.2"
},
"io.zipkin.brave:brave": {
"locked": "4.0.6",
"requested": "4.0.6"
},
"io.zipkin.java:zipkin": {
"locked": "1.29.2",
"requested": "1.29.2"
},
"javax.validation:validation-api": {
"locked": "2.0.0.CR3",
"requested": "2.0.0.CR3"
},
"junit:junit": {
"locked": "4.12",
"requested": "4.12"
},
"org.apache.cassandra:cassandra-all": {
"locked": "3.11.0",
"requested": "3.11.0"
},
"org.apache.commons:commons-lang3": {
"locked": "3.6",
"requested": "3.6"
},
"org.aspectj:aspectjrt": {
"locked": "1.8.10",
"requested": "1.8.10"
},
"org.aspectj:aspectjweaver": {
"locked": "1.8.10",
"requested": "1.8.10"
},
"org.cassandraunit:cassandra-unit": {
"locked": "3.1.4.0-SNAPSHOT",
"requested": "3.1.4.0-SNAPSHOT"
},
"org.codehaus.jackson:jackson-core-asl": {
"locked": "1.9.13",
"requested": "1.9.13"
},
"org.codehaus.jackson:jackson-mapper-asl": {
"locked": "1.9.13",
"requested": "1.9.13"
},
"org.hamcrest:hamcrest-core": {
"locked": "1.3",
"requested": "1.3"
},
"org.hamcrest:hamcrest-library": {
"locked": "1.3",
"requested": "1.3"
},
"org.mockito:mockito-core": {
"locked": "2.8.47",
"requested": "2.8.47"
},
"org.slf4j:jcl-over-slf4j": {
"locked": "1.7.7",
"requested": "1.7.1"
},
"org.slf4j:slf4j-api": {
"locked": "1.7.25",
"requested": "1.7.1"
},
"org.springframework:spring-core": {
"locked": "4.3.10.RELEASE",
"requested": "4.3.10.RELEASE"
}
},
"testRuntimeClasspath": {
"com.anthemengineering.mojo:infer-maven-plugin": {
"locked": "0.1.0",
"requested": "0.1.0"
},
"com.datastax.cassandra:cassandra-driver-core": {
"locked": "3.3.0",
"requested": "3.3.0"
},
"com.diffplug.durian:durian": {
"locked": "3.5.0-SNAPSHOT",
"requested": "3.+"
},
"com.github.stephenc:jamm": {
"locked": "0.2.5",
"requested": "0.2.5"
},
"com.google.guava:guava": {
"locked": "21.0",
"requested": "20.0"
},
"commons-io:commons-io": {
"locked": "2.5",
"requested": "2.5"
},
"io.dropwizard.metrics:metrics-core": {
"locked": "3.2.2",
"requested": "3.2.2"
},
"io.zipkin.brave:brave": {
"locked": "4.0.6",
"requested": "4.0.6"
},
"io.zipkin.java:zipkin": {
"locked": "1.29.2",
"requested": "1.29.2"
},
"javax.validation:validation-api": {
"locked": "2.0.0.CR3",
"requested": "2.0.0.CR3"
},
"junit:junit": {
"locked": "4.12",
"requested": "4.12"
},
"org.apache.cassandra:cassandra-all": {
"locked": "3.11.0",
"requested": "3.11.0"
},
"org.apache.commons:commons-lang3": {
"locked": "3.6",
"requested": "3.6"
},
"org.aspectj:aspectjrt": {
"locked": "1.8.10",
"requested": "1.8.10"
},
"org.aspectj:aspectjweaver": {
"locked": "1.8.10",
"requested": "1.8.10"
},
"org.cassandraunit:cassandra-unit": {
"locked": "3.1.4.0-SNAPSHOT",
"requested": "3.1.4.0-SNAPSHOT"
},
"org.codehaus.jackson:jackson-core-asl": {
"locked": "1.9.13",
"requested": "1.9.13"
},
"org.codehaus.jackson:jackson-mapper-asl": {
"locked": "1.9.13",
"requested": "1.9.13"
},
"org.hamcrest:hamcrest-core": {
"locked": "1.3",
"requested": "1.3"
},
"org.hamcrest:hamcrest-library": {
"locked": "1.3",
"requested": "1.3"
},
"org.mockito:mockito-core": {
"locked": "2.8.47",
"requested": "2.8.47"
},
"org.slf4j:jcl-over-slf4j": {
"locked": "1.7.7",
"requested": "1.7.1"
},
"org.slf4j:slf4j-api": {
"locked": "1.7.25",
"requested": "1.7.1"
},
"org.springframework:spring-core": {
"locked": "4.3.10.RELEASE",
"requested": "4.3.10.RELEASE"
}
}
}

View file

@ -11,7 +11,7 @@
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Maven: com.datastax.cassandra:cassandra-driver-core:3.3.2" level="project" /> <orderEntry type="library" name="Maven: com.datastax.cassandra:cassandra-driver-core:3.3.0" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-handler:4.0.47.Final" level="project" /> <orderEntry type="library" name="Maven: io.netty:netty-handler:4.0.47.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-buffer:4.0.47.Final" level="project" /> <orderEntry type="library" name="Maven: io.netty:netty-buffer:4.0.47.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-common:4.0.47.Final" level="project" /> <orderEntry type="library" name="Maven: io.netty:netty-common:4.0.47.Final" level="project" />
@ -28,14 +28,15 @@
<orderEntry type="library" name="Maven: com.github.jnr:jnr-x86asm:1.0.2" level="project" /> <orderEntry type="library" name="Maven: com.github.jnr:jnr-x86asm:1.0.2" level="project" />
<orderEntry type="library" name="Maven: com.github.jnr:jnr-posix:3.0.27" level="project" /> <orderEntry type="library" name="Maven: com.github.jnr:jnr-posix:3.0.27" level="project" />
<orderEntry type="library" name="Maven: com.github.jnr:jnr-constants:0.9.0" level="project" /> <orderEntry type="library" name="Maven: com.github.jnr:jnr-constants:0.9.0" level="project" />
<orderEntry type="library" name="Maven: com.datastax.cassandra:cassandra-driver-extras:3.3.2" level="project" />
<orderEntry type="library" name="Maven: com.diffplug.durian:durian:3.4.0" level="project" /> <orderEntry type="library" name="Maven: com.diffplug.durian:durian:3.4.0" level="project" />
<orderEntry type="library" name="Maven: org.aspectj:aspectjweaver:1.8.10" level="project" /> <orderEntry type="library" name="Maven: org.aspectj:aspectjweaver:1.8.10" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.6" level="project" /> <orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.6" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-core:4.3.10.RELEASE" level="project" /> <orderEntry type="library" name="Maven: org.springframework:spring-core:4.3.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: commons-logging:commons-logging:1.2" level="project" /> <orderEntry type="library" name="Maven: commons-logging:commons-logging:1.2" level="project" />
<orderEntry type="library" name="Maven: javax.cache:cache-api:1.1.0" level="project" />
<orderEntry type="library" name="Maven: com.google.guava:guava:20.0" level="project" /> <orderEntry type="library" name="Maven: com.google.guava:guava:20.0" level="project" />
<orderEntry type="library" name="Maven: io.zipkin.java:zipkin:1.29.2" level="project" />
<orderEntry type="library" name="Maven: io.zipkin.brave:brave:4.0.6" level="project" />
<orderEntry type="library" name="Maven: io.zipkin.reporter:zipkin-reporter:0.6.12" level="project" />
<orderEntry type="library" name="Maven: io.dropwizard.metrics:metrics-core:3.2.2" level="project" /> <orderEntry type="library" name="Maven: io.dropwizard.metrics:metrics-core:3.2.2" level="project" />
<orderEntry type="library" name="Maven: javax.validation:validation-api:2.0.0.CR3" level="project" /> <orderEntry type="library" name="Maven: javax.validation:validation-api:2.0.0.CR3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.codehaus.jackson:jackson-mapper-asl:1.9.13" level="project" /> <orderEntry type="library" scope="TEST" name="Maven: org.codehaus.jackson:jackson-mapper-asl:1.9.13" level="project" />
@ -114,9 +115,9 @@
<orderEntry type="library" scope="TEST" name="Maven: org.caffinitas.ohc:ohc-core:0.4.4" level="project" /> <orderEntry type="library" scope="TEST" name="Maven: org.caffinitas.ohc:ohc-core:0.4.4" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.github.ben-manes.caffeine:caffeine:2.2.6" level="project" /> <orderEntry type="library" scope="TEST" name="Maven: com.github.ben-manes.caffeine:caffeine:2.2.6" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.jctools:jctools-core:1.2.1" level="project" /> <orderEntry type="library" scope="TEST" name="Maven: org.jctools:jctools-core:1.2.1" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: ca.exprofesso:guava-jcache:1.0.4" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: commons-io:commons-io:2.5" level="project" /> <orderEntry type="library" scope="TEST" name="Maven: commons-io:commons-io:2.5" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.12" level="project" /> <orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.12" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.github.stephenc:jamm:0.2.5" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-library:1.3" level="project" /> <orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-library:1.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" /> <orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-core:2.8.47" level="project" /> <orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-core:2.8.47" level="project" />

54
pom.xml
View file

@ -109,13 +109,7 @@
<dependency> <dependency>
<groupId>com.datastax.cassandra</groupId> <groupId>com.datastax.cassandra</groupId>
<artifactId>cassandra-driver-core</artifactId> <artifactId>cassandra-driver-core</artifactId>
<version>3.3.2</version> <version>3.3.0</version>
</dependency>
<dependency>
<groupId>com.datastax.cassandra</groupId>
<artifactId>cassandra-driver-extras</artifactId>
<version>3.3.2</version>
</dependency> </dependency>
<dependency> <dependency>
@ -142,19 +136,25 @@
<version>4.3.10.RELEASE</version> <version>4.3.10.RELEASE</version>
</dependency> </dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<version>1.1.0</version>
</dependency>
<dependency> <dependency>
<groupId>com.google.guava</groupId> <groupId>com.google.guava</groupId>
<artifactId>guava</artifactId> <artifactId>guava</artifactId>
<version>20.0</version> <version>20.0</version>
</dependency> </dependency>
<!-- Metrics --> <!-- Metrics and tracing -->
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin</artifactId>
<version>1.29.2</version>
</dependency>
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave</artifactId>
<version>4.0.6</version>
</dependency>
<dependency> <dependency>
<groupId>io.dropwizard.metrics</groupId> <groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-core</artifactId> <artifactId>metrics-core</artifactId>
@ -211,24 +211,6 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>ca.exprofesso</groupId>
<artifactId>guava-jcache</artifactId>
<version>1.0.4</version>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
<exclusion>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>commons-io</groupId> <groupId>commons-io</groupId>
<artifactId>commons-io</artifactId> <artifactId>commons-io</artifactId>
@ -243,6 +225,13 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>com.github.stephenc</groupId>
<artifactId>jamm</artifactId>
<version>0.2.5</version>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.hamcrest</groupId> <groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId> <artifactId>hamcrest-library</artifactId>
@ -277,6 +266,7 @@
<version>1.7.1</version> <version>1.7.1</version>
<scope>runtime</scope> <scope>runtime</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>

1
settings.gradle Normal file
View file

@ -0,0 +1 @@
rootProject.name = 'helenus-core'

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -5,7 +5,7 @@ import com.datastax.driver.core.querybuilder.Select;
public class CreateMaterializedView extends Create { public class CreateMaterializedView extends Create {
private final String viewName; private String viewName;
private Select.Where selection; private Select.Where selection;
private String primaryKey; private String primaryKey;
private String clustering; private String clustering;

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -33,6 +33,6 @@ public abstract class AbstractAuditedEntityDraft<E> extends AbstractEntityDraft<
} }
public Date createdAt() { public Date createdAt() {
return get("createdAt", Date.class); return (Date) get("createdAt", Date.class);
} }
} }

View file

@ -2,36 +2,22 @@ package net.helenus.core;
import com.google.common.primitives.Primitives; import com.google.common.primitives.Primitives;
import java.io.Serializable; import java.io.Serializable;
import java.util.Collection; import java.util.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import net.helenus.core.reflect.DefaultPrimitiveTypes; import net.helenus.core.reflect.DefaultPrimitiveTypes;
import net.helenus.core.reflect.Drafted; import net.helenus.core.reflect.Drafted;
import net.helenus.core.reflect.MapExportable; import net.helenus.core.reflect.MapExportable;
import net.helenus.mapping.HelenusProperty;
import net.helenus.mapping.MappingUtil; import net.helenus.mapping.MappingUtil;
import org.apache.commons.lang3.SerializationUtils; import org.apache.commons.lang3.SerializationUtils;
public abstract class AbstractEntityDraft<E> implements Drafted<E> { public abstract class AbstractEntityDraft<E> implements Drafted<E> {
private final Map<String, Object> backingMap = new HashMap<String, Object>();
private final MapExportable entity; private final MapExportable entity;
private final Map<String, Object> valuesMap; private final Map<String, Object> entityMap;
private final Set<String> readSet;
private final Map<String, Object> mutationsMap = new HashMap<String, Object>();
public AbstractEntityDraft(MapExportable entity) { public AbstractEntityDraft(MapExportable entity) {
this.entity = entity; this.entity = entity;
// Entities can mutate their map. this.entityMap = entity != null ? entity.toMap() : new HashMap<String, Object>();
if (entity != null) {
this.valuesMap = entity.toMap(true);
this.readSet = entity.toReadSet();
} else {
this.valuesMap = new HashMap<String, Object>();
this.readSet = new HashSet<String>();
}
} }
public abstract Class<E> getEntityClass(); public abstract Class<E> getEntityClass();
@ -47,11 +33,10 @@ public abstract class AbstractEntityDraft<E> implements Drafted<E> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> T get(String key, Class<?> returnType) { public <T> T get(String key, Class<?> returnType) {
readSet.add(key); T value = (T) backingMap.get(key);
T value = (T) mutationsMap.get(key);
if (value == null) { if (value == null) {
value = (T) valuesMap.get(key); value = (T) entityMap.get(key);
if (value == null) { if (value == null) {
if (Primitives.allPrimitiveTypes().contains(returnType)) { if (Primitives.allPrimitiveTypes().contains(returnType)) {
@ -64,28 +49,23 @@ public abstract class AbstractEntityDraft<E> implements Drafted<E> {
return (T) type.getDefaultValue(); return (T) type.getDefaultValue();
} }
} else { } else {
// Collections fetched from the valuesMap // Collections fetched from the entityMap
if (value instanceof Collection) { if (value instanceof Collection) {
try {
value = MappingUtil.<T>clone(value);
} catch (CloneNotSupportedException e) {
// TODO(gburd): deep?shallow? copy of List, Map, Set to a mutable collection.
value = (T) SerializationUtils.<Serializable>clone((Serializable) value); value = (T) SerializationUtils.<Serializable>clone((Serializable) value);
} }
} }
} }
}
return value; return value;
} }
public <T> Object set(Getter<T> getter, Object value) { public <T> Object set(Getter<T> getter, Object value) {
HelenusProperty prop = MappingUtil.resolveMappingProperty(getter).getProperty(); return set(this.<T>methodNameFor(getter), value);
String key = prop.getPropertyName();
HelenusValidator.INSTANCE.validate(prop, value);
if (key == null || value == null) {
return null;
}
mutationsMap.put(key, value);
return value;
} }
public Object set(String key, Object value) { public Object set(String key, Object value) {
@ -93,12 +73,12 @@ public abstract class AbstractEntityDraft<E> implements Drafted<E> {
return null; return null;
} }
mutationsMap.put(key, value); backingMap.put(key, value);
return value; return value;
} }
public void put(String key, Object value) { public void put(String key, Object value) {
mutationsMap.put(key, value); backingMap.put(key, value);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -106,22 +86,28 @@ public abstract class AbstractEntityDraft<E> implements Drafted<E> {
return (T) mutate(this.<T>methodNameFor(getter), value); return (T) mutate(this.<T>methodNameFor(getter), value);
} }
public <T> T mutate(String key, T value) { public Object mutate(String key, Object value) {
Objects.requireNonNull(key); Objects.requireNonNull(key);
if (value != null) { if (value == null) {
return null;
}
if (entity != null) { if (entity != null) {
T currentValue = this.<T>fetch(key); Map<String, Object> map = entity.toMap();
if (!value.equals(currentValue)) {
mutationsMap.put(key, value); if (map.containsKey(key) && !value.equals(map.get(key))) {
backingMap.put(key, value);
return value; return value;
} }
return map.get(key);
} else { } else {
mutationsMap.put(key, value); backingMap.put(key, value);
}
}
return null; return null;
} }
}
private <T> String methodNameFor(Getter<T> getter) { private <T> String methodNameFor(Getter<T> getter) {
return MappingUtil.resolveMappingProperty(getter).getProperty().getPropertyName(); return MappingUtil.resolveMappingProperty(getter).getProperty().getPropertyName();
@ -133,8 +119,8 @@ public abstract class AbstractEntityDraft<E> implements Drafted<E> {
public Object unset(String key) { public Object unset(String key) {
if (key != null) { if (key != null) {
Object value = mutationsMap.get(key); Object value = backingMap.get(key);
mutationsMap.put(key, null); backingMap.put(key, null);
return value; return value;
} }
return null; return null;
@ -144,18 +130,10 @@ public abstract class AbstractEntityDraft<E> implements Drafted<E> {
return this.<T>reset(this.<T>methodNameFor(getter), desiredValue); return this.<T>reset(this.<T>methodNameFor(getter), desiredValue);
} }
private <T> T fetch(String key) {
T value = (T) mutationsMap.get(key);
if (value == null) {
value = (T) valuesMap.get(key);
}
return value;
}
public <T> boolean reset(String key, T desiredValue) { public <T> boolean reset(String key, T desiredValue) {
if (key != null && desiredValue != null) { if (key != null && desiredValue != null) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
T currentValue = (T) this.<T>fetch(key); T currentValue = (T) backingMap.get(key);
if (currentValue == null || !currentValue.equals(desiredValue)) { if (currentValue == null || !currentValue.equals(desiredValue)) {
set(key, desiredValue); set(key, desiredValue);
return true; return true;
@ -166,7 +144,7 @@ public abstract class AbstractEntityDraft<E> implements Drafted<E> {
@Override @Override
public Map<String, Object> toMap() { public Map<String, Object> toMap() {
return toMap(valuesMap); return toMap(entityMap);
} }
public Map<String, Object> toMap(Map<String, Object> entityMap) { public Map<String, Object> toMap(Map<String, Object> entityMap) {
@ -177,26 +155,21 @@ public abstract class AbstractEntityDraft<E> implements Drafted<E> {
combined.put(e.getKey(), e.getValue()); combined.put(e.getKey(), e.getValue());
} }
} else { } else {
combined = new HashMap<String, Object>(mutationsMap.size()); combined = new HashMap<String, Object>(backingMap.size());
} }
for (String key : mutated()) { for (String key : mutated()) {
combined.put(key, mutationsMap.get(key)); combined.put(key, backingMap.get(key));
} }
return combined; return combined;
} }
@Override @Override
public Set<String> mutated() { public Set<String> mutated() {
return mutationsMap.keySet(); return backingMap.keySet();
}
@Override
public Set<String> read() {
return readSet;
} }
@Override @Override
public String toString() { public String toString() {
return mutationsMap.toString(); return backingMap.toString();
} }
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +15,7 @@
*/ */
package net.helenus.core; package net.helenus.core;
import brave.Tracer;
import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.MetricRegistry;
import com.datastax.driver.core.*; import com.datastax.driver.core.*;
import com.google.common.base.Stopwatch; import com.google.common.base.Stopwatch;
@ -25,6 +25,7 @@ import java.io.PrintStream;
import java.util.List; import java.util.List;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import net.helenus.core.cache.Facet; import net.helenus.core.cache.Facet;
import net.helenus.core.operation.Operation;
import net.helenus.mapping.value.ColumnValuePreparer; import net.helenus.mapping.value.ColumnValuePreparer;
import net.helenus.mapping.value.ColumnValueProvider; import net.helenus.mapping.value.ColumnValueProvider;
import net.helenus.support.Either; import net.helenus.support.Either;
@ -42,8 +43,6 @@ public abstract class AbstractSessionOperations {
public abstract boolean isShowCql(); public abstract boolean isShowCql();
public abstract boolean showValues();
public abstract PrintStream getPrintStream(); public abstract PrintStream getPrintStream();
public abstract Executor getExecutor(); public abstract Executor getExecutor();
@ -60,6 +59,7 @@ public abstract class AbstractSessionOperations {
public PreparedStatement prepare(RegularStatement statement) { public PreparedStatement prepare(RegularStatement statement) {
try { try {
logStatement(statement, false);
return currentSession().prepare(statement); return currentSession().prepare(statement);
} catch (RuntimeException e) { } catch (RuntimeException e) {
throw translateException(e); throw translateException(e);
@ -68,48 +68,63 @@ public abstract class AbstractSessionOperations {
public ListenableFuture<PreparedStatement> prepareAsync(RegularStatement statement) { public ListenableFuture<PreparedStatement> prepareAsync(RegularStatement statement) {
try { try {
logStatement(statement, false);
return currentSession().prepareAsync(statement); return currentSession().prepareAsync(statement);
} catch (RuntimeException e) { } catch (RuntimeException e) {
throw translateException(e); throw translateException(e);
} }
} }
public ResultSet execute(Statement statement) { public ResultSet execute(Statement statement, boolean showValues) {
return execute(statement, null, null); return execute(statement, null, null, showValues);
} }
public ResultSet execute(Statement statement, Stopwatch timer) { public ResultSet execute(Statement statement, Stopwatch timer, boolean showValues) {
return execute(statement, null, timer); return execute(statement, null, timer, showValues);
} }
public ResultSet execute(Statement statement, UnitOfWork uow) { public ResultSet execute(Statement statement, UnitOfWork uow, boolean showValues) {
return execute(statement, uow, null); return execute(statement, uow, null, showValues);
} }
public ResultSet execute(Statement statement, UnitOfWork uow, Stopwatch timer) { public ResultSet execute(
return executeAsync(statement, uow, timer).getUninterruptibly(); Statement statement, UnitOfWork uow, Stopwatch timer, boolean showValues) {
return executeAsync(statement, uow, timer, showValues).getUninterruptibly();
} }
public ResultSetFuture executeAsync(Statement statement) { public ResultSetFuture executeAsync(Statement statement, boolean showValues) {
return executeAsync(statement, null, null); return executeAsync(statement, null, null, showValues);
} }
public ResultSetFuture executeAsync(Statement statement, Stopwatch timer) { public ResultSetFuture executeAsync(Statement statement, Stopwatch timer, boolean showValues) {
return executeAsync(statement, null, timer); return executeAsync(statement, null, timer, showValues);
} }
public ResultSetFuture executeAsync(Statement statement, UnitOfWork uow) { public ResultSetFuture executeAsync(Statement statement, UnitOfWork uow, boolean showValues) {
return executeAsync(statement, uow, null); return executeAsync(statement, uow, null, showValues);
} }
public ResultSetFuture executeAsync(Statement statement, UnitOfWork uow, Stopwatch timer) { public ResultSetFuture executeAsync(Statement statement, UnitOfWork uow, Stopwatch timer, boolean showValues) {
try { try {
logStatement(statement, showValues);
return currentSession().executeAsync(statement); return currentSession().executeAsync(statement);
} catch (RuntimeException e) { } catch (RuntimeException e) {
throw translateException(e); throw translateException(e);
} }
} }
private void logStatement(Statement statement, boolean showValues) {
if (isShowCql()) {
printCql(Operation.queryString(statement, showValues));
} else if (LOG.isDebugEnabled()) {
LOG.info("CQL> " + Operation.queryString(statement, showValues));
}
}
public Tracer getZipkinTracer() {
return null;
}
public MetricRegistry getMetricRegistry() { public MetricRegistry getMetricRegistry() {
return null; return null;
} }
@ -129,5 +144,12 @@ public abstract class AbstractSessionOperations {
public void updateCache(Object pojo, List<Facet> facets) {} public void updateCache(Object pojo, List<Facet> facets) {}
public void cacheEvict(List<Facet> facets) {} void printCql(String cql) {
getPrintStream().println(cql);
}
public void cacheEvict(List<Facet> facets) {}
public boolean obscureValuesInQueries() { return false; }
} }

View file

@ -0,0 +1,503 @@
/*
* Copyright (C) 2015 The Helenus Authors
*
* 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.helenus.core;
import com.datastax.driver.core.utils.UUIDs;
import com.diffplug.common.base.Errors;
import com.google.common.base.Stopwatch;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import com.google.common.collect.TreeTraverser;
import net.helenus.core.cache.CacheUtil;
import net.helenus.core.cache.Facet;
import net.helenus.core.operation.AbstractOperation;
import net.helenus.core.operation.BatchOperation;
import net.helenus.support.Either;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static net.helenus.core.HelenusSession.deleted;
import static net.helenus.core.Query.gte;
import static net.helenus.core.Query.lt;
/** Encapsulates the concept of a "transaction" as a unit-of-work. */
public abstract class AbstractUnitOfWork<E extends Exception>
implements UnitOfWork<E>, AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(AbstractUnitOfWork.class);
private final List<AbstractUnitOfWork<E>> nested = new ArrayList<>();
private final HelenusSession session;
private final AbstractUnitOfWork<E> parent;
private final UUID id;
private final Table<String, String, Either<Object, List<Facet>>> cache = HashBasedTable.create();
protected String purpose;
protected List<String> nestedPurposes = new ArrayList<String>();
protected String info;
protected int cacheHits = 0;
protected int cacheMisses = 0;
protected int databaseLookups = 0;
protected Stopwatch elapsedTime;
protected Map<String, Double> databaseTime = new HashMap<>();
protected double cacheLookupTime = 0.0;
private List<CommitThunk> postCommit = new ArrayList<CommitThunk>();
private boolean aborted = false;
private boolean committed = false;
private long committedAt = 0L;
private BatchOperation batch;
private WriteAheadLog wal;
private long oldestInFlight;
protected AbstractUnitOfWork(HelenusSession session, AbstractUnitOfWork<E> parent) {
Objects.requireNonNull(session, "containing session cannot be null");
this.session = session;
this.parent = parent;
this.id = UUIDs.random();
this.wal = Helenus.dsl(WriteAheadLog.class);
}
@Override
public void addDatabaseTime(String name, Stopwatch amount) {
Double time = databaseTime.get(name);
if (time == null) {
databaseTime.put(name, (double) amount.elapsed(TimeUnit.MICROSECONDS));
} else {
databaseTime.put(name, time + amount.elapsed(TimeUnit.MICROSECONDS));
}
}
@Override
public void addCacheLookupTime(Stopwatch amount) {
cacheLookupTime += amount.elapsed(TimeUnit.MICROSECONDS);
}
@Override
public void addNestedUnitOfWork(UnitOfWork<E> uow) {
synchronized (nested) {
nested.add((AbstractUnitOfWork<E>) uow);
}
}
@Override
public synchronized UnitOfWork<E> begin() {
if (LOG.isInfoEnabled()) {
elapsedTime = Stopwatch.createStarted();
}
UUID seq = UUIDs.timeBased();
try {
session.upsert(WriteAheadLog.class)
.value(wal::lsn, seq)
.value(wal::uow, id)
.value(wal::type, WriteAheadLog.Type.BEGIN)
.usingTimestamp(seq.timestamp())
.consistencyQuorum()
.sync();
} catch(TimeoutException e) {
aborted = true;
}
/* TODO(gburd): find oldest BEGIN record between: time[now] and time[now] - txn timeout (e.g. 5m ago)
that doesn't have a corresponding COMMITTED or ABORTED record. Save that UUID for later. */
oldestInFlight = seq.timestamp() - (5 * 60 * 1000 * 1000 * 100);
Date d = new Date(oldestInFlight);
return this;
}
@Override
public String getPurpose() {
return purpose;
}
@Override
public UnitOfWork setPurpose(String purpose) {
this.purpose = purpose;
return this;
}
@Override
public void setInfo(String info) {
this.info = info;
}
@Override
public void recordCacheAndDatabaseOperationCount(int cache, int ops) {
if (cache > 0) {
cacheHits += cache;
} else {
cacheMisses += Math.abs(cache);
}
if (ops > 0) {
databaseLookups += ops;
}
}
public String logTimers(String what) {
double e = (double) elapsedTime.elapsed(TimeUnit.MICROSECONDS) / 1000.0;
double d = 0.0;
double c = cacheLookupTime / 1000.0;
double fc = (c / e) * 100.0;
String database = "";
if (databaseTime.size() > 0) {
List<String> dbt = new ArrayList<>(databaseTime.size());
for (Map.Entry<String, Double> dt : databaseTime.entrySet()) {
double t = dt.getValue() / 1000.0;
d += t;
dbt.add(String.format("%s took %,.3fms %,2.2f%%", dt.getKey(), t, (t / e) * 100.0));
}
double fd = (d / e) * 100.0;
database =
String.format(
", %d quer%s (%,.3fms %,2.2f%% - %s)",
databaseLookups, (databaseLookups > 1) ? "ies" : "y", d, fd, String.join(", ", dbt));
}
String cache = "";
if (cacheLookupTime > 0) {
int cacheLookups = cacheHits + cacheMisses;
cache =
String.format(
" with %d cache lookup%s (%,.3fms %,2.2f%% - %,d hit, %,d miss)",
cacheLookups, cacheLookups > 1 ? "s" : "", c, fc, cacheHits, cacheMisses);
}
String da = "";
if (databaseTime.size() > 0 || cacheLookupTime > 0) {
double dat = d + c;
double daf = (dat / e) * 100;
da =
String.format(
" consuming %,.3fms for data access, or %,2.2f%% of total UOW time.", dat, daf);
}
String x = nestedPurposes.stream().distinct().collect(Collectors.joining(", "));
String n =
nested
.stream()
.map(uow -> String.valueOf(uow.hashCode()))
.collect(Collectors.joining(", "));
String s =
String.format(
Locale.US,
"UOW(%s%s) %s in %,.3fms%s%s%s%s%s%s",
hashCode(),
(nested.size() > 0 ? ", [" + n + "]" : ""),
what,
e,
cache,
database,
da,
(purpose == null ? "" : " " + purpose),
(nestedPurposes.isEmpty()) ? "" : ", " + x,
(info == null) ? "" : " " + info);
return s;
}
private void applyPostCommitFunctions() {
if (!postCommit.isEmpty()) {
for (CommitThunk f : postCommit) {
f.apply();
}
}
if (LOG.isInfoEnabled()) {
LOG.info(logTimers("committed"));
}
}
@Override
public Optional<Object> cacheLookup(List<Facet> facets) {
String tableName = CacheUtil.schemaName(facets);
Optional<Object> result = Optional.empty();
for (Facet facet : facets) {
if (!facet.fixed()) {
String columnName = facet.name() + "==" + facet.value();
Either<Object, List<Facet>> eitherValue = cache.get(tableName, columnName);
if (eitherValue != null) {
Object value = deleted;
if (eitherValue.isLeft()) {
value = eitherValue.getLeft();
}
result = Optional.of(value);
break;
}
}
}
if (!result.isPresent()) {
// Be sure to check all enclosing UnitOfWork caches as well, we may be nested.
if (parent != null) {
return parent.cacheLookup(facets);
}
}
return result;
}
@Override
public List<Facet> cacheEvict(List<Facet> facets) {
Either<Object, List<Facet>> deletedObjectFacets = Either.right(facets);
String tableName = CacheUtil.schemaName(facets);
Optional<Object> optionalValue = cacheLookup(facets);
if (optionalValue.isPresent()) {
Object value = optionalValue.get();
for (Facet facet : facets) {
if (!facet.fixed()) {
String columnKey = facet.name() + "==" + facet.value();
// mark the value identified by the facet to `deleted`
cache.put(tableName, columnKey, deletedObjectFacets);
}
}
// look for other row/col pairs that referenced the same object, mark them
// `deleted`
cache
.columnKeySet()
.forEach(
columnKey -> {
Either<Object, List<Facet>> eitherCachedValue = cache.get(tableName, columnKey);
if (eitherCachedValue.isLeft()) {
Object cachedValue = eitherCachedValue.getLeft();
if (cachedValue == value) {
cache.put(tableName, columnKey, deletedObjectFacets);
String[] parts = columnKey.split("==");
facets.add(new Facet<String>(parts[0], parts[1]));
}
}
});
}
return facets;
}
@Override
public void cacheUpdate(Object value, List<Facet> facets) {
String tableName = CacheUtil.schemaName(facets);
for (Facet facet : facets) {
if (!facet.fixed()) {
if (facet.alone()) {
String columnName = facet.name() + "==" + facet.value();
cache.put(tableName, columnName, Either.left(value));
}
}
}
}
public void batch(AbstractOperation s) {
if (batch == null) {
batch = new BatchOperation(session);
}
batch.add(s);
}
private Iterator<AbstractUnitOfWork<E>> getChildNodes() {
return nested.iterator();
}
/**
* Checks to see if the work performed between calling begin and now can be committed or not.
*
* @return a function from which to chain work that only happens when commit is successful
* @throws E when the work overlaps with other concurrent writers.
*/
public PostCommitFunction<Void, Void> commit() throws E, TimeoutException {
if (batch != null) {
committedAt = batch.sync(this);
}
// All nested UnitOfWork should be committed (not aborted) before calls to
// commit, check.
boolean canCommit = true;
TreeTraverser<AbstractUnitOfWork<E>> traverser =
TreeTraverser.using(node -> node::getChildNodes);
for (AbstractUnitOfWork<E> uow : traverser.postOrderTraversal(this)) {
if (this != uow) {
canCommit &= (!uow.aborted && uow.committed);
}
}
// 1. log.record(txn::provisionalCommit)
UUID seqPrep = UUIDs.timeBased();
try {
UUID seq = seqPrep;
session.upsert(WriteAheadLog.class)
.value(wal::lsn, seq)
.value(wal::uow, id)
.value(wal::type, WriteAheadLog.Type.PREPARED)
.usingTimestamp(seq.timestamp())
.consistencyQuorum()
.sync();
} catch (TimeoutException e) {
canCommit = false;
aborted = true;
}
// 2. fetch log records between oldest in-flight txn begin and
Stream<WriteAheadLog> recs = session.select(WriteAheadLog.class)
.where(wal::lsn, gte(oldestInFlight))
.and(wal::lsn, lt(seqPrep))
.consistencyQuorum()
.sync();
// examine log for conflicts in read-set and write-set between begin and
// provisional commit
// if (conflict) { throw new ConflictingUnitOfWorkException(this) }
UUID seqCommit = UUIDs.timeBased();
try {
UUID seq = seqCommit;
session.upsert(WriteAheadLog.class)
.value(wal::lsn, seq)
.value(wal::uow, id)
.value(wal::type, WriteAheadLog.Type.COMMITTED)
.usingTimestamp(seq.timestamp())
.consistencyQuorum()
.sync();
} catch (TimeoutException e) {
canCommit = false;
aborted = true;
}
// else return function so as to enable commit.andThen(() -> { do something iff
// commit was successful; })
if (canCommit) {
committed = true;
aborted = false;
nested.forEach((uow) -> Errors.rethrow().wrap(uow::commit));
elapsedTime.stop();
if (parent == null) {
// Apply all post-commit functions, this is the outter-most UnitOfWork.
traverser
.postOrderTraversal(this)
.forEach(
uow -> {
uow.applyPostCommitFunctions();
});
// Merge our cache into the session cache.
session.mergeCache(cache);
return new PostCommitFunction(this, null);
} else {
// Merge cache and statistics into parent if there is one.
parent.mergeCache(cache);
parent.addBatched(batch);
if (purpose != null) {
parent.nestedPurposes.add(purpose);
}
parent.cacheHits += cacheHits;
parent.cacheMisses += cacheMisses;
parent.databaseLookups += databaseLookups;
parent.cacheLookupTime += cacheLookupTime;
for (Map.Entry<String, Double> dt : databaseTime.entrySet()) {
String name = dt.getKey();
if (parent.databaseTime.containsKey(name)) {
double t = parent.databaseTime.get(name);
parent.databaseTime.put(name, t + dt.getValue());
} else {
parent.databaseTime.put(name, dt.getValue());
}
}
}
}
// else {
// Constructor<T> ctor = clazz.getConstructor(conflictExceptionClass);
// T object = ctor.newInstance(new Object[] { String message });
// }
return new PostCommitFunction(this, postCommit);
}
private void addBatched(BatchOperation batch) {
if (this.batch == null) {
this.batch = batch;
} else {
this.batch.addAll(batch);
}
}
/* Explicitly discard the work and mark it as as such in the log. */
public synchronized void abort() {
TreeTraverser<AbstractUnitOfWork<E>> traverser =
TreeTraverser.using(node -> node::getChildNodes);
traverser
.postOrderTraversal(this)
.forEach(
uow -> {
uow.committed = false;
uow.aborted = true;
});
// log.record(txn::abort)
// cache.invalidateSince(txn::start time)
if (LOG.isInfoEnabled()) {
if (elapsedTime.isRunning()) {
elapsedTime.stop();
}
LOG.info(logTimers("aborted"));
}
}
private void mergeCache(Table<String, String, Either<Object, List<Facet>>> from) {
Table<String, String, Either<Object, List<Facet>>> to = this.cache;
from.rowMap()
.forEach(
(rowKey, columnMap) -> {
columnMap.forEach(
(columnKey, value) -> {
if (to.contains(rowKey, columnKey)) {
// TODO(gburd): merge case, preserve object identity
to.put(
rowKey,
columnKey,
Either.left(
CacheUtil.merge(
to.get(rowKey, columnKey).getLeft(),
from.get(rowKey, columnKey).getLeft())));
} else {
to.put(rowKey, columnKey, from.get(rowKey, columnKey));
}
});
});
}
public String describeConflicts() {
return "it's complex...";
}
@Override
public void close() throws E {
// Closing a AbstractUnitOfWork will abort iff we've not already aborted or
// committed this unit of work.
if (aborted == false && committed == false) {
abort();
}
}
public boolean hasAborted() {
return aborted;
}
public boolean hasCommitted() {
return committed;
}
public long committedAt() { return committedAt; }
}

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -0,0 +1,6 @@
package net.helenus.core;
@FunctionalInterface
public interface CommitThunk {
void apply();
}

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -80,8 +79,7 @@ public final class Filter<V> {
return new Filter<V>(node, postulate); return new Filter<V>(node, postulate);
} }
public static <V> Filter<V> create( public static <V> Filter<V> create(Getter<V> getter, HelenusPropertyNode node, Postulate<V> postulate) {
Getter<V> getter, HelenusPropertyNode node, Postulate<V> postulate) {
Objects.requireNonNull(getter, "empty getter"); Objects.requireNonNull(getter, "empty getter");
Objects.requireNonNull(postulate, "empty operator"); Objects.requireNonNull(postulate, "empty operator");
return new Filter<V>(node, postulate); return new Filter<V>(node, postulate);

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -82,10 +81,6 @@ public final class Helenus {
return new SessionInitializer(session); return new SessionInitializer(session);
} }
public static SessionInitializer init(Session session, String keyspace) {
return new SessionInitializer(session, keyspace);
}
public static SessionInitializer init(Session session) { public static SessionInitializer init(Session session) {
if (session == null) { if (session == null) {

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,19 +17,23 @@ package net.helenus.core;
import static net.helenus.core.Query.eq; import static net.helenus.core.Query.eq;
import brave.Tracer;
import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.MetricRegistry;
import com.datastax.driver.core.*; import com.datastax.driver.core.*;
import com.google.common.collect.Table; import com.google.common.collect.Table;
import java.io.Closeable; import java.io.Closeable;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.*; import java.util.*;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.function.Function; import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.cache.Cache;
import javax.cache.CacheManager;
import net.helenus.core.cache.CacheUtil; import net.helenus.core.cache.CacheUtil;
import net.helenus.core.cache.Facet; import net.helenus.core.cache.Facet;
import net.helenus.core.cache.SessionCache;
import net.helenus.core.cache.UnboundFacet; import net.helenus.core.cache.UnboundFacet;
import net.helenus.core.operation.*; import net.helenus.core.operation.*;
import net.helenus.core.reflect.Drafted; import net.helenus.core.reflect.Drafted;
@ -44,69 +47,77 @@ import net.helenus.support.*;
import net.helenus.support.Fun.Tuple1; import net.helenus.support.Fun.Tuple1;
import net.helenus.support.Fun.Tuple2; import net.helenus.support.Fun.Tuple2;
import net.helenus.support.Fun.Tuple6; import net.helenus.support.Fun.Tuple6;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelenusSession extends AbstractSessionOperations implements Closeable { public class HelenusSession extends AbstractSessionOperations implements Closeable {
public static final Object deleted = new Object(); public static final Object deleted = new Object();
private static final Logger LOG = LoggerFactory.getLogger(HelenusSession.class);
private static final Pattern classNameRegex =
Pattern.compile("^(?:\\w+\\.)+(?:(\\w+)|(\\w+)\\$.*)$");
private final Session session; private final Session session;
private final CodecRegistry registry; private final CodecRegistry registry;
private final ConsistencyLevel defaultConsistencyLevel; private final ConsistencyLevel defaultConsistencyLevel;
private final boolean defaultQueryIdempotency; private final boolean defaultQueryIdempotency;
private final MetricRegistry metricRegistry; private final MetricRegistry metricRegistry;
private final Tracer zipkinTracer;
private final PrintStream printStream; private final PrintStream printStream;
private final Class<? extends UnitOfWork> unitOfWorkClass;
private final SessionRepository sessionRepository; private final SessionRepository sessionRepository;
private final Executor executor; private final Executor executor;
private final boolean dropSchemaOnClose; private final boolean dropSchemaOnClose;
private final CacheManager cacheManager; private final SessionCache<String, Object> sessionCache;
private final RowColumnValueProvider valueProvider; private final RowColumnValueProvider valueProvider;
private final StatementColumnValuePreparer valuePreparer; private final StatementColumnValuePreparer valuePreparer;
private final Metadata metadata; private final Metadata metadata;
private final boolean obscureValuesInQueries;
private volatile String usingKeyspace; private volatile String usingKeyspace;
private volatile boolean showCql; private volatile boolean showCql;
private volatile boolean showValues;
HelenusSession( HelenusSession(
Session session, Session session,
String usingKeyspace, String usingKeyspace,
CodecRegistry registry, CodecRegistry registry,
boolean showCql, boolean showCql,
boolean showValues, boolean obscureValues,
PrintStream printStream, PrintStream printStream,
SessionRepositoryBuilder sessionRepositoryBuilder, SessionRepositoryBuilder sessionRepositoryBuilder,
Executor executor, Executor executor,
boolean dropSchemaOnClose, boolean dropSchemaOnClose,
ConsistencyLevel consistencyLevel, ConsistencyLevel consistencyLevel,
boolean defaultQueryIdempotency, boolean defaultQueryIdempotency,
CacheManager cacheManager, Class<? extends UnitOfWork> unitOfWorkClass,
MetricRegistry metricRegistry) { SessionCache sessionCache,
MetricRegistry metricRegistry,
Tracer tracer) {
this.session = session; this.session = session;
this.registry = registry == null ? CodecRegistry.DEFAULT_INSTANCE : registry; this.registry = registry == null ? CodecRegistry.DEFAULT_INSTANCE : registry;
this.usingKeyspace = this.usingKeyspace =
Objects.requireNonNull( Objects.requireNonNull(
usingKeyspace, "keyspace needs to be selected before creating session"); usingKeyspace, "keyspace needs to be selected before creating session");
this.showCql = showCql; this.showCql = showCql;
this.showValues = showValues; this.obscureValuesInQueries = obscureValues;
this.printStream = printStream; this.printStream = printStream;
this.sessionRepository = this.sessionRepository = sessionRepositoryBuilder.build();
sessionRepositoryBuilder == null ? null : sessionRepositoryBuilder.build();
this.executor = executor; this.executor = executor;
this.dropSchemaOnClose = dropSchemaOnClose; this.dropSchemaOnClose = dropSchemaOnClose;
this.defaultConsistencyLevel = consistencyLevel; this.defaultConsistencyLevel = consistencyLevel;
this.defaultQueryIdempotency = defaultQueryIdempotency; this.defaultQueryIdempotency = defaultQueryIdempotency;
this.unitOfWorkClass = unitOfWorkClass;
this.metricRegistry = metricRegistry; this.metricRegistry = metricRegistry;
this.cacheManager = cacheManager; this.zipkinTracer = tracer;
if (sessionCache == null) {
this.sessionCache = SessionCache.<String, Object>defaultCache();
} else {
this.sessionCache = sessionCache;
}
this.valueProvider = new RowColumnValueProvider(this.sessionRepository); this.valueProvider = new RowColumnValueProvider(this.sessionRepository);
this.valuePreparer = new StatementColumnValuePreparer(this.sessionRepository); this.valuePreparer = new StatementColumnValuePreparer(this.sessionRepository);
this.metadata = session == null ? null : session.getCluster().getMetadata(); this.metadata = session.getCluster().getMetadata();
}
public UnitOfWork begin() {
return new UnitOfWork(this).begin();
}
public UnitOfWork begin(UnitOfWork parent) {
return new UnitOfWork(this, parent).begin();
} }
@Override @Override
@ -125,6 +136,9 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
return this; return this;
} }
@Override
public boolean obscureValuesInQueries() { return obscureValuesInQueries; }
@Override @Override
public boolean isShowCql() { public boolean isShowCql() {
return showCql; return showCql;
@ -145,20 +159,6 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
return this; return this;
} }
public HelenusSession showQueryValuesInLog(boolean showValues) {
this.showValues = showValues;
return this;
}
public HelenusSession showQueryValuesInLog() {
this.showValues = true;
return this;
}
public boolean showValues() {
return showValues;
}
@Override @Override
public Executor getExecutor() { public Executor getExecutor() {
return executor; return executor;
@ -179,6 +179,11 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
return valuePreparer; return valuePreparer;
} }
@Override
public Tracer getZipkinTracer() {
return zipkinTracer;
}
@Override @Override
public MetricRegistry getMetricRegistry() { public MetricRegistry getMetricRegistry() {
return metricRegistry; return metricRegistry;
@ -197,29 +202,19 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
@Override @Override
public Object checkCache(String tableName, List<Facet> facets) { public Object checkCache(String tableName, List<Facet> facets) {
Object result = null; Object result = null;
if (cacheManager != null) {
Cache<String, Object> cache = cacheManager.getCache(tableName);
if (cache != null) {
for (String key : CacheUtil.flatKeys(tableName, facets)) { for (String key : CacheUtil.flatKeys(tableName, facets)) {
result = cache.get(key); result = sessionCache.get(key);
if (result != null) { if (result != null) {
return result; return result;
} }
} }
}
}
return null; return null;
} }
@Override @Override
public void cacheEvict(List<Facet> facets) { public void cacheEvict(List<Facet> facets) {
if (cacheManager != null) {
String tableName = CacheUtil.schemaName(facets); String tableName = CacheUtil.schemaName(facets);
Cache<String, Object> cache = cacheManager.getCache(tableName); CacheUtil.flatKeys(tableName, facets).forEach(key -> sessionCache.invalidate(key));
if (cache != null) {
CacheUtil.flatKeys(tableName, facets).forEach(key -> cache.remove(key));
}
}
} }
@Override @Override
@ -257,7 +252,6 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
@Override @Override
public void mergeCache(Table<String, String, Either<Object, List<Facet>>> uowCache) { public void mergeCache(Table<String, String, Either<Object, List<Facet>>> uowCache) {
if (cacheManager != null) {
List<Object> items = List<Object> items =
uowCache uowCache
.values() .values()
@ -313,40 +307,91 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
.collect(Collectors.toList()); .collect(Collectors.toList());
for (List<Facet> facets : deletedFacetSets) { for (List<Facet> facets : deletedFacetSets) {
String tableName = CacheUtil.schemaName(facets); String tableName = CacheUtil.schemaName(facets);
Cache<String, Object> cache = cacheManager.getCache(tableName);
if (cache != null) {
List<String> keys = CacheUtil.flatKeys(tableName, facets); List<String> keys = CacheUtil.flatKeys(tableName, facets);
keys.forEach(key -> cache.remove(key)); keys.forEach(key -> sessionCache.invalidate(key));
}
}
} }
} }
private void replaceCachedFacetValues( private void replaceCachedFacetValues(
Object pojo, String tableName, List<String[]> facetCombinations) { Object pojo, String tableName, List<String[]> facetCombinations) {
if (cacheManager != null) {
for (String[] combination : facetCombinations) { for (String[] combination : facetCombinations) {
String cacheKey = tableName + "." + Arrays.toString(combination); String cacheKey = tableName + "." + Arrays.toString(combination);
Cache<String, Object> cache = cacheManager.getCache(tableName);
if (cache != null) {
if (pojo == null || pojo == HelenusSession.deleted) { if (pojo == null || pojo == HelenusSession.deleted) {
cache.remove(cacheKey); sessionCache.invalidate(cacheKey);
} else { } else {
cache.put(cacheKey, pojo); sessionCache.put(cacheKey, pojo);
} }
} }
} }
}
}
public CacheManager getCacheManager() {
return cacheManager;
}
public Metadata getMetadata() { public Metadata getMetadata() {
return metadata; return metadata;
} }
public UnitOfWork begin() {
return this.begin(null);
}
private String extractClassNameFromStackFrame(String classNameOnStack) {
String name = null;
Matcher m = classNameRegex.matcher(classNameOnStack);
if (m.find()) {
name = (m.group(1) != null) ? m.group(1) : ((m.group(2) != null) ? m.group(2) : name);
} else {
name = classNameOnStack;
}
return name;
}
public synchronized UnitOfWork begin(UnitOfWork parent) {
try {
Class<? extends UnitOfWork> clazz = unitOfWorkClass;
Constructor<? extends UnitOfWork> ctor =
clazz.getConstructor(HelenusSession.class, UnitOfWork.class);
UnitOfWork uow = ctor.newInstance(this, parent);
if (LOG.isInfoEnabled() && uow.getPurpose() == null) {
StringBuilder purpose = null;
int frame = 0;
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
String targetClassName = HelenusSession.class.getSimpleName();
String stackClassName = null;
do {
frame++;
stackClassName = extractClassNameFromStackFrame(trace[frame].getClassName());
} while (!stackClassName.equals(targetClassName) && frame < trace.length);
do {
frame++;
stackClassName = extractClassNameFromStackFrame(trace[frame].getClassName());
} while (stackClassName.equals(targetClassName) && frame < trace.length);
if (frame < trace.length) {
purpose =
new StringBuilder()
.append(trace[frame].getClassName())
.append(".")
.append(trace[frame].getMethodName())
.append("(")
.append(trace[frame].getFileName())
.append(":")
.append(trace[frame].getLineNumber())
.append(")");
uow.setPurpose(purpose.toString());
}
}
if (parent != null) {
parent.addNestedUnitOfWork(uow);
}
return uow.begin();
} catch (NoSuchMethodException
| InvocationTargetException
| InstantiationException
| IllegalAccessException e) {
throw new HelenusException(
String.format(
"Unable to instantiate %s as a UnitOfWork.", unitOfWorkClass.getSimpleName()),
e);
}
}
public <E> SelectOperation<E> select(E pojo) { public <E> SelectOperation<E> select(E pojo) {
Objects.requireNonNull( Objects.requireNonNull(
pojo, "supplied object must be a dsl for a registered entity but cannot be null"); pojo, "supplied object must be a dsl for a registered entity but cannot be null");
@ -381,17 +426,9 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
return new SelectOperation<Fun.ArrayTuple>(this); return new SelectOperation<Fun.ArrayTuple>(this);
} }
public <E> SelectOperation<E> selectAll(Class<E> entityClass) { public SelectOperation<Row> selectAll(Class<?> entityClass) {
Objects.requireNonNull(entityClass, "entityClass is empty"); Objects.requireNonNull(entityClass, "entityClass is empty");
HelenusEntity entity = Helenus.entity(entityClass); return new SelectOperation<Row>(this, Helenus.entity(entityClass));
return new SelectOperation<E>(
this,
entity,
(r) -> {
Map<String, Object> map = new ValueProviderMap(r, valueProvider, entity);
return (E) Helenus.map(entityClass, map);
});
} }
public <E> SelectOperation<Row> selectAll(E pojo) { public <E> SelectOperation<Row> selectAll(E pojo) {
@ -411,8 +448,7 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
Objects.requireNonNull(getter1, "field 1 is empty"); Objects.requireNonNull(getter1, "field 1 is empty");
HelenusPropertyNode p1 = MappingUtil.resolveMappingProperty(getter1); HelenusPropertyNode p1 = MappingUtil.resolveMappingProperty(getter1);
return new SelectOperation<Tuple1<V1>>( return new SelectOperation<Tuple1<V1>>(this, new Mappers.Mapper1<V1>(getValueProvider(), p1), p1);
this, new Mappers.Mapper1<V1>(getValueProvider(), p1), p1);
} }
public <V1, V2> SelectOperation<Tuple2<V1, V2>> select(Getter<V1> getter1, Getter<V2> getter2) { public <V1, V2> SelectOperation<Tuple2<V1, V2>> select(Getter<V1> getter1, Getter<V2> getter2) {
@ -421,8 +457,7 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
HelenusPropertyNode p1 = MappingUtil.resolveMappingProperty(getter1); HelenusPropertyNode p1 = MappingUtil.resolveMappingProperty(getter1);
HelenusPropertyNode p2 = MappingUtil.resolveMappingProperty(getter2); HelenusPropertyNode p2 = MappingUtil.resolveMappingProperty(getter2);
return new SelectOperation<Fun.Tuple2<V1, V2>>( return new SelectOperation<Fun.Tuple2<V1, V2>>(this, new Mappers.Mapper2<V1, V2>(getValueProvider(), p1, p2), p1, p2);
this, new Mappers.Mapper2<V1, V2>(getValueProvider(), p1, p2), p1, p2);
} }
public <V1, V2, V3> SelectOperation<Fun.Tuple3<V1, V2, V3>> select( public <V1, V2, V3> SelectOperation<Fun.Tuple3<V1, V2, V3>> select(
@ -666,21 +701,21 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
if (entity != null) { if (entity != null) {
return new InsertOperation<T>(this, entity, entity.getMappingInterface(), true); return new InsertOperation<T>(this, entity, entity.getMappingInterface(), true);
} else { } else {
return this.<T>insert(pojo, null, null); return this.<T>insert(pojo, null);
} }
} }
public <T> InsertOperation<T> insert(Drafted draft) { public <T> InsertOperation<T> insert(Drafted draft) {
return insert(draft.build(), draft.mutated(), draft.read()); return insert(draft.build(), draft.mutated());
} }
private <T> InsertOperation<T> insert(T pojo, Set<String> mutations, Set<String> read) { private <T> InsertOperation<T> insert(T pojo, Set<String> mutations) {
Objects.requireNonNull(pojo, "pojo is empty"); Objects.requireNonNull(pojo, "pojo is empty");
Class<?> iface = MappingUtil.getMappingInterface(pojo); Class<?> iface = MappingUtil.getMappingInterface(pojo);
HelenusEntity entity = Helenus.entity(iface); HelenusEntity entity = Helenus.entity(iface);
return new InsertOperation<T>(this, entity, pojo, mutations, read, true); return new InsertOperation<T>(this, entity, pojo, mutations, true);
} }
public InsertOperation<ResultSet> upsert() { public InsertOperation<ResultSet> upsert() {
@ -692,12 +727,11 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
} }
public <T> InsertOperation<T> upsert(Drafted draft) { public <T> InsertOperation<T> upsert(Drafted draft) {
return this.<T>upsert((T) draft.build(), draft.mutated(), draft.read()); return this.<T>upsert((T) draft.build(), draft.mutated());
} }
public <T> InsertOperation<T> upsert(T pojo) { public <T> InsertOperation<T> upsert(T pojo) {
Objects.requireNonNull( Objects.requireNonNull(pojo,
pojo,
"supplied object must be either an instance of the entity class or a dsl for it, but cannot be null"); "supplied object must be either an instance of the entity class or a dsl for it, but cannot be null");
HelenusEntity entity = null; HelenusEntity entity = null;
try { try {
@ -707,17 +741,17 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
if (entity != null) { if (entity != null) {
return new InsertOperation<T>(this, entity, entity.getMappingInterface(), false); return new InsertOperation<T>(this, entity, entity.getMappingInterface(), false);
} else { } else {
return this.<T>upsert(pojo, null, null); return this.<T>upsert(pojo, null);
} }
} }
private <T> InsertOperation<T> upsert(T pojo, Set<String> mutations, Set<String> read) { private <T> InsertOperation<T> upsert(T pojo, Set<String> mutations) {
Objects.requireNonNull(pojo, "pojo is empty"); Objects.requireNonNull(pojo, "pojo is empty");
Class<?> iface = MappingUtil.getMappingInterface(pojo); Class<?> iface = MappingUtil.getMappingInterface(pojo);
HelenusEntity entity = Helenus.entity(iface); HelenusEntity entity = Helenus.entity(iface);
return new InsertOperation<T>(this, entity, pojo, mutations, read, false); return new InsertOperation<T>(this, entity, pojo, mutations, false);
} }
public DeleteOperation delete() { public DeleteOperation delete() {
@ -738,9 +772,6 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
} }
public void close() { public void close() {
if (session == null) {
return;
}
if (session.isClosed()) { if (session.isClosed()) {
return; return;
@ -771,11 +802,11 @@ public class HelenusSession extends AbstractSessionOperations implements Closeab
switch (entity.getType()) { switch (entity.getType()) {
case TABLE: case TABLE:
execute(SchemaUtil.dropTable(entity)); execute(SchemaUtil.dropTable(entity), true);
break; break;
case UDT: case UDT:
execute(SchemaUtil.dropUserType(entity)); execute(SchemaUtil.dropUserType(entity), true);
break; break;
default: default:

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -2,74 +2,25 @@ package net.helenus.core;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import net.helenus.support.CheckedRunnable;
public class PostCommitFunction<T, R> implements java.util.function.Function<T, R> { public class PostCommitFunction<T, R> implements java.util.function.Function<T, R> {
public static final PostCommitFunction<Void, Void> NULL_ABORT = new PostCommitFunction<Void, Void>(null, null, null, false);
public static final PostCommitFunction<Void, Void> NULL_COMMIT = new PostCommitFunction<Void, Void>(null, null, null, true);
private final List<CheckedRunnable> commitThunks; private final UnitOfWork uow;
private final List<CheckedRunnable> abortThunks; private final List<CommitThunk> postCommit;
private Consumer<? super Throwable> exceptionallyThunk;
private boolean committed;
PostCommitFunction(List<CheckedRunnable> postCommit, List<CheckedRunnable> abortThunks, PostCommitFunction(UnitOfWork uow, List<CommitThunk> postCommit) {
Consumer<? super Throwable> exceptionallyThunk, this.uow = uow;
boolean committed) { this.postCommit = postCommit;
this.commitThunks = postCommit;
this.abortThunks = abortThunks;
this.exceptionallyThunk = exceptionallyThunk;
this.committed = committed;
} }
private void apply(CheckedRunnable... fns) { public void andThen(CommitThunk after) {
try {
for (CheckedRunnable fn : fns) {
fn.run();
}
} catch (Throwable t) {
if (exceptionallyThunk != null) {
exceptionallyThunk.accept(t);
}
}
}
public PostCommitFunction<T, R> andThen(CheckedRunnable... after) {
Objects.requireNonNull(after); Objects.requireNonNull(after);
if (commitThunks == null) { if (postCommit == null) {
if (committed) { after.apply();
apply(after);
}
} else { } else {
for (CheckedRunnable fn : after) { postCommit.add(after);
commitThunks.add(fn);
} }
} }
return this;
}
public PostCommitFunction<T, R> orElse(CheckedRunnable... after) {
Objects.requireNonNull(after);
if (abortThunks == null) {
if (!committed) {
apply(after);
}
} else {
for (CheckedRunnable fn : after) {
abortThunks.add(fn);
}
}
return this;
}
public PostCommitFunction<T, R> exceptionally(Consumer<? super Throwable> fn) {
Objects.requireNonNull(fn);
exceptionallyThunk = fn;
return this;
}
@Override @Override
public R apply(T t) { public R apply(T t) {

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -338,7 +337,7 @@ public final class SchemaUtil {
public static SchemaStatement createIndex(HelenusProperty prop) { public static SchemaStatement createIndex(HelenusProperty prop) {
if (prop.caseSensitiveIndex()) { if (prop.caseSensitiveIndex()) {
return SchemaBuilder.createIndex(indexName(prop)) return SchemaBuilder.createIndex(prop.getIndexName().get().toCql())
.ifNotExists() .ifNotExists()
.onTable(prop.getEntity().getName().toCql()) .onTable(prop.getEntity().getName().toCql())
.andColumn(prop.getColumnName().toCql()); .andColumn(prop.getColumnName().toCql());
@ -407,7 +406,7 @@ public final class SchemaUtil {
} }
public static SchemaStatement dropIndex(HelenusProperty prop) { public static SchemaStatement dropIndex(HelenusProperty prop) {
return SchemaBuilder.dropIndex(indexName(prop)).ifExists(); return SchemaBuilder.dropIndex(prop.getIndexName().get().toCql()).ifExists();
} }
private static SchemaBuilder.Direction mapDirection(OrderingDirection o) { private static SchemaBuilder.Direction mapDirection(OrderingDirection o) {
@ -466,9 +465,4 @@ public final class SchemaUtil {
} }
return null; return null;
} }
private static String indexName(HelenusProperty prop) {
return prop.getEntity().getName().toCql() + "_" + prop.getIndexName().get().toCql();
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +15,7 @@
*/ */
package net.helenus.core; package net.helenus.core;
import brave.Tracer;
import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.MetricRegistry;
import com.datastax.driver.core.*; import com.datastax.driver.core.*;
import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.MoreExecutors;
@ -25,7 +25,9 @@ import java.util.*;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.function.Consumer; import java.util.function.Consumer;
import javax.cache.CacheManager;
import net.helenus.core.annotation.Transactional;
import net.helenus.core.cache.SessionCache;
import net.helenus.core.reflect.DslExportable; import net.helenus.core.reflect.DslExportable;
import net.helenus.mapping.HelenusEntity; import net.helenus.mapping.HelenusEntity;
import net.helenus.mapping.HelenusEntityType; import net.helenus.mapping.HelenusEntityType;
@ -43,26 +45,20 @@ public final class SessionInitializer extends AbstractSessionOperations {
private CodecRegistry registry; private CodecRegistry registry;
private String usingKeyspace; private String usingKeyspace;
private boolean showCql = false; private boolean showCql = false;
private boolean showValues = true;
private ConsistencyLevel consistencyLevel; private ConsistencyLevel consistencyLevel;
private boolean idempotent = false; private boolean idempotent = true;
private MetricRegistry metricRegistry = new MetricRegistry(); private MetricRegistry metricRegistry = new MetricRegistry();
private Tracer zipkinTracer;
private PrintStream printStream = System.out; private PrintStream printStream = System.out;
private Executor executor = MoreExecutors.directExecutor(); private Executor executor = MoreExecutors.directExecutor();
private Class<? extends UnitOfWork> unitOfWorkClass = UnitOfWorkImpl.class;
private SessionRepositoryBuilder sessionRepository; private SessionRepositoryBuilder sessionRepository;
private boolean dropUnusedColumns = false; private boolean dropUnusedColumns = false;
private boolean dropUnusedIndexes = false; private boolean dropUnusedIndexes = false;
private KeyspaceMetadata keyspaceMetadata; private KeyspaceMetadata keyspaceMetadata;
private AutoDdl autoDdl = AutoDdl.UPDATE; private AutoDdl autoDdl = AutoDdl.UPDATE;
private CacheManager cacheManager = null; private SessionCache sessionCache = null;
private boolean obscureValues = true;
SessionInitializer(Session session, String keyspace) {
this.session = session;
this.usingKeyspace = keyspace;
if (session != null) {
this.sessionRepository = new SessionRepositoryBuilder(session);
}
}
SessionInitializer(Session session) { SessionInitializer(Session session) {
this.session = Objects.requireNonNull(session, "empty session"); this.session = Objects.requireNonNull(session, "empty session");
@ -110,32 +106,38 @@ public final class SessionInitializer extends AbstractSessionOperations {
return this; return this;
} }
public SessionInitializer showQueryValuesInLog(boolean showValues) { public SessionInitializer obscureValuesWhenLoggingQueries() {
this.showValues = showValues; this.obscureValues = true;
return this; return this;
} }
public SessionInitializer showQueryValuesInLog() { public SessionInitializer obscureValuesWhenLoggingQueries(boolean obscureValues) {
this.showValues = true; this.obscureValues = obscureValues;
return this; return this;
} }
public boolean showValues() {
return showValues;
}
public SessionInitializer metricRegistry(MetricRegistry metricRegistry) { public SessionInitializer metricRegistry(MetricRegistry metricRegistry) {
this.metricRegistry = metricRegistry; this.metricRegistry = metricRegistry;
return this; return this;
} }
public SessionInitializer zipkinTracer(Tracer tracer) {
this.zipkinTracer = tracer;
return this;
}
public SessionInitializer setUnitOfWorkClass(Class<? extends UnitOfWork> e) {
this.unitOfWorkClass = e;
return this;
}
public SessionInitializer consistencyLevel(ConsistencyLevel consistencyLevel) { public SessionInitializer consistencyLevel(ConsistencyLevel consistencyLevel) {
this.consistencyLevel = consistencyLevel; this.consistencyLevel = consistencyLevel;
return this; return this;
} }
public SessionInitializer setCacheManager(CacheManager cacheManager) { public SessionInitializer setSessionCache(SessionCache sessionCache) {
this.cacheManager = cacheManager; this.sessionCache = sessionCache;
return this; return this;
} }
@ -143,11 +145,6 @@ public final class SessionInitializer extends AbstractSessionOperations {
return consistencyLevel; return consistencyLevel;
} }
public SessionInitializer setOperationsIdempotentByDefault() {
this.idempotent = true;
return this;
}
public SessionInitializer idempotentQueryExecution(boolean idempotent) { public SessionInitializer idempotentQueryExecution(boolean idempotent) {
this.idempotent = idempotent; this.idempotent = idempotent;
return this; return this;
@ -249,10 +246,8 @@ public final class SessionInitializer extends AbstractSessionOperations {
} }
public SessionInitializer use(String keyspace) { public SessionInitializer use(String keyspace) {
if (session != null) {
session.execute(SchemaUtil.use(keyspace, false)); session.execute(SchemaUtil.use(keyspace, false));
this.usingKeyspace = keyspace; this.usingKeyspace = keyspace;
}
return this; return this;
} }
@ -273,23 +268,27 @@ public final class SessionInitializer extends AbstractSessionOperations {
usingKeyspace, usingKeyspace,
registry, registry,
showCql, showCql,
showValues, obscureValues,
printStream, printStream,
sessionRepository, sessionRepository,
executor, executor,
autoDdl == AutoDdl.CREATE_DROP, autoDdl == AutoDdl.CREATE_DROP,
consistencyLevel, consistencyLevel,
idempotent, idempotent,
cacheManager, unitOfWorkClass,
metricRegistry); sessionCache,
metricRegistry,
zipkinTracer);
} }
private void initialize() { private void initialize() {
Objects.requireNonNull(usingKeyspace, "please define keyspace by 'use' operator"); Objects.requireNonNull(usingKeyspace, "please define keyspace by 'use' operator");
initList.forEach( boolean transactionalEntities = false;
(either) -> { HelenusEntity walEntity = null;
for (Either<Object, Class<?>> either : initList) {
Class<?> iface = null; Class<?> iface = null;
if (either.isLeft()) { if (either.isLeft()) {
iface = MappingUtil.getMappingInterface(either.getLeft()); iface = MappingUtil.getMappingInterface(either.getLeft());
@ -298,15 +297,18 @@ public final class SessionInitializer extends AbstractSessionOperations {
} }
DslExportable dsl = (DslExportable) Helenus.dsl(iface); DslExportable dsl = (DslExportable) Helenus.dsl(iface);
if (session != null) {
dsl.setCassandraMetadataForHelenusSession(session.getCluster().getMetadata()); dsl.setCassandraMetadataForHelenusSession(session.getCluster().getMetadata());
} sessionRepository.add(dsl);
if (sessionRepository != null) {
if (!transactionalEntities && iface.getDeclaredAnnotation(Transactional.class) != null) {
transactionalEntities = true;
dsl = (DslExportable) Helenus.dsl(WriteAheadLog.class);
dsl.setCassandraMetadataForHelenusSession(session.getCluster().getMetadata());
walEntity = dsl.getHelenusMappingEntity();
sessionRepository.add(dsl); sessionRepository.add(dsl);
} }
}); }
if (session == null) return;
TableOperations tableOps = new TableOperations(this, dropUnusedColumns, dropUnusedIndexes); TableOperations tableOps = new TableOperations(this, dropUnusedColumns, dropUnusedIndexes);
UserTypeOperations userTypeOps = new UserTypeOperations(this, dropUnusedColumns); UserTypeOperations userTypeOps = new UserTypeOperations(this, dropUnusedColumns);
@ -334,6 +336,10 @@ public final class SessionInitializer extends AbstractSessionOperations {
eachUserTypeInReverseOrder(userTypeOps, e -> userTypeOps.dropUserType(e)); eachUserTypeInReverseOrder(userTypeOps, e -> userTypeOps.dropUserType(e));
if (transactionalEntities) {
tableOps.dropTable(walEntity);
}
// FALLTHRU to CREATE case (read: the absence of a `break;` statement here is // FALLTHRU to CREATE case (read: the absence of a `break;` statement here is
// intentional!) // intentional!)
case CREATE: case CREATE:
@ -351,6 +357,9 @@ public final class SessionInitializer extends AbstractSessionOperations {
.filter(e -> e.getType() == HelenusEntityType.VIEW) .filter(e -> e.getType() == HelenusEntityType.VIEW)
.forEach(e -> tableOps.createView(e)); .forEach(e -> tableOps.createView(e));
if (transactionalEntities) {
tableOps.createTable(walEntity);
}
break; break;
case VALIDATE: case VALIDATE:
@ -362,6 +371,9 @@ public final class SessionInitializer extends AbstractSessionOperations {
.filter(e -> e.getType() == HelenusEntityType.TABLE) .filter(e -> e.getType() == HelenusEntityType.TABLE)
.forEach(e -> tableOps.validateTable(getTableMetadata(e), e)); .forEach(e -> tableOps.validateTable(getTableMetadata(e), e));
if (transactionalEntities) {
tableOps.validateTable(getTableMetadata(walEntity), walEntity);
}
break; break;
case UPDATE: case UPDATE:
@ -384,6 +396,10 @@ public final class SessionInitializer extends AbstractSessionOperations {
.stream() .stream()
.filter(e -> e.getType() == HelenusEntityType.VIEW) .filter(e -> e.getType() == HelenusEntityType.VIEW)
.forEach(e -> tableOps.createView(e)); .forEach(e -> tableOps.createView(e));
if (transactionalEntities) {
tableOps.updateTable(getTableMetadata(walEntity), walEntity);
}
break; break;
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -36,12 +35,12 @@ public final class TableOperations {
} }
public void createTable(HelenusEntity entity) { public void createTable(HelenusEntity entity) {
sessionOps.execute(SchemaUtil.createTable(entity)); sessionOps.execute(SchemaUtil.createTable(entity), true);
executeBatch(SchemaUtil.createIndexes(entity)); executeBatch(SchemaUtil.createIndexes(entity));
} }
public void dropTable(HelenusEntity entity) { public void dropTable(HelenusEntity entity) {
sessionOps.execute(SchemaUtil.dropTable(entity)); sessionOps.execute(SchemaUtil.dropTable(entity), true);
} }
public void validateTable(TableMetadata tmd, HelenusEntity entity) { public void validateTable(TableMetadata tmd, HelenusEntity entity) {
@ -80,14 +79,17 @@ public final class TableOperations {
public void createView(HelenusEntity entity) { public void createView(HelenusEntity entity) {
sessionOps.execute( sessionOps.execute(
SchemaUtil.createMaterializedView( SchemaUtil.createMaterializedView(
sessionOps.usingKeyspace(), entity.getName().toCql(), entity)); sessionOps.usingKeyspace(), entity.getName().toCql(), entity),
// executeBatch(SchemaUtil.createIndexes(entity)); NOTE: Unfortunately C* 3.10 does not yet support 2i on materialized views. true);
// executeBatch(SchemaUtil.createIndexes(entity)); NOTE: Unfortunately C* 3.10
// does not yet support 2i on materialized views.
} }
public void dropView(HelenusEntity entity) { public void dropView(HelenusEntity entity) {
sessionOps.execute( sessionOps.execute(
SchemaUtil.dropMaterializedView( SchemaUtil.dropMaterializedView(
sessionOps.usingKeyspace(), entity.getName().toCql(), entity)); sessionOps.usingKeyspace(), entity.getName().toCql(), entity),
true);
} }
public void updateView(TableMetadata tmd, HelenusEntity entity) { public void updateView(TableMetadata tmd, HelenusEntity entity) {
@ -102,6 +104,9 @@ public final class TableOperations {
private void executeBatch(List<SchemaStatement> list) { private void executeBatch(List<SchemaStatement> list) {
list.forEach(s -> sessionOps.execute(s)); list.forEach(
s -> {
sessionOps.execute(s, true);
});
} }
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,138 +15,16 @@
*/ */
package net.helenus.core; package net.helenus.core;
import static net.helenus.core.HelenusSession.deleted; import com.datastax.driver.core.Statement;
import com.google.common.base.Stopwatch; import com.google.common.base.Stopwatch;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import com.google.common.collect.TreeTraverser;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import javax.cache.Cache;
import javax.cache.CacheManager;
import javax.cache.configuration.CacheEntryListenerConfiguration;
import javax.cache.configuration.Configuration;
import javax.cache.integration.CacheLoader;
import javax.cache.integration.CacheLoaderException;
import javax.cache.integration.CompletionListener;
import javax.cache.processor.EntryProcessor;
import javax.cache.processor.EntryProcessorException;
import javax.cache.processor.EntryProcessorResult;
import net.helenus.core.cache.CacheUtil;
import net.helenus.core.cache.Facet; import net.helenus.core.cache.Facet;
import net.helenus.core.cache.MapCache;
import net.helenus.core.operation.AbstractOperation; import net.helenus.core.operation.AbstractOperation;
import net.helenus.core.operation.BatchOperation;
import net.helenus.mapping.MappingUtil;
import net.helenus.support.CheckedRunnable;
import net.helenus.support.Either;
import net.helenus.support.HelenusException;
import org.apache.commons.lang3.SerializationUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** Encapsulates the concept of a "transaction" as a unit-of-work. */ public interface UnitOfWork<X extends Exception> extends AutoCloseable {
public class UnitOfWork implements AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(UnitOfWork.class);
public final UnitOfWork parent;
protected final List<UnitOfWork> nested = new ArrayList<>();
protected final Table<String, String, Either<Object, List<Facet>>> cache = HashBasedTable.create();
protected final EvictTrackingMapCache<String, Object> statementCache;
protected final HelenusSession session;
protected String purpose;
protected List<String> nestedPurposes = new ArrayList<String>();
protected String info;
protected int cacheHits = 0;
protected int cacheMisses = 0;
protected int databaseLookups = 0;
protected final Stopwatch elapsedTime;
protected Map<String, Double> databaseTime = new HashMap<>();
protected double cacheLookupTimeMSecs = 0.0;
private List<CheckedRunnable> commitThunks = new ArrayList<>();
private List<CheckedRunnable> abortThunks = new ArrayList<>();
private Consumer<? super Throwable> exceptionallyThunk;
private List<CompletableFuture<?>> asyncOperationFutures = new ArrayList<CompletableFuture<?>>();
private boolean aborted = false;
private boolean committed = false;
private long committedAt = 0L;
private BatchOperation batch;
public UnitOfWork(HelenusSession session) {
this(session, null);
}
public UnitOfWork(HelenusSession session, UnitOfWork parent) {
Objects.requireNonNull(session, "containing session cannot be null");
this.parent = parent;
if (parent != null) {
parent.addNestedUnitOfWork(this);
}
this.session = session;
CacheLoader<String, Object> cacheLoader = null;
if (parent != null) {
cacheLoader =
new CacheLoader<String, Object>() {
Cache<String, Object> cache = parent.getCache();
@Override
public Object load(String key) throws CacheLoaderException {
return cache.get(key);
}
@Override
public Map<String, Object> loadAll(Iterable<? extends String> keys)
throws CacheLoaderException {
Map<String, Object> kvp = new HashMap<String, Object>();
for (String key : keys) {
kvp.put(key, cache.get(key));
}
return kvp;
}
};
}
this.elapsedTime = Stopwatch.createUnstarted();
this.statementCache = new EvictTrackingMapCache<String, Object>(null, "UOW(" + hashCode() + ")", cacheLoader, true);
}
public void addDatabaseTime(String name, Stopwatch amount) {
Double time = databaseTime.get(name);
if (time == null) {
databaseTime.put(name, (double) amount.elapsed(TimeUnit.MICROSECONDS));
} else {
databaseTime.put(name, time + amount.elapsed(TimeUnit.MICROSECONDS));
}
}
public void addCacheLookupTime(Stopwatch amount) {
cacheLookupTimeMSecs += amount.elapsed(TimeUnit.MICROSECONDS);
}
public void addNestedUnitOfWork(UnitOfWork uow) {
synchronized (nested) {
nested.add(uow);
}
}
/** /**
* Marks the beginning of a transactional section of work. Will write a * Marks the beginning of a transactional section of work. Will write a
@ -155,662 +32,48 @@ public class UnitOfWork implements AutoCloseable {
* *
* @return the handle used to commit or abort the work. * @return the handle used to commit or abort the work.
*/ */
public synchronized UnitOfWork begin() { UnitOfWork<X> begin();
elapsedTime.start();
// log.record(txn::start)
return this;
}
public String getPurpose() { void addNestedUnitOfWork(UnitOfWork<X> uow);
return purpose;
}
public UnitOfWork setPurpose(String purpose) {
this.purpose = purpose;
return this;
}
public void addFuture(CompletableFuture<?> future) {
asyncOperationFutures.add(future);
}
public void setInfo(String info) {
this.info = info;
}
public void recordCacheAndDatabaseOperationCount(int cache, int ops) {
if (cache > 0) {
cacheHits += cache;
} else {
cacheMisses += Math.abs(cache);
}
if (ops > 0) {
databaseLookups += ops;
}
}
public String logTimers(String what) {
double e = (double) elapsedTime.elapsed(TimeUnit.MICROSECONDS) / 1000.0;
double d = 0.0;
double c = cacheLookupTimeMSecs / 1000.0;
double fc = (c / e) * 100.0;
String database = "";
if (databaseTime.size() > 0) {
List<String> dbt = new ArrayList<>(databaseTime.size());
for (Map.Entry<String, Double> dt : databaseTime.entrySet()) {
double t = dt.getValue() / 1000.0;
d += t;
dbt.add(String.format("%s took %,.3fms %,2.2f%%", dt.getKey(), t, (t / e) * 100.0));
}
double fd = (d / e) * 100.0;
database =
String.format(
", %d quer%s (%,.3fms %,2.2f%% - %s)",
databaseLookups, (databaseLookups > 1) ? "ies" : "y", d, fd, String.join(", ", dbt));
}
String cache = "";
if (cacheLookupTimeMSecs > 0) {
int cacheLookups = cacheHits + cacheMisses;
cache =
String.format(
" with %d cache lookup%s (%,.3fms %,2.2f%% - %,d hit, %,d miss)",
cacheLookups, cacheLookups > 1 ? "s" : "", c, fc, cacheHits, cacheMisses);
}
String da = "";
if (databaseTime.size() > 0 || cacheLookupTimeMSecs > 0) {
double dat = d + c;
double daf = (dat / e) * 100;
da =
String.format(
" consuming %,.3fms for data access, or %,2.2f%% of total UOW time.", dat, daf);
}
String x = nestedPurposes.stream().distinct().collect(Collectors.joining(", "));
String n =
nested
.stream()
.map(uow -> String.valueOf(uow.hashCode()))
.collect(Collectors.joining(", "));
String s =
String.format(
Locale.US,
"UOW(%s%s) %s in %,.3fms%s%s%s%s%s%s",
hashCode(),
(nested.size() > 0 ? ", [" + n + "]" : ""),
what,
e,
cache,
database,
da,
(purpose == null ? "" : " " + purpose),
(nestedPurposes.isEmpty()) ? "" : ", " + x,
(info == null) ? "" : " " + info);
return s;
}
private void applyPostCommitFunctions(String what, List<CheckedRunnable> thunks, Consumer<? super Throwable> exceptionallyThunk) {
if (!thunks.isEmpty()) {
for (CheckedRunnable f : thunks) {
try {
f.run();
} catch (Throwable t) {
if (exceptionallyThunk != null) {
exceptionallyThunk.accept(t);
}
}
}
}
}
public Optional<Object> cacheLookup(List<Facet> facets) {
String tableName = CacheUtil.schemaName(facets);
Optional<Object> result = Optional.empty();
for (Facet facet : facets) {
if (!facet.fixed()) {
String columnName = facet.name() + "==" + facet.value();
Either<Object, List<Facet>> eitherValue = cache.get(tableName, columnName);
if (eitherValue != null) {
Object value = deleted;
if (eitherValue.isLeft()) {
value = eitherValue.getLeft();
}
return Optional.of(value);
}
}
}
// Be sure to check all enclosing UnitOfWork caches as well, we may be nested.
result = checkParentCache(facets);
if (result.isPresent()) {
Object r = result.get();
Class<?> iface = MappingUtil.getMappingInterface(r);
if (Helenus.entity(iface).isDraftable()) {
cacheUpdate(r, facets);
} else {
cacheUpdate(SerializationUtils.<Serializable>clone((Serializable) r), facets);
}
}
return result;
}
private Optional<Object> checkParentCache(List<Facet> facets) {
Optional<Object> result = Optional.empty();
if (parent != null) {
result = parent.checkParentCache(facets);
}
return result;
}
public List<Facet> cacheEvict(List<Facet> facets) {
Either<Object, List<Facet>> deletedObjectFacets = Either.right(facets);
String tableName = CacheUtil.schemaName(facets);
Optional<Object> optionalValue = cacheLookup(facets);
for (Facet facet : facets) {
if (!facet.fixed()) {
String columnKey = facet.name() + "==" + facet.value();
// mark the value identified by the facet to `deleted`
cache.put(tableName, columnKey, deletedObjectFacets);
}
}
// Now, look for other row/col pairs that referenced the same object, mark them
// `deleted` if the cache had a value before we added the deleted marker objects.
if (optionalValue.isPresent()) {
Object value = optionalValue.get();
cache
.columnKeySet()
.forEach(
columnKey -> {
Either<Object, List<Facet>> eitherCachedValue = cache.get(tableName, columnKey);
if (eitherCachedValue.isLeft()) {
Object cachedValue = eitherCachedValue.getLeft();
if (cachedValue == value) {
cache.put(tableName, columnKey, deletedObjectFacets);
String[] parts = columnKey.split("==");
facets.add(new Facet<String>(parts[0], parts[1]));
}
}
});
}
return facets;
}
public Cache<String, Object> getCache() {
return statementCache;
}
public Object cacheUpdate(Object value, List<Facet> facets) {
Object result = null;
String tableName = CacheUtil.schemaName(facets);
for (Facet facet : facets) {
if (!facet.fixed()) {
if (facet.alone()) {
String columnName = facet.name() + "==" + facet.value();
if (result == null) result = cache.get(tableName, columnName);
cache.put(tableName, columnName, Either.left(value));
}
}
}
return result;
}
public void batch(AbstractOperation s) {
if (batch == null) {
batch = new BatchOperation(session);
}
batch.add(s);
}
private Iterator<UnitOfWork> getChildNodes() {
return nested.iterator();
}
/** /**
* Checks to see if the work performed between calling begin and now can be committed or not. * Checks to see if the work performed between calling begin and now can be committed or not.
* *
* @return a function from which to chain work that only happens when commit is successful * @return a function from which to chain work that only happens when commit is successful
* @throws HelenusException when the work overlaps with other concurrent writers. * @throws X when the work overlaps with other concurrent writers.
*/ */
public synchronized PostCommitFunction<Void, Void> commit() throws HelenusException { PostCommitFunction<Void, Void> commit() throws X, TimeoutException;
if (isDone()) {
return PostCommitFunction.NULL_ABORT;
}
// Only the outer-most UOW batches statements for commit time, execute them.
if (batch != null) {
committedAt = batch.sync(this); //TODO(gburd): update cache with writeTime...
}
// All nested UnitOfWork should be committed (not aborted) before calls to
// commit, check.
boolean canCommit = true;
TreeTraverser<UnitOfWork> traverser = TreeTraverser.using(node -> node::getChildNodes);
for (UnitOfWork uow : traverser.postOrderTraversal(this)) {
if (this != uow) {
canCommit &= (!uow.aborted && uow.committed);
}
}
if (!canCommit) {
if (parent == null) {
// Apply all post-commit abort functions, this is the outer-most UnitOfWork.
traverser
.postOrderTraversal(this)
.forEach(
uow -> {
applyPostCommitFunctions("aborted", abortThunks, exceptionallyThunk);
});
elapsedTime.stop();
if (LOG.isInfoEnabled()) {
LOG.info(logTimers("aborted"));
}
}
return PostCommitFunction.NULL_ABORT;
} else {
committed = true;
aborted = false;
if (parent == null) {
// Apply all post-commit commit functions, this is the outer-most UnitOfWork.
traverser
.postOrderTraversal(this)
.forEach(
uow -> {
applyPostCommitFunctions("committed", uow.commitThunks, exceptionallyThunk);
});
// Merge our statement cache into the session cache if it exists.
CacheManager cacheManager = session.getCacheManager();
if (cacheManager != null) {
for (Map.Entry<String, Object> entry :
(Set<Map.Entry<String, Object>>) statementCache.<Map>unwrap(Map.class).entrySet()) {
String[] keyParts = entry.getKey().split("\\.");
if (keyParts.length == 2) {
String cacheName = keyParts[0];
String key = keyParts[1];
if (!StringUtils.isBlank(cacheName) && !StringUtils.isBlank(key)) {
Cache<Object, Object> cache = cacheManager.getCache(cacheName);
if (cache != null) {
Object value = entry.getValue();
if (value == deleted) {
cache.remove(key);
} else {
cache.put(key.toString(), value);
}
}
}
}
}
}
// Merge our cache into the session cache.
session.mergeCache(cache);
// Spoil any lingering futures that may be out there.
asyncOperationFutures.forEach(
f ->
f.completeExceptionally(
new HelenusException(
"Futures must be resolved before their unit of work has committed/aborted.")));
elapsedTime.stop();
if (LOG.isInfoEnabled()) {
LOG.info(logTimers("committed"));
}
return PostCommitFunction.NULL_COMMIT;
} else {
// Merge cache and statistics into parent if there is one.
parent.statementCache.putAll(statementCache.<Map>unwrap(Map.class));
parent.statementCache.removeAll(statementCache.getDeletions());
parent.mergeCache(cache);
parent.addBatched(batch);
if (purpose != null) {
parent.nestedPurposes.add(purpose);
}
parent.cacheHits += cacheHits;
parent.cacheMisses += cacheMisses;
parent.databaseLookups += databaseLookups;
parent.cacheLookupTimeMSecs += cacheLookupTimeMSecs;
for (Map.Entry<String, Double> dt : databaseTime.entrySet()) {
String name = dt.getKey();
if (parent.databaseTime.containsKey(name)) {
double t = parent.databaseTime.get(name);
parent.databaseTime.put(name, t + dt.getValue());
} else {
parent.databaseTime.put(name, dt.getValue());
}
}
}
}
// TODO(gburd): hopefully we'll be able to detect conflicts here and so we'd want to...
// else {
// Constructor<T> ctor = clazz.getConstructor(conflictExceptionClass);
// T object = ctor.newInstance(new Object[] { String message });
// }
return new PostCommitFunction<Void, Void>(commitThunks, abortThunks, exceptionallyThunk, true);
}
private void addBatched(BatchOperation batchArg) {
if (batchArg != null) {
if (this.batch == null) {
this.batch = batchArg;
} else {
this.batch.addAll(batchArg);
}
}
}
/** /**
* Explicitly abort the work within this unit of work. Any nested aborted unit of work will * Explicitly abort the work within this unit of work. Any nested aborted unit of work will
* trigger the entire unit of work to commit. * trigger the entire unit of work to commit.
*/ */
public synchronized void abort() { void abort();
if (!aborted) {
aborted = true;
// Spoil any pending futures created within the context of this unit of work. boolean hasAborted();
asyncOperationFutures.forEach(
f ->
f.completeExceptionally(
new HelenusException(
"Futures must be resolved before their unit of work has committed/aborted.")));
TreeTraverser<UnitOfWork> traverser = TreeTraverser.using(node -> node::getChildNodes); boolean hasCommitted();
traverser
.postOrderTraversal(this)
.forEach(
uow -> {
applyPostCommitFunctions("aborted", uow.abortThunks, exceptionallyThunk);
uow.abortThunks.clear();
});
if (parent == null) { long committedAt();
if (elapsedTime.isRunning()) {
elapsedTime.stop();
}
if (LOG.isInfoEnabled()) {
LOG.info(logTimers("aborted"));
}
}
// TODO(gburd): when we integrate the transaction support we'll need to... void batch(AbstractOperation operation);
// log.record(txn::abort)
// cache.invalidateSince(txn::start time)
}
}
private void mergeCache(Table<String, String, Either<Object, List<Facet>>> from) { Optional<Object> cacheLookup(List<Facet> facets);
Table<String, String, Either<Object, List<Facet>>> to = this.cache;
from.rowMap()
.forEach(
(rowKey, columnMap) -> {
columnMap.forEach(
(columnKey, value) -> {
if (to.contains(rowKey, columnKey)) {
to.put(
rowKey,
columnKey,
Either.left(
CacheUtil.merge(
to.get(rowKey, columnKey).getLeft(),
from.get(rowKey, columnKey).getLeft())));
} else {
to.put(rowKey, columnKey, from.get(rowKey, columnKey));
}
});
});
}
public boolean isDone() { void cacheUpdate(Object pojo, List<Facet> facets);
return aborted || committed;
}
public String describeConflicts() { List<Facet> cacheEvict(List<Facet> facets);
return "it's complex...";
}
@Override String getPurpose();
public void close() throws HelenusException {
// Closing a UnitOfWork will abort iff we've not already aborted or committed this unit of work.
if (aborted == false && committed == false) {
abort();
}
}
public boolean hasAborted() { UnitOfWork setPurpose(String purpose);
return aborted;
}
public boolean hasCommitted() { void setInfo(String info);
return committed;
}
public long committedAt() { void addDatabaseTime(String name, Stopwatch amount);
return committedAt;
}
private static class EvictTrackingMapCache<K, V> implements Cache<K, V> { void addCacheLookupTime(Stopwatch amount);
private final Set<K> deletes;
private final Cache<K, V> delegate;
public EvictTrackingMapCache(CacheManager manager, String name, CacheLoader<K, V> cacheLoader, // Cache > 0 means "cache hit", < 0 means cache miss.
boolean isReadThrough) { void recordCacheAndDatabaseOperationCount(int cache, int database);
deletes = Collections.synchronizedSet(new HashSet<>());
delegate = new MapCache<>(manager, name, cacheLoader, isReadThrough);
}
/** Non-interface method; should only be called by UnitOfWork when merging to an enclosing UnitOfWork. */
public Set<K> getDeletions() {
return new HashSet<>(deletes);
}
@Override
public V get(K key) {
if (deletes.contains(key)) {
return null;
}
return delegate.get(key);
}
@Override
public Map<K, V> getAll(Set<? extends K> keys) {
Set<? extends K> clonedKeys = new HashSet<>(keys);
clonedKeys.removeAll(deletes);
return delegate.getAll(clonedKeys);
}
@Override
public boolean containsKey(K key) {
if (deletes.contains(key)) {
return false;
}
return delegate.containsKey(key);
}
@Override
public void loadAll(Set<? extends K> keys, boolean replaceExistingValues, CompletionListener listener) {
Set<? extends K> clonedKeys = new HashSet<>(keys);
clonedKeys.removeAll(deletes);
delegate.loadAll(clonedKeys, replaceExistingValues, listener);
}
@Override
public void put(K key, V value) {
if (deletes.contains(key)) {
deletes.remove(key);
}
delegate.put(key, value);
}
@Override
public V getAndPut(K key, V value) {
if (deletes.contains(key)) {
deletes.remove(key);
}
return delegate.getAndPut(key, value);
}
@Override
public void putAll(Map<? extends K, ? extends V> map) {
deletes.removeAll(map.keySet());
delegate.putAll(map);
}
@Override
public synchronized boolean putIfAbsent(K key, V value) {
if (!delegate.containsKey(key) && deletes.contains(key)) {
deletes.remove(key);
}
return delegate.putIfAbsent(key, value);
}
@Override
public boolean remove(K key) {
boolean removed = delegate.remove(key);
deletes.add(key);
return removed;
}
@Override
public boolean remove(K key, V value) {
boolean removed = delegate.remove(key, value);
if (removed) {
deletes.add(key);
}
return removed;
}
@Override
public V getAndRemove(K key) {
V value = delegate.getAndRemove(key);
deletes.add(key);
return value;
}
@Override
public void removeAll(Set<? extends K> keys) {
Set<? extends K> cloneKeys = new HashSet<>(keys);
delegate.removeAll(cloneKeys);
deletes.addAll(cloneKeys);
}
@Override
@SuppressWarnings("unchecked")
public synchronized void removeAll() {
Map<K, V> impl = delegate.unwrap(Map.class);
Set<K> keys = impl.keySet();
delegate.removeAll();
deletes.addAll(keys);
}
@Override
public void clear() {
delegate.clear();
// TODO(gburd): all parents too
deletes.clear();
}
@Override
public boolean replace(K key, V oldValue, V newValue) {
if (deletes.contains(key)) {
return false;
}
return delegate.replace(key, oldValue, newValue);
}
@Override
public boolean replace(K key, V value) {
if (deletes.contains(key)) {
return false;
}
return delegate.replace(key, value);
}
@Override
public V getAndReplace(K key, V value) {
if (deletes.contains(key)) {
return null;
}
return delegate.getAndReplace(key, value);
}
@Override
public <C extends Configuration<K, V>> C getConfiguration(Class<C> clazz) {
return delegate.getConfiguration(clazz);
}
@Override
public <T> T invoke(K key, EntryProcessor<K, V, T> processor, Object... arguments)
throws EntryProcessorException {
if (deletes.contains(key)) {
return null;
}
return delegate.invoke(key, processor, arguments);
}
@Override
public <T> Map<K, EntryProcessorResult<T>> invokeAll(Set<? extends K> keys, EntryProcessor<K, V, T> processor,
Object... arguments) {
Set<? extends K> clonedKeys = new HashSet<>(keys);
clonedKeys.removeAll(deletes);
return delegate.invokeAll(clonedKeys, processor, arguments);
}
@Override
public String getName() {
return delegate.getName();
}
@Override
public CacheManager getCacheManager() {
return delegate.getCacheManager();
}
@Override
public void close() {
delegate.close();
}
@Override
public boolean isClosed() {
return delegate.isClosed();
}
@Override
public <T> T unwrap(Class<T> clazz) {
return delegate.unwrap(clazz);
}
@Override
public void registerCacheEntryListener(CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration) {
delegate.registerCacheEntryListener(cacheEntryListenerConfiguration);
}
@Override
public void deregisterCacheEntryListener(CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration) {
delegate.deregisterCacheEntryListener(cacheEntryListenerConfiguration);
}
@Override
public Iterator<Entry<K, V>> iterator() {
return delegate.iterator();
}
}
} }

View file

@ -0,0 +1,26 @@
/*
* Copyright (C) 2015 The Helenus Authors
*
* 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.helenus.core;
import net.helenus.support.HelenusException;
class UnitOfWorkImpl extends AbstractUnitOfWork<HelenusException> {
@SuppressWarnings("unchecked")
public UnitOfWorkImpl(HelenusSession session, UnitOfWork parent) {
super(session, (AbstractUnitOfWork<HelenusException>) parent);
}
}

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -34,12 +33,12 @@ public final class UserTypeOperations {
public void createUserType(HelenusEntity entity) { public void createUserType(HelenusEntity entity) {
sessionOps.execute(SchemaUtil.createUserType(entity)); sessionOps.execute(SchemaUtil.createUserType(entity), true);
} }
public void dropUserType(HelenusEntity entity) { public void dropUserType(HelenusEntity entity) {
sessionOps.execute(SchemaUtil.dropUserType(entity)); sessionOps.execute(SchemaUtil.dropUserType(entity), true);
} }
public void validateUserType(UserType userType, HelenusEntity entity) { public void validateUserType(UserType userType, HelenusEntity entity) {
@ -72,6 +71,9 @@ public final class UserTypeOperations {
private void executeBatch(List<SchemaStatement> list) { private void executeBatch(List<SchemaStatement> list) {
list.forEach(s -> sessionOps.execute(s)); list.forEach(
s -> {
sessionOps.execute(s, true);
});
} }
} }

View file

@ -0,0 +1,44 @@
/*
* Copyright (C) 2015 The Helenus Authors
*
* 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.helenus.core;
import com.datastax.driver.core.DataType;
import net.helenus.mapping.annotation.*;
import java.util.Date;
import java.util.Set;
import java.util.UUID;
@Table(value="wal")
public interface WriteAheadLog {
enum Type { BEGIN, PREPARED, COMMITTED, ABORTED }
@PartitionKey
@Types.Timestamp
Date lsn();
@Column(value="id")
UUID uow();
@Column
default Type type() { return Type.BEGIN; }
@Column
@Index
@Types.Set(DataType.Name.TEXT)
Set<String> mutations();
}

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -0,0 +1,25 @@
/*
* Copyright (C) 2015 The Helenus Authors
*
* 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.helenus.core.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Transactional {}

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -31,9 +30,7 @@ public class BoundFacet extends Facet<String> {
this.properties.put(property, value); this.properties.put(property, value);
} }
public Set<HelenusProperty> getProperties() { public Set<HelenusProperty> getProperties() { return properties.keySet(); }
return properties.keySet();
}
public BoundFacet(String name, Map<HelenusProperty, Object> properties) { public BoundFacet(String name, Map<HelenusProperty, Object> properties) {
super( super(

View file

@ -3,15 +3,7 @@ package net.helenus.core.cache;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import net.helenus.core.Helenus;
import net.helenus.core.reflect.Entity;
import net.helenus.core.reflect.MapExportable;
import net.helenus.mapping.HelenusEntity;
import net.helenus.mapping.HelenusProperty;
import net.helenus.mapping.MappingUtil;
import net.helenus.mapping.value.BeanColumnValueProvider;
public class CacheUtil { public class CacheUtil {
@ -26,8 +18,7 @@ public class CacheUtil {
return out; return out;
} }
private static void kCombinations( private static void kCombinations(List<String> items, int n, int k, String[] arr, List<String[]> out) {
List<String> items, int n, int k, String[] arr, List<String[]> out) {
if (k == 0) { if (k == 0) {
out.add(arr.clone()); out.add(arr.clone());
} else { } else {
@ -41,8 +32,7 @@ public class CacheUtil {
public static List<String> flatKeys(String table, List<Facet> facets) { public static List<String> flatKeys(String table, List<Facet> facets) {
return flattenFacets(facets) return flattenFacets(facets)
.stream() .stream()
.map( .map(combination -> {
combination -> {
return table + "." + Arrays.toString(combination); return table + "." + Arrays.toString(combination);
}) })
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -61,18 +51,14 @@ public class CacheUtil {
}) })
.collect(Collectors.toList())); .collect(Collectors.toList()));
// TODO(gburd): rework so as to not generate the combinations at all rather than filter // TODO(gburd): rework so as to not generate the combinations at all rather than filter
facets = facets = facets.stream()
facets
.stream()
.filter(f -> !f.fixed()) .filter(f -> !f.fixed())
.filter(f -> !f.alone() || !f.combined()) .filter(f -> !f.alone() || !f.combined())
.collect(Collectors.toList()); .collect(Collectors.toList());
for (Facet facet : facets) { for (Facet facet : facets) {
combinations = combinations = combinations
combinations
.stream() .stream()
.filter( .filter(combo -> {
combo -> {
// When used alone, this facet is not distinct so don't use it as a key. // When used alone, this facet is not distinct so don't use it as a key.
if (combo.length == 1) { if (combo.length == 1) {
if (!facet.alone() && combo[0].startsWith(facet.name() + "==")) { if (!facet.alone() && combo[0].startsWith(facet.name() + "==")) {
@ -95,102 +81,30 @@ public class CacheUtil {
return combinations; return combinations;
} }
/** Merge changed values in the map behind `from` into `to`. */ /**
public static Object merge(Object t, Object f) { * Merge changed values in the map behind `from` into `to`.
HelenusEntity entity = Helenus.resolve(MappingUtil.getMappingInterface(t)); *
* @param to
if (t == f) return t; * @param from
if (f == null) return t; * @return
if (t == null) return f; */
public static Object merge(Object to, Object from) {
if (t instanceof MapExportable if (to == from) {
&& t instanceof Entity
&& f instanceof MapExportable
&& f instanceof Entity) {
Entity to = (Entity) t;
Entity from = (Entity) f;
Map<String, Object> toValueMap = ((MapExportable) to).toMap();
Map<String, Object> fromValueMap = ((MapExportable) from).toMap();
for (HelenusProperty prop : entity.getOrderedProperties()) {
switch (prop.getColumnType()) {
case PARTITION_KEY:
case CLUSTERING_COLUMN:
continue;
default:
Object toVal = BeanColumnValueProvider.INSTANCE.getColumnValue(to, -1, prop, false);
Object fromVal = BeanColumnValueProvider.INSTANCE.getColumnValue(from, -1, prop, false);
String ttlKey = ttlKey(prop);
String writeTimeKey = writeTimeKey(prop);
int[] toTtlI = (int[]) toValueMap.get(ttlKey);
int toTtl = (toTtlI != null) ? toTtlI[0] : 0;
Long toWriteTime = (Long) toValueMap.get(writeTimeKey);
int[] fromTtlI = (int[]) fromValueMap.get(ttlKey);
int fromTtl = (fromTtlI != null) ? fromTtlI[0] : 0;
Long fromWriteTime = (Long) fromValueMap.get(writeTimeKey);
if (toVal != null) {
if (fromVal != null) {
if (toVal == fromVal) {
// Case: object identity
// Goal: ensure write time and ttl are also in sync
if (fromWriteTime != null
&& fromWriteTime != 0L
&& (toWriteTime == null || fromWriteTime > toWriteTime)) {
((MapExportable) to).put(writeTimeKey, fromWriteTime);
}
if (fromTtl > 0 && fromTtl > toTtl) {
((MapExportable) to).put(ttlKey, fromTtl);
}
} else if (fromWriteTime != null && fromWriteTime != 0L) {
// Case: to exists and from exists
// Goal: copy over from -> to iff from.writeTime > to.writeTime
if (toWriteTime != null && toWriteTime != 0L) {
if (fromWriteTime > toWriteTime) {
((MapExportable) to).put(prop.getPropertyName(), fromVal);
((MapExportable) to).put(writeTimeKey, fromWriteTime);
if (fromTtl > 0) {
((MapExportable) to).put(ttlKey, fromTtl);
}
}
} else {
((MapExportable) to).put(prop.getPropertyName(), fromVal);
((MapExportable) to).put(writeTimeKey, fromWriteTime);
if (fromTtl > 0) {
((MapExportable) to).put(ttlKey, fromTtl);
}
}
} else {
if (toWriteTime == null || toWriteTime == 0L) {
// Caution, entering grey area...
if (!toVal.equals(fromVal)) {
// dangerous waters here, values diverge without information that enables resolution,
// policy (for now) is to move value from -> to anyway.
((MapExportable) to).put(prop.getPropertyName(), fromVal);
if (fromTtl > 0) {
((MapExportable) to).put(ttlKey, fromTtl);
}
}
}
}
}
} else {
// Case: from exists, but to doesn't (it's null)
// Goal: copy over from -> to, include ttl and writeTime if present
if (fromVal != null) {
((MapExportable) to).put(prop.getPropertyName(), fromVal);
if (fromWriteTime != null && fromWriteTime != 0L) {
((MapExportable) to).put(writeTimeKey, fromWriteTime);
}
if (fromTtl > 0) {
((MapExportable) to).put(ttlKey, fromTtl);
}
}
}
}
}
return to; return to;
} else {
return from;
} }
return t; /*
* // TODO(gburd): take ttl and writeTime into account when merging. Map<String,
* Object> toValueMap = to instanceof MapExportable ? ((MapExportable)
* to).toMap() : null; Map<String, Object> fromValueMap = to instanceof
* MapExportable ? ((MapExportable) from).toMap() : null;
*
* if (toValueMap != null && fromValueMap != null) { for (String key :
* fromValueMap.keySet()) { if (toValueMap.containsKey(key) &&
* toValueMap.get(key) != fromValueMap.get(key)) { toValueMap.put(key,
* fromValueMap.get(key)); } } } return to;
*/
} }
public static String schemaName(List<Facet> facets) { public static String schemaName(List<Facet> facets) {
@ -201,21 +115,9 @@ public class CacheUtil {
.collect(Collectors.joining(".")); .collect(Collectors.joining("."));
} }
public static String writeTimeKey(HelenusProperty prop) { public static String writeTimeKey(String propertyName) {
return writeTimeKey(prop.getColumnName().toCql(false)); return "_" + propertyName + "_writeTime";
} }
public static String ttlKey(HelenusProperty prop) { public static String ttlKey(String propertyName) { return "_" + propertyName + "_ttl"; }
return ttlKey(prop.getColumnName().toCql(false));
}
public static String writeTimeKey(String columnName) {
String key = "_" + columnName + "_writeTime";
return key.toLowerCase();
}
public static String ttlKey(String columnName) {
String key = "_" + columnName + "_ttl";
return key.toLowerCase();
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -59,11 +58,6 @@ public class Facet<T> {
this.combined = combined; this.combined = combined;
} }
public boolean alone() { public boolean alone() { return alone; }
return alone; public boolean combined() { return combined; }
}
public boolean combined() {
return combined;
}
} }

View file

@ -0,0 +1,43 @@
/*
* Copyright (C) 2015 The Helenus Authors
*
* 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.helenus.core.cache;
import com.google.common.cache.Cache;
public class GuavaCache<K, V> implements SessionCache<K, V> {
final Cache<K, V> cache;
GuavaCache(Cache<K, V> cache) {
this.cache = cache;
}
@Override
public void invalidate(K key) {
cache.invalidate(key);
}
@Override
public V get(K key) {
return cache.getIfPresent(key);
}
@Override
public void put(K key, V value) {
cache.put(key, value);
}
}

View file

@ -1,463 +0,0 @@
package net.helenus.core.cache;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.cache.Cache;
import javax.cache.CacheManager;
import javax.cache.configuration.CacheEntryListenerConfiguration;
import javax.cache.configuration.Configuration;
import javax.cache.event.CacheEntryRemovedListener;
import javax.cache.integration.CacheLoader;
import javax.cache.integration.CompletionListener;
import javax.cache.processor.EntryProcessor;
import javax.cache.processor.EntryProcessorException;
import javax.cache.processor.EntryProcessorResult;
import javax.cache.processor.MutableEntry;
public class MapCache<K, V> implements Cache<K, V> {
private final CacheManager manager;
private final String name;
private Map<K, V> map = new ConcurrentHashMap<>();
private Set<CacheEntryRemovedListener<K, V>> cacheEntryRemovedListeners = new HashSet<>();
private CacheLoader<K, V> cacheLoader = null;
private boolean isReadThrough = false;
private static class MapConfiguration<K, V> implements Configuration<K, V> {
private static final long serialVersionUID = 6093947542772516209L;
@Override
public Class<K> getKeyType() {
return null;
}
@Override
public Class<V> getValueType() {
return null;
}
@Override
public boolean isStoreByValue() {
return false;
}
}
public MapCache(
CacheManager manager, String name, CacheLoader<K, V> cacheLoader, boolean isReadThrough) {
this.manager = manager;
this.name = name;
this.cacheLoader = cacheLoader;
this.isReadThrough = isReadThrough;
}
/** {@inheritDoc} */
@Override
public V get(K key) {
V value = null;
synchronized (map) {
value = map.get(key);
if (value == null && isReadThrough && cacheLoader != null) {
V loadedValue = cacheLoader.load(key);
if (loadedValue != null) {
map.put(key, loadedValue);
value = loadedValue;
}
}
}
return value;
}
/** {@inheritDoc} */
@Override
public Map<K, V> getAll(Set<? extends K> keys) {
Map<K, V> result = null;
synchronized (map) {
result = new HashMap<K, V>(keys.size());
Iterator<? extends K> it = keys.iterator();
while (it.hasNext()) {
K key = it.next();
V value = map.get(key);
if (value != null) {
result.put(key, value);
it.remove();
}
}
if (keys.size() != 0 && isReadThrough && cacheLoader != null) {
Map<K, V> loadedValues = cacheLoader.loadAll(keys);
for (Map.Entry<K, V> entry : loadedValues.entrySet()) {
V v = entry.getValue();
if (v != null) {
K k = entry.getKey();
map.put(k, v);
result.put(k, v);
}
}
}
}
return result;
}
/** {@inheritDoc} */
@Override
public boolean containsKey(K key) {
return map.containsKey(key);
}
/** {@inheritDoc} */
@Override
public void loadAll(
Set<? extends K> keys, boolean replaceExistingValues, CompletionListener completionListener) {
if (cacheLoader != null) {
try {
synchronized (map) {
Map<K, V> loadedValues = cacheLoader.loadAll(keys);
for (Map.Entry<K, V> entry : loadedValues.entrySet()) {
V value = entry.getValue();
K key = entry.getKey();
if (value != null) {
boolean existsCurrently = map.containsKey(key);
if (!existsCurrently || replaceExistingValues) {
map.put(key, value);
keys.remove(key);
}
}
}
}
} catch (Exception e) {
if (completionListener != null) {
completionListener.onException(e);
}
}
}
if (completionListener != null) {
if (keys.isEmpty()) {
completionListener.onCompletion();
}
}
}
/** {@inheritDoc} */
@Override
public void put(K key, V value) {
map.put(key, value);
}
/** {@inheritDoc} */
@Override
public V getAndPut(K key, V value) {
V result = null;
synchronized (map) {
result = map.get(key);
if (result == null && isReadThrough && cacheLoader != null) {
V loadedValue = cacheLoader.load(key);
if (loadedValue != null) {
result = loadedValue;
}
}
map.put(key, value);
}
return result;
}
/** {@inheritDoc} */
@Override
public void putAll(Map<? extends K, ? extends V> map) {
synchronized (map) {
for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
this.map.put(entry.getKey(), entry.getValue());
}
}
}
/** {@inheritDoc} */
@Override
public boolean putIfAbsent(K key, V value) {
synchronized (map) {
if (!map.containsKey(key)) {
map.put(key, value);
return true;
} else {
return false;
}
}
}
/** {@inheritDoc} */
@Override
public boolean remove(K key) {
boolean removed = false;
synchronized (map) {
removed = map.remove(key) != null;
notifyRemovedListeners(key);
}
return removed;
}
/** {@inheritDoc} */
@Override
public boolean remove(K key, V oldValue) {
synchronized (map) {
V value = map.get(key);
if (value != null && oldValue.equals(value)) {
map.remove(key);
notifyRemovedListeners(key);
return true;
}
}
return false;
}
/** {@inheritDoc} */
@Override
public V getAndRemove(K key) {
synchronized (map) {
V oldValue = null;
oldValue = map.get(key);
map.remove(key);
notifyRemovedListeners(key);
return oldValue;
}
}
/** {@inheritDoc} */
@Override
public boolean replace(K key, V oldValue, V newValue) {
synchronized (map) {
V value = map.get(key);
if (value != null && oldValue.equals(value)) {
map.put(key, newValue);
return true;
}
}
return false;
}
/** {@inheritDoc} */
@Override
public boolean replace(K key, V value) {
synchronized (map) {
if (map.containsKey(key)) {
map.put(key, value);
return true;
}
}
return false;
}
/** {@inheritDoc} */
@Override
public V getAndReplace(K key, V value) {
synchronized (map) {
V oldValue = map.get(key);
if (value != null && value.equals(oldValue)) {
map.put(key, value);
return oldValue;
}
}
return null;
}
/** {@inheritDoc} */
@Override
public void removeAll(Set<? extends K> keys) {
synchronized (map) {
Iterator<? extends K> it = keys.iterator();
while (it.hasNext()) {
K key = it.next();
if (map.containsKey(key)) {
map.remove(key);
} else {
it.remove();
}
}
}
notifyRemovedListeners(keys);
}
/** {@inheritDoc} */
@Override
public void removeAll() {
synchronized (map) {
Set<K> keys = map.keySet();
map.clear();
notifyRemovedListeners(keys);
}
}
/** {@inheritDoc} */
@Override
public void clear() {
map.clear();
}
/** {@inheritDoc} */
@Override
public <C extends Configuration<K, V>> C getConfiguration(Class<C> clazz) {
if (!MapConfiguration.class.isAssignableFrom(clazz)) {
throw new IllegalArgumentException();
}
return null;
}
/** {@inheritDoc} */
@Override
public <T> T invoke(K key, EntryProcessor<K, V, T> entryProcessor, Object... arguments)
throws EntryProcessorException {
// TODO
return null;
}
/** {@inheritDoc} */
@Override
public <T> Map<K, EntryProcessorResult<T>> invokeAll(
Set<? extends K> keys, EntryProcessor<K, V, T> entryProcessor, Object... arguments) {
synchronized (map) {
for (K key : keys) {
V value = map.get(key);
if (value != null) {
entryProcessor.process(
new MutableEntry<K, V>() {
@Override
public boolean exists() {
return map.containsKey(key);
}
@Override
public void remove() {
synchronized (map) {
V value = map.get(key);
if (value != null) {
map.remove(key);
notifyRemovedListeners(key);
}
}
}
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return map.get(value);
}
@Override
public <T> T unwrap(Class<T> clazz) {
return null;
}
@Override
public void setValue(V value) {
map.put(key, value);
}
},
arguments);
}
}
}
return null;
}
/** {@inheritDoc} */
@Override
public String getName() {
return name;
}
/** {@inheritDoc} */
@Override
public CacheManager getCacheManager() {
return manager;
}
/** {@inheritDoc} */
@Override
public void close() {}
/** {@inheritDoc} */
@Override
public boolean isClosed() {
return false;
}
/** {@inheritDoc} */
@Override
@SuppressWarnings("unchecked")
public <T> T unwrap(Class<T> clazz) {
if (Map.class.isAssignableFrom(clazz)) {
return (T) map;
}
return null;
}
/** {@inheritDoc} */
@Override
public void registerCacheEntryListener(
CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration) {
//cacheEntryRemovedListeners.add(cacheEntryListenerConfiguration.getCacheEntryListenerFactory().create());
}
/** {@inheritDoc} */
@Override
public void deregisterCacheEntryListener(
CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration) {}
/** {@inheritDoc} */
@Override
public Iterator<Entry<K, V>> iterator() {
synchronized (map) {
return new Iterator<Entry<K, V>>() {
Iterator<Map.Entry<K, V>> entries = map.entrySet().iterator();
@Override
public boolean hasNext() {
return entries.hasNext();
}
@Override
public Entry<K, V> next() {
Map.Entry<K, V> entry = entries.next();
return new Entry<K, V>() {
K key = entry.getKey();
V value = entry.getValue();
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return value;
}
@Override
public <T> T unwrap(Class<T> clazz) {
return null;
}
};
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}
private void notifyRemovedListeners(K key) {
// if (cacheEntryRemovedListeners != null) {
// cacheEntryRemovedListeners.forEach(listener -> listener.onRemoved())
// }
}
private void notifyRemovedListeners(Set<? extends K> keys) {}
}

View file

@ -0,0 +1,60 @@
/*
* Copyright (C) 2015 The Helenus Authors
*
* 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.helenus.core.cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalListener;
import com.google.common.cache.RemovalNotification;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public interface SessionCache<K, V> {
static final Logger LOG = LoggerFactory.getLogger(SessionCache.class);
static <K, V> SessionCache<K, V> defaultCache() {
GuavaCache<K, V> cache;
RemovalListener<K, V> listener =
new RemovalListener<K, V>() {
@Override
public void onRemoval(RemovalNotification<K, V> n) {
if (n.wasEvicted()) {
String cause = n.getCause().name();
LOG.info(cause);
}
}
};
cache =
new GuavaCache<K, V>(
CacheBuilder.newBuilder()
.maximumSize(25_000)
.expireAfterAccess(5, TimeUnit.MINUTES)
.softValues()
.removalListener(listener)
.build());
return cache;
}
void invalidate(K key);
V get(K key);
void put(K key, V value);
}

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,7 +19,6 @@ import java.util.*;
import net.helenus.core.*; import net.helenus.core.*;
import net.helenus.core.cache.Facet; import net.helenus.core.cache.Facet;
import net.helenus.core.cache.UnboundFacet; import net.helenus.core.cache.UnboundFacet;
import net.helenus.core.reflect.HelenusPropertyNode;
import net.helenus.mapping.HelenusProperty; import net.helenus.mapping.HelenusProperty;
public abstract class AbstractFilterOperation<E, O extends AbstractFilterOperation<E, O>> public abstract class AbstractFilterOperation<E, O extends AbstractFilterOperation<E, O>>
@ -110,28 +108,6 @@ public abstract class AbstractFilterOperation<E, O extends AbstractFilterOperati
ifFilters.add(filter); ifFilters.add(filter);
} }
@Override
protected boolean isIdempotentOperation() {
if (filters == null) {
return super.isIdempotentOperation();
}
return filters
.stream()
.anyMatch(
filter -> {
HelenusPropertyNode node = filter.getNode();
if (node != null) {
HelenusProperty prop = node.getProperty();
if (prop != null) {
return prop.isIdempotent();
}
}
return false;
})
|| super.isIdempotentOperation();
}
protected List<Facet> bindFacetValues(List<Facet> facets) { protected List<Facet> bindFacetValues(List<Facet> facets) {
if (facets == null) { if (facets == null) {
return new ArrayList<Facet>(); return new ArrayList<Facet>();

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -43,7 +42,7 @@ public abstract class AbstractFilterStreamOperation<
public <V> O where(Getter<V> getter, Operator operator, V val) { public <V> O where(Getter<V> getter, Operator operator, V val) {
if (val != null) addFilter(Filter.create(getter, operator, val)); addFilter(Filter.create(getter, operator, val));
return (O) this; return (O) this;
} }
@ -64,7 +63,7 @@ public abstract class AbstractFilterStreamOperation<
public <V> O and(Getter<V> getter, Operator operator, V val) { public <V> O and(Getter<V> getter, Operator operator, V val) {
if (val != null) addFilter(Filter.create(getter, operator, val)); addFilter(Filter.create(getter, operator, val));
return (O) this; return (O) this;
} }
@ -85,7 +84,7 @@ public abstract class AbstractFilterStreamOperation<
public <V> O onlyIf(Getter<V> getter, Operator operator, V val) { public <V> O onlyIf(Getter<V> getter, Operator operator, V val) {
if (val != null) addIfFilter(Filter.create(getter, operator, val)); addIfFilter(Filter.create(getter, operator, val));
return (O) this; return (O) this;
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,6 +20,8 @@ import com.datastax.driver.core.ResultSet;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException; import java.util.concurrent.CompletionException;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import com.datastax.driver.core.Statement;
import net.helenus.core.AbstractSessionOperations; import net.helenus.core.AbstractSessionOperations;
import net.helenus.core.UnitOfWork; import net.helenus.core.UnitOfWork;
@ -40,9 +41,8 @@ public abstract class AbstractOperation<E, O extends AbstractOperation<E, O>>
public E sync() throws TimeoutException { public E sync() throws TimeoutException {
final Timer.Context context = requestLatency.time(); final Timer.Context context = requestLatency.time();
try { try {
ResultSet resultSet = ResultSet resultSet = this.execute(sessionOps,null, traceContext, queryExecutionTimeout, queryTimeoutUnits,
this.execute( showValues,false);
sessionOps, null, queryExecutionTimeout, queryTimeoutUnits, showValues, false);
return transform(resultSet); return transform(resultSet);
} finally { } finally {
context.stop(); context.stop();
@ -54,8 +54,11 @@ public abstract class AbstractOperation<E, O extends AbstractOperation<E, O>>
final Timer.Context context = requestLatency.time(); final Timer.Context context = requestLatency.time();
try { try {
ResultSet resultSet = ResultSet resultSet = execute(sessionOps, uow, traceContext,
execute(sessionOps, uow, queryExecutionTimeout, queryTimeoutUnits, showValues, true); queryExecutionTimeout,
queryTimeoutUnits,
showValues,
true);
E result = transform(resultSet); E result = transform(resultSet);
return result; return result;
} finally { } finally {
@ -76,8 +79,7 @@ public abstract class AbstractOperation<E, O extends AbstractOperation<E, O>>
public CompletableFuture<E> async(UnitOfWork uow) { public CompletableFuture<E> async(UnitOfWork uow) {
if (uow == null) return async(); if (uow == null) return async();
CompletableFuture<E> f = return CompletableFuture.<E>supplyAsync(
CompletableFuture.<E>supplyAsync(
() -> { () -> {
try { try {
return sync(); return sync();
@ -85,7 +87,5 @@ public abstract class AbstractOperation<E, O extends AbstractOperation<E, O>>
throw new CompletionException(ex); throw new CompletionException(ex);
} }
}); });
uow.addFuture(f);
return f;
} }
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -25,20 +24,16 @@ import com.google.common.base.Function;
import com.google.common.base.Stopwatch; import com.google.common.base.Stopwatch;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import java.io.Serializable;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException; import java.util.concurrent.CompletionException;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import net.helenus.core.AbstractSessionOperations; import net.helenus.core.AbstractSessionOperations;
import net.helenus.core.Helenus;
import net.helenus.core.UnitOfWork; import net.helenus.core.UnitOfWork;
import net.helenus.core.cache.CacheUtil; import net.helenus.core.cache.CacheUtil;
import net.helenus.core.cache.Facet; import net.helenus.core.cache.Facet;
import net.helenus.mapping.MappingUtil;
import net.helenus.support.Fun; import net.helenus.support.Fun;
import org.apache.commons.lang3.SerializationUtils;
public abstract class AbstractOptionalOperation<E, O extends AbstractOptionalOperation<E, O>> public abstract class AbstractOptionalOperation<E, O extends AbstractOptionalOperation<E, O>>
extends AbstractStatementOperation<E, O> { extends AbstractStatementOperation<E, O> {
@ -74,8 +69,6 @@ public abstract class AbstractOptionalOperation<E, O extends AbstractOptionalOpe
if (updateCache) { if (updateCache) {
List<Facet> facets = bindFacetValues(); List<Facet> facets = bindFacetValues();
if (facets != null && facets.size() > 0) {
if (facets.stream().filter(f -> !f.fixed()).distinct().count() > 0) {
String tableName = CacheUtil.schemaName(facets); String tableName = CacheUtil.schemaName(facets);
cacheResult = (E) sessionOps.checkCache(tableName, facets); cacheResult = (E) sessionOps.checkCache(tableName, facets);
if (cacheResult != null) { if (cacheResult != null) {
@ -88,10 +81,6 @@ public abstract class AbstractOptionalOperation<E, O extends AbstractOptionalOpe
cacheMiss.mark(); cacheMiss.mark();
} }
} }
} else {
//TODO(gburd): look in statement cache for results
}
}
if (!result.isPresent()) { if (!result.isPresent()) {
// Formulate the query and execute it against the Cassandra cluster. // Formulate the query and execute it against the Cassandra cluster.
@ -99,6 +88,7 @@ public abstract class AbstractOptionalOperation<E, O extends AbstractOptionalOpe
this.execute( this.execute(
sessionOps, sessionOps,
null, null,
traceContext,
queryExecutionTimeout, queryExecutionTimeout,
queryTimeoutUnits, queryTimeoutUnits,
showValues, showValues,
@ -110,9 +100,7 @@ public abstract class AbstractOptionalOperation<E, O extends AbstractOptionalOpe
if (updateCache && result.isPresent()) { if (updateCache && result.isPresent()) {
E r = result.get(); E r = result.get();
Class<?> resultClass = r.getClass(); if (!(r instanceof Fun)) {
if (!(resultClass.getEnclosingClass() != null
&& resultClass.getEnclosingClass() == Fun.class)) {
List<Facet> facets = getFacets(); List<Facet> facets = getFacets();
if (facets != null && facets.size() > 1) { if (facets != null && facets.size() > 1) {
sessionOps.updateCache(r, facets); sessionOps.updateCache(r, facets);
@ -125,7 +113,7 @@ public abstract class AbstractOptionalOperation<E, O extends AbstractOptionalOpe
} }
} }
public Optional<E> sync(UnitOfWork uow) throws TimeoutException { public Optional<E> sync(UnitOfWork<?> uow) throws TimeoutException {
if (uow == null) return sync(); if (uow == null) return sync();
final Timer.Context context = requestLatency.time(); final Timer.Context context = requestLatency.time();
@ -139,8 +127,7 @@ public abstract class AbstractOptionalOperation<E, O extends AbstractOptionalOpe
Stopwatch timer = Stopwatch.createStarted(); Stopwatch timer = Stopwatch.createStarted();
try { try {
List<Facet> facets = bindFacetValues(); List<Facet> facets = bindFacetValues();
if (facets != null && facets.size() > 0) { if (facets != null) {
if (facets.stream().filter(f -> !f.fixed()).distinct().count() > 0) {
cachedResult = checkCache(uow, facets); cachedResult = checkCache(uow, facets);
if (cachedResult != null) { if (cachedResult != null) {
updateCache = false; updateCache = false;
@ -149,41 +136,23 @@ public abstract class AbstractOptionalOperation<E, O extends AbstractOptionalOpe
cacheHits.mark(); cacheHits.mark();
uow.recordCacheAndDatabaseOperationCount(1, 0); uow.recordCacheAndDatabaseOperationCount(1, 0);
} else { } else {
updateCache = true;
uowCacheMiss.mark(); uowCacheMiss.mark();
if (isSessionCacheable()) { if (isSessionCacheable()) {
String tableName = CacheUtil.schemaName(facets); String tableName = CacheUtil.schemaName(facets);
cachedResult = (E) sessionOps.checkCache(tableName, facets); cachedResult = (E) sessionOps.checkCache(tableName, facets);
if (cachedResult != null) { if (cachedResult != null) {
Class<?> iface = MappingUtil.getMappingInterface(cachedResult);
if (Helenus.entity(iface).isDraftable()) {
result = Optional.of(cachedResult); result = Optional.of(cachedResult);
} else {
result =
Optional.of(
(E)
SerializationUtils.<Serializable>clone(
(Serializable) cachedResult));
}
updateCache = false;
sessionCacheHits.mark(); sessionCacheHits.mark();
cacheHits.mark(); cacheHits.mark();
uow.recordCacheAndDatabaseOperationCount(1, 0); uow.recordCacheAndDatabaseOperationCount(1, 0);
} else { } else {
updateCache = true;
sessionCacheMiss.mark(); sessionCacheMiss.mark();
cacheMiss.mark(); cacheMiss.mark();
uow.recordCacheAndDatabaseOperationCount(-1, 0); uow.recordCacheAndDatabaseOperationCount(-1, 0);
} }
} else {
updateCache = false;
} }
} }
} else {
//TODO(gburd): look in statement cache for results
updateCache = false; //true;
cacheMiss.mark();
uow.recordCacheAndDatabaseOperationCount(-1, 0);
}
} else { } else {
updateCache = false; updateCache = false;
} }
@ -206,7 +175,14 @@ public abstract class AbstractOptionalOperation<E, O extends AbstractOptionalOpe
// Formulate the query and execute it against the Cassandra cluster. // Formulate the query and execute it against the Cassandra cluster.
ResultSet resultSet = ResultSet resultSet =
execute(sessionOps, uow, queryExecutionTimeout, queryTimeoutUnits, showValues, true); execute(
sessionOps,
uow,
traceContext,
queryExecutionTimeout,
queryTimeoutUnits,
showValues,
true);
// Transform the query result set into the desired shape. // Transform the query result set into the desired shape.
result = transform(resultSet); result = transform(resultSet);
@ -238,10 +214,9 @@ public abstract class AbstractOptionalOperation<E, O extends AbstractOptionalOpe
}); });
} }
public CompletableFuture<Optional<E>> async(UnitOfWork uow) { public CompletableFuture<Optional<E>> async(UnitOfWork<?> uow) {
if (uow == null) return async(); if (uow == null) return async();
CompletableFuture<Optional<E>> f = return CompletableFuture.<Optional<E>>supplyAsync(
CompletableFuture.<Optional<E>>supplyAsync(
() -> { () -> {
try { try {
return sync(); return sync();
@ -249,7 +224,5 @@ public abstract class AbstractOptionalOperation<E, O extends AbstractOptionalOpe
throw new CompletionException(ex); throw new CompletionException(ex);
} }
}); });
uow.addFuture(f);
return f;
} }
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +15,8 @@
*/ */
package net.helenus.core.operation; package net.helenus.core.operation;
import brave.Tracer;
import brave.propagation.TraceContext;
import com.datastax.driver.core.ConsistencyLevel; import com.datastax.driver.core.ConsistencyLevel;
import com.datastax.driver.core.PreparedStatement; import com.datastax.driver.core.PreparedStatement;
import com.datastax.driver.core.RegularStatement; import com.datastax.driver.core.RegularStatement;
@ -46,10 +47,10 @@ public abstract class AbstractStatementOperation<E, O extends AbstractStatementO
private ConsistencyLevel consistencyLevel; private ConsistencyLevel consistencyLevel;
private ConsistencyLevel serialConsistencyLevel; private ConsistencyLevel serialConsistencyLevel;
private RetryPolicy retryPolicy; private RetryPolicy retryPolicy;
private boolean idempotent = false;
private boolean enableTracing = false; private boolean enableTracing = false;
private long[] defaultTimestamp = null; private long[] defaultTimestamp = null;
private int[] fetchSize = null; private int[] fetchSize = null;
protected boolean idempotent = false;
public AbstractStatementOperation(AbstractSessionOperations sessionOperations) { public AbstractStatementOperation(AbstractSessionOperations sessionOperations) {
super(sessionOperations); super(sessionOperations);
@ -246,16 +247,22 @@ public abstract class AbstractStatementOperation<E, O extends AbstractStatementO
statement.setFetchSize(fetchSize[0]); statement.setFetchSize(fetchSize[0]);
} }
if (isIdempotentOperation()) { if (idempotent) {
statement.setIdempotent(true); statement.setIdempotent(true);
} }
return statement; return statement;
} }
@Override public O zipkinContext(TraceContext traceContext) {
protected boolean isIdempotentOperation() { if (traceContext != null) {
return idempotent; Tracer tracer = this.sessionOps.getZipkinTracer();
if (tracer != null) {
this.traceContext = traceContext;
}
}
return (O) this;
} }
public Statement statement() { public Statement statement() {
@ -305,7 +312,7 @@ public abstract class AbstractStatementOperation<E, O extends AbstractStatementO
return ignoreCache; return ignoreCache;
} }
protected E checkCache(UnitOfWork uow, List<Facet> facets) { protected E checkCache(UnitOfWork<?> uow, List<Facet> facets) {
E result = null; E result = null;
Optional<Object> optionalCachedResult = Optional.empty(); Optional<Object> optionalCachedResult = Optional.empty();
@ -319,7 +326,7 @@ public abstract class AbstractStatementOperation<E, O extends AbstractStatementO
return result; return result;
} }
protected Object cacheUpdate(UnitOfWork uow, E pojo, List<Facet> identifyingFacets) { protected void cacheUpdate(UnitOfWork<?> uow, E pojo, List<Facet> identifyingFacets) {
List<Facet> facets = new ArrayList<>(); List<Facet> facets = new ArrayList<>();
Map<String, Object> valueMap = Map<String, Object> valueMap =
pojo instanceof MapExportable ? ((MapExportable) pojo).toMap() : null; pojo instanceof MapExportable ? ((MapExportable) pojo).toMap() : null;
@ -351,6 +358,6 @@ public abstract class AbstractStatementOperation<E, O extends AbstractStatementO
} }
// Cache the value (pojo), the statement key, and the fully bound facets. // Cache the value (pojo), the statement key, and the fully bound facets.
return uow.cacheUpdate(pojo, facets); uow.cacheUpdate(pojo, facets);
} }
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -25,7 +24,6 @@ import com.google.common.base.Function;
import com.google.common.base.Stopwatch; import com.google.common.base.Stopwatch;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@ -33,13 +31,10 @@ import java.util.concurrent.CompletionException;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.stream.Stream; import java.util.stream.Stream;
import net.helenus.core.AbstractSessionOperations; import net.helenus.core.AbstractSessionOperations;
import net.helenus.core.Helenus;
import net.helenus.core.UnitOfWork; import net.helenus.core.UnitOfWork;
import net.helenus.core.cache.CacheUtil; import net.helenus.core.cache.CacheUtil;
import net.helenus.core.cache.Facet; import net.helenus.core.cache.Facet;
import net.helenus.mapping.MappingUtil;
import net.helenus.support.Fun; import net.helenus.support.Fun;
import org.apache.commons.lang3.SerializationUtils;
public abstract class AbstractStreamOperation<E, O extends AbstractStreamOperation<E, O>> public abstract class AbstractStreamOperation<E, O extends AbstractStreamOperation<E, O>>
extends AbstractStatementOperation<E, O> { extends AbstractStatementOperation<E, O> {
@ -75,8 +70,6 @@ public abstract class AbstractStreamOperation<E, O extends AbstractStreamOperati
if (!ignoreCache() && isSessionCacheable()) { if (!ignoreCache() && isSessionCacheable()) {
List<Facet> facets = bindFacetValues(); List<Facet> facets = bindFacetValues();
if (facets != null && facets.size() > 0) {
if (facets.stream().filter(f -> !f.fixed()).distinct().count() > 0) {
String tableName = CacheUtil.schemaName(facets); String tableName = CacheUtil.schemaName(facets);
cacheResult = (E) sessionOps.checkCache(tableName, facets); cacheResult = (E) sessionOps.checkCache(tableName, facets);
if (cacheResult != null) { if (cacheResult != null) {
@ -88,10 +81,6 @@ public abstract class AbstractStreamOperation<E, O extends AbstractStreamOperati
sessionCacheMiss.mark(); sessionCacheMiss.mark();
cacheMiss.mark(); cacheMiss.mark();
} }
} else {
//TODO(gburd): look in statement cache for results
}
}
} }
if (resultStream == null) { if (resultStream == null) {
@ -100,6 +89,7 @@ public abstract class AbstractStreamOperation<E, O extends AbstractStreamOperati
this.execute( this.execute(
sessionOps, sessionOps,
null, null,
traceContext,
queryExecutionTimeout, queryExecutionTimeout,
queryTimeoutUnits, queryTimeoutUnits,
showValues, showValues,
@ -115,9 +105,7 @@ public abstract class AbstractStreamOperation<E, O extends AbstractStreamOperati
List<E> again = new ArrayList<>(); List<E> again = new ArrayList<>();
resultStream.forEach( resultStream.forEach(
result -> { result -> {
Class<?> resultClass = result.getClass(); if (!(result instanceof Fun)) {
if (!(resultClass.getEnclosingClass() != null
&& resultClass.getEnclosingClass() == Fun.class)) {
sessionOps.updateCache(result, facets); sessionOps.updateCache(result, facets);
} }
again.add(result); again.add(result);
@ -145,8 +133,7 @@ public abstract class AbstractStreamOperation<E, O extends AbstractStreamOperati
Stopwatch timer = Stopwatch.createStarted(); Stopwatch timer = Stopwatch.createStarted();
try { try {
List<Facet> facets = bindFacetValues(); List<Facet> facets = bindFacetValues();
if (facets != null && facets.size() > 0) { if (facets != null) {
if (facets.stream().filter(f -> !f.fixed()).distinct().count() > 0) {
cachedResult = checkCache(uow, facets); cachedResult = checkCache(uow, facets);
if (cachedResult != null) { if (cachedResult != null) {
updateCache = false; updateCache = false;
@ -155,40 +142,23 @@ public abstract class AbstractStreamOperation<E, O extends AbstractStreamOperati
cacheHits.mark(); cacheHits.mark();
uow.recordCacheAndDatabaseOperationCount(1, 0); uow.recordCacheAndDatabaseOperationCount(1, 0);
} else { } else {
updateCache = true;
uowCacheMiss.mark(); uowCacheMiss.mark();
if (isSessionCacheable()) { if (isSessionCacheable()) {
String tableName = CacheUtil.schemaName(facets); String tableName = CacheUtil.schemaName(facets);
cachedResult = (E) sessionOps.checkCache(tableName, facets); cachedResult = (E) sessionOps.checkCache(tableName, facets);
if (cachedResult != null) { if (cachedResult != null) {
Class<?> iface = MappingUtil.getMappingInterface(cachedResult); resultStream = Stream.of(cachedResult);
E result = null;
if (Helenus.entity(iface).isDraftable()) {
result = cachedResult;
} else {
result =
(E) SerializationUtils.<Serializable>clone((Serializable) cachedResult);
}
updateCache = false;
resultStream = Stream.of(result);
sessionCacheHits.mark(); sessionCacheHits.mark();
cacheHits.mark(); cacheHits.mark();
uow.recordCacheAndDatabaseOperationCount(1, 0); uow.recordCacheAndDatabaseOperationCount(1, 0);
} else { } else {
updateCache = true;
sessionCacheMiss.mark(); sessionCacheMiss.mark();
cacheMiss.mark(); cacheMiss.mark();
uow.recordCacheAndDatabaseOperationCount(-1, 0); uow.recordCacheAndDatabaseOperationCount(-1, 0);
} }
} else {
updateCache = false;
} }
} }
} else {
//TODO(gburd): look in statement cache for results
updateCache = false; //true;
cacheMiss.mark();
uow.recordCacheAndDatabaseOperationCount(-1, 0);
}
} else { } else {
updateCache = false; updateCache = false;
} }
@ -203,7 +173,14 @@ public abstract class AbstractStreamOperation<E, O extends AbstractStreamOperati
// Check to see if we fetched the object from the cache // Check to see if we fetched the object from the cache
if (resultStream == null) { if (resultStream == null) {
ResultSet resultSet = ResultSet resultSet =
execute(sessionOps, uow, queryExecutionTimeout, queryTimeoutUnits, showValues, true); execute(
sessionOps,
uow,
traceContext,
queryExecutionTimeout,
queryTimeoutUnits,
showValues,
true);
resultStream = transform(resultSet); resultStream = transform(resultSet);
} }
@ -215,11 +192,8 @@ public abstract class AbstractStreamOperation<E, O extends AbstractStreamOperati
List<Facet> facets = getFacets(); List<Facet> facets = getFacets();
resultStream.forEach( resultStream.forEach(
result -> { result -> {
Class<?> resultClass = result.getClass(); if (result != deleted && !(result instanceof Fun)) {
if (result != deleted cacheUpdate(uow, result, facets);
&& !(resultClass.getEnclosingClass() != null
&& resultClass.getEnclosingClass() == Fun.class)) {
result = (E) cacheUpdate(uow, result, facets);
} }
again.add(result); again.add(result);
}); });
@ -246,8 +220,7 @@ public abstract class AbstractStreamOperation<E, O extends AbstractStreamOperati
public CompletableFuture<Stream<E>> async(UnitOfWork uow) { public CompletableFuture<Stream<E>> async(UnitOfWork uow) {
if (uow == null) return async(); if (uow == null) return async();
CompletableFuture<Stream<E>> f = return CompletableFuture.<Stream<E>>supplyAsync(
CompletableFuture.<Stream<E>>supplyAsync(
() -> { () -> {
try { try {
return sync(); return sync();
@ -255,7 +228,5 @@ public abstract class AbstractStreamOperation<E, O extends AbstractStreamOperati
throw new CompletionException(ex); throw new CompletionException(ex);
} }
}); });
uow.addFuture(f);
return f;
} }
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,31 +16,26 @@
package net.helenus.core.operation; package net.helenus.core.operation;
import com.codahale.metrics.Timer; import com.codahale.metrics.Timer;
import com.datastax.driver.core.AtomicMonotonicTimestampGenerator;
import com.datastax.driver.core.BatchStatement; import com.datastax.driver.core.BatchStatement;
import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.TimestampGenerator;
import com.google.common.base.Stopwatch; import com.google.common.base.Stopwatch;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
import net.helenus.core.AbstractSessionOperations; import net.helenus.core.AbstractSessionOperations;
import net.helenus.core.UnitOfWork; import net.helenus.core.UnitOfWork;
import net.helenus.support.HelenusException; import net.helenus.support.HelenusException;
public class BatchOperation extends Operation<Long> { import java.util.ArrayList;
//TODO(gburd): find the way to get the driver's timestamp generator import java.util.List;
private static final TimestampGenerator timestampGenerator = import java.util.concurrent.TimeoutException;
new AtomicMonotonicTimestampGenerator(); import java.util.stream.Collectors;
private final BatchStatement batch; public class BatchOperation extends Operation<Long> {
private BatchStatement batch = null;
private List<AbstractOperation<?, ?>> operations = new ArrayList<AbstractOperation<?, ?>>(); private List<AbstractOperation<?, ?>> operations = new ArrayList<AbstractOperation<?, ?>>();
private boolean logged = true; private boolean logged = true;
private long timestamp = 0L;
public BatchOperation(AbstractSessionOperations sessionOperations) { public BatchOperation(AbstractSessionOperations sessionOperations) {
super(sessionOperations); super(sessionOperations);
batch = new BatchStatement();
} }
public void add(AbstractOperation<?, ?> operation) { public void add(AbstractOperation<?, ?> operation) {
@ -50,9 +44,11 @@ public class BatchOperation extends Operation<Long> {
@Override @Override
public BatchStatement buildStatement(boolean cached) { public BatchStatement buildStatement(boolean cached) {
batch.addAll( batch = new BatchStatement();
operations.stream().map(o -> o.buildStatement(cached)).collect(Collectors.toList())); batch.addAll(operations.stream().map(o -> o.buildStatement(cached)).collect(Collectors.toList()));
batch.setConsistencyLevel(sessionOps.getDefaultConsistencyLevel()); batch.setConsistencyLevel(sessionOps.getDefaultConsistencyLevel());
timestamp = System.nanoTime();
batch.setDefaultTimestamp(timestamp);
return batch; return batch;
} }
@ -66,48 +62,41 @@ public class BatchOperation extends Operation<Long> {
return this; return this;
} }
public Long sync() { public Long sync() throws TimeoutException {
if (operations.size() == 0) return 0L; if (operations.size() == 0) return 0L;
final Timer.Context context = requestLatency.time(); final Timer.Context context = requestLatency.time();
try { try {
batch.setDefaultTimestamp(timestampGenerator.next()); timestamp = System.nanoTime();
ResultSet resultSet = batch.setDefaultTimestamp(timestamp);
this.execute( ResultSet resultSet = this.execute(sessionOps, null, traceContext, queryExecutionTimeout, queryTimeoutUnits, showValues, false);
sessionOps, null, queryExecutionTimeout, queryTimeoutUnits, showValues, false);
if (!resultSet.wasApplied()) { if (!resultSet.wasApplied()) {
throw new HelenusException("Failed to apply batch."); throw new HelenusException("Failed to apply batch.");
} }
} catch (TimeoutException e) {
throw new HelenusException(e);
} finally { } finally {
context.stop(); context.stop();
} }
return batch.getDefaultTimestamp(); return timestamp;
} }
public Long sync(UnitOfWork uow) { public Long sync(UnitOfWork<?> uow) throws TimeoutException {
if (operations.size() == 0) return 0L; if (operations.size() == 0) return 0L;
if (uow == null) return sync(); if (uow == null)
return sync();
final Timer.Context context = requestLatency.time(); final Timer.Context context = requestLatency.time();
final Stopwatch timer = Stopwatch.createStarted(); final Stopwatch timer = Stopwatch.createStarted();
try { try {
uow.recordCacheAndDatabaseOperationCount(0, 1); uow.recordCacheAndDatabaseOperationCount(0, 1);
batch.setDefaultTimestamp(timestampGenerator.next()); ResultSet resultSet = this.execute(sessionOps, uow, traceContext, queryExecutionTimeout, queryTimeoutUnits, showValues, false);
ResultSet resultSet =
this.execute(
sessionOps, uow, queryExecutionTimeout, queryTimeoutUnits, showValues, false);
if (!resultSet.wasApplied()) { if (!resultSet.wasApplied()) {
throw new HelenusException("Failed to apply batch."); throw new HelenusException("Failed to apply batch.");
} }
} catch (TimeoutException e) {
throw new HelenusException(e);
} finally { } finally {
context.stop(); context.stop();
timer.stop(); timer.stop();
} }
uow.addDatabaseTime("Cassandra", timer); uow.addDatabaseTime("Cassandra", timer);
return batch.getDefaultTimestamp(); return timestamp;
} }
public void addAll(BatchOperation batch) { public void addAll(BatchOperation batch) {
@ -115,25 +104,11 @@ public class BatchOperation extends Operation<Long> {
} }
public String toString() { public String toString() {
return toString(true); //TODO(gburd): sessionOps.showQueryValues()
}
public String toString(boolean showValues) {
StringBuilder s = new StringBuilder(); StringBuilder s = new StringBuilder();
s.append("BEGIN "); s.append("BEGIN ");
if (!logged) { if (!logged) { s.append("UN"); }
s.append("UNLOGGED "); s.append("LOGGED BATCH; ");
} s.append(operations.stream().map(o -> Operation.queryString(o.buildStatement(false), showValues)).collect(Collectors.joining(" ")));
s.append("BATCH ");
if (batch.getDefaultTimestamp() > -9223372036854775808L) {
s.append("USING TIMESTAMP ").append(String.valueOf(batch.getDefaultTimestamp())).append(" ");
}
s.append(
operations
.stream()
.map(o -> Operation.queryString(o.buildStatement(showValues), showValues))
.collect(Collectors.joining(" ")));
s.append(" APPLY BATCH;"); s.append(" APPLY BATCH;");
return s.toString(); return s.toString();
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -135,10 +134,6 @@ public final class DeleteOperation extends AbstractFilterOperation<ResultSet, De
return bindFacetValues(getFacets()); return bindFacetValues(getFacets());
} }
protected boolean isIdempotentOperation() {
return true;
}
@Override @Override
public ResultSet sync() throws TimeoutException { public ResultSet sync() throws TimeoutException {
ResultSet result = super.sync(); ResultSet result = super.sync();

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,10 +19,6 @@ import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.querybuilder.BuiltStatement; import com.datastax.driver.core.querybuilder.BuiltStatement;
import com.datastax.driver.core.querybuilder.Insert; import com.datastax.driver.core.querybuilder.Insert;
import com.datastax.driver.core.querybuilder.QueryBuilder; import com.datastax.driver.core.querybuilder.QueryBuilder;
import java.util.*;
import java.util.concurrent.TimeoutException;
import java.util.function.Function;
import java.util.stream.Collectors;
import net.helenus.core.AbstractSessionOperations; import net.helenus.core.AbstractSessionOperations;
import net.helenus.core.Getter; import net.helenus.core.Getter;
import net.helenus.core.Helenus; import net.helenus.core.Helenus;
@ -32,6 +27,7 @@ import net.helenus.core.cache.CacheUtil;
import net.helenus.core.cache.Facet; import net.helenus.core.cache.Facet;
import net.helenus.core.cache.UnboundFacet; import net.helenus.core.cache.UnboundFacet;
import net.helenus.core.reflect.DefaultPrimitiveTypes; import net.helenus.core.reflect.DefaultPrimitiveTypes;
import net.helenus.core.reflect.Drafted;
import net.helenus.core.reflect.HelenusPropertyNode; import net.helenus.core.reflect.HelenusPropertyNode;
import net.helenus.core.reflect.MapExportable; import net.helenus.core.reflect.MapExportable;
import net.helenus.mapping.HelenusEntity; import net.helenus.mapping.HelenusEntity;
@ -42,13 +38,16 @@ import net.helenus.support.Fun;
import net.helenus.support.HelenusException; import net.helenus.support.HelenusException;
import net.helenus.support.HelenusMappingException; import net.helenus.support.HelenusMappingException;
import java.util.*;
import java.util.concurrent.TimeoutException;
import java.util.function.Function;
import java.util.stream.Collectors;
public final class InsertOperation<T> extends AbstractOperation<T, InsertOperation<T>> { public final class InsertOperation<T> extends AbstractOperation<T, InsertOperation<T>> {
private final List<Fun.Tuple2<HelenusPropertyNode, Object>> values = private final List<Fun.Tuple2<HelenusPropertyNode, Object>> values = new ArrayList<Fun.Tuple2<HelenusPropertyNode, Object>>();
new ArrayList<Fun.Tuple2<HelenusPropertyNode, Object>>();
private final T pojo; private final T pojo;
private final Class<?> resultType; private final Class<?> resultType;
private final Set<String> readSet;
private HelenusEntity entity; private HelenusEntity entity;
private boolean ifNotExists; private boolean ifNotExists;
@ -59,48 +58,34 @@ public final class InsertOperation<T> extends AbstractOperation<T, InsertOperati
public InsertOperation(AbstractSessionOperations sessionOperations, boolean ifNotExists) { public InsertOperation(AbstractSessionOperations sessionOperations, boolean ifNotExists) {
super(sessionOperations); super(sessionOperations);
this.pojo = null;
this.readSet = null;
this.ifNotExists = ifNotExists; this.ifNotExists = ifNotExists;
this.pojo = null;
this.resultType = ResultSet.class; this.resultType = ResultSet.class;
} }
public InsertOperation( public InsertOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity, Class<?> resultType, boolean ifNotExists) {
AbstractSessionOperations sessionOperations,
HelenusEntity entity,
Class<?> resultType,
boolean ifNotExists) {
super(sessionOperations); super(sessionOperations);
this.pojo = null;
this.readSet = null;
this.ifNotExists = ifNotExists; this.ifNotExists = ifNotExists;
this.pojo = null;
this.resultType = resultType; this.resultType = resultType;
this.entity = entity; this.entity = entity;
} }
public InsertOperation( public InsertOperation(AbstractSessionOperations sessionOperations, Class<?> resultType, boolean ifNotExists) {
AbstractSessionOperations sessionOperations, Class<?> resultType, boolean ifNotExists) {
super(sessionOperations); super(sessionOperations);
this.pojo = null;
this.readSet = null;
this.ifNotExists = ifNotExists; this.ifNotExists = ifNotExists;
this.pojo = null;
this.resultType = resultType; this.resultType = resultType;
} }
public InsertOperation( public InsertOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity, T pojo,
AbstractSessionOperations sessionOperations, Set<String> mutations, boolean ifNotExists) {
HelenusEntity entity,
T pojo,
Set<String> mutations,
Set<String> read,
boolean ifNotExists) {
super(sessionOperations); super(sessionOperations);
this.entity = entity;
this.pojo = pojo; this.pojo = pojo;
this.readSet = read;
this.entity = entity;
this.ifNotExists = ifNotExists; this.ifNotExists = ifNotExists;
this.resultType = entity.getMappingInterface(); this.resultType = entity.getMappingInterface();
@ -159,28 +144,16 @@ public final class InsertOperation<T> extends AbstractOperation<T, InsertOperati
@Override @Override
public BuiltStatement buildStatement(boolean cached) { public BuiltStatement buildStatement(boolean cached) {
List<HelenusEntity> entities = List<Class<?>> entities = values.stream().map(t -> t._1.getProperty().getEntity().getMappingInterface()).distinct().collect(Collectors.toList());
values
.stream()
.map(t -> t._1.getProperty().getEntity())
.distinct()
.collect(Collectors.toList());
if (entities.size() != 1) { if (entities.size() != 1) {
throw new HelenusMappingException( throw new HelenusMappingException("you can insert only single entity at a time, found: "
"you can insert only single entity at a time, found: " + entities.stream().map(e -> e.toString()).collect(Collectors.joining(", ")));
+ entities
.stream()
.map(e -> e.getMappingInterface().toString())
.collect(Collectors.joining(", ")));
} }
HelenusEntity entity = entities.get(0); HelenusEntity entity = values.get(0)._1.getEntity();
if (this.entity != null) { if (this.entity != null) {
if (this.entity != entity) { if (this.entity != entity) {
throw new HelenusMappingException( throw new HelenusMappingException("you can insert only single entity at a time, found: " +
"you can insert only single entity at a time, found: " this.entity.getMappingInterface().toString() + ", " + entity.getMappingInterface().toString());
+ this.entity.getMappingInterface().toString()
+ ", "
+ entity.getMappingInterface().toString());
} }
} else { } else {
this.entity = entity; this.entity = entity;
@ -217,7 +190,7 @@ public final class InsertOperation<T> extends AbstractOperation<T, InsertOperati
private T newInstance(Class<?> iface) { private T newInstance(Class<?> iface) {
if (values.size() > 0) { if (values.size() > 0) {
boolean immutable = entity.isDraftable(); boolean immutable = iface.isAssignableFrom(Drafted.class);
Collection<HelenusProperty> properties = entity.getOrderedProperties(); Collection<HelenusProperty> properties = entity.getOrderedProperties();
Map<String, Object> backingMap = new HashMap<String, Object>(properties.size()); Map<String, Object> backingMap = new HashMap<String, Object>(properties.size());
@ -230,8 +203,8 @@ public final class InsertOperation<T> extends AbstractOperation<T, InsertOperati
if (backingMap.containsKey(key)) { if (backingMap.containsKey(key)) {
// Some values man need to be converted (e.g. from String to Enum). This is done // Some values man need to be converted (e.g. from String to Enum). This is done
// within the BeanColumnValueProvider below. // within the BeanColumnValueProvider below.
Optional<Function<Object, Object>> converter = Optional<Function<Object, Object>> converter = prop.getReadConverter(
prop.getReadConverter(sessionOps.getSessionRepository()); sessionOps.getSessionRepository());
if (converter.isPresent()) { if (converter.isPresent()) {
backingMap.put(key, converter.get().apply(backingMap.get(key))); backingMap.put(key, converter.get().apply(backingMap.get(key)));
} }
@ -239,8 +212,7 @@ public final class InsertOperation<T> extends AbstractOperation<T, InsertOperati
// If we started this operation with an instance of this type, use values from // If we started this operation with an instance of this type, use values from
// that. // that.
if (pojo != null) { if (pojo != null) {
backingMap.put( backingMap.put(key, BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop, immutable));
key, BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop, immutable));
} else { } else {
// Otherwise we'll use default values for the property type if available. // Otherwise we'll use default values for the property type if available.
Class<?> propType = prop.getJavaType(); Class<?> propType = prop.getJavaType();
@ -293,12 +265,9 @@ public final class InsertOperation<T> extends AbstractOperation<T, InsertOperati
protected void adjustTtlAndWriteTime(MapExportable pojo) { protected void adjustTtlAndWriteTime(MapExportable pojo) {
if (ttl != null || writeTime != 0L) { if (ttl != null || writeTime != 0L) {
List<String> columnNames = List<String> propertyNames = values.stream()
values
.stream()
.map(t -> t._1.getProperty()) .map(t -> t._1.getProperty())
.filter( .filter(prop -> {
prop -> {
switch (prop.getColumnType()) { switch (prop.getColumnType()) {
case PARTITION_KEY: case PARTITION_KEY:
case CLUSTERING_COLUMN: case CLUSTERING_COLUMN:
@ -310,23 +279,17 @@ public final class InsertOperation<T> extends AbstractOperation<T, InsertOperati
.map(prop -> prop.getColumnName().toCql(false)) .map(prop -> prop.getColumnName().toCql(false))
.collect(Collectors.toList()); .collect(Collectors.toList());
if (columnNames.size() > 0) { if (propertyNames.size() > 0) {
if (ttl != null) { if (ttl != null) {
columnNames.forEach(name -> pojo.put(CacheUtil.ttlKey(name), ttl)); propertyNames.forEach(name -> pojo.put(CacheUtil.ttlKey(name), ttl));
} }
if (writeTime != 0L) { if (writeTime != 0L) {
columnNames.forEach(name -> pojo.put(CacheUtil.writeTimeKey(name), writeTime)); propertyNames.forEach(name -> pojo.put(CacheUtil.writeTimeKey(name), writeTime));
} }
} }
} }
} }
@Override
protected boolean isIdempotentOperation() {
return values.stream().map(v -> v._1.getProperty()).allMatch(prop -> prop.isIdempotent())
|| super.isIdempotentOperation();
}
@Override @Override
public T sync() throws TimeoutException { public T sync() throws TimeoutException {
T result = super.sync(); T result = super.sync();
@ -358,6 +321,10 @@ public final class InsertOperation<T> extends AbstractOperation<T, InsertOperati
adjustTtlAndWriteTime((MapExportable) result); adjustTtlAndWriteTime((MapExportable) result);
} }
cacheUpdate(uow, result, bindFacetValues()); cacheUpdate(uow, result, bindFacetValues());
} else {
if (entity.isCacheable()) {
sessionOps.cacheEvict(bindFacetValues());
}
} }
return result; return result;
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +15,9 @@
*/ */
package net.helenus.core.operation; package net.helenus.core.operation;
import brave.Span;
import brave.Tracer;
import brave.propagation.TraceContext;
import com.codahale.metrics.Meter; import com.codahale.metrics.Meter;
import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer; import com.codahale.metrics.Timer;
@ -40,7 +42,8 @@ public abstract class Operation<E> {
private static final Logger LOG = LoggerFactory.getLogger(Operation.class); private static final Logger LOG = LoggerFactory.getLogger(Operation.class);
protected final AbstractSessionOperations sessionOps; protected final AbstractSessionOperations sessionOps;
protected boolean showValues; protected boolean showValues = false;
protected TraceContext traceContext;
protected long queryExecutionTimeout = 10; protected long queryExecutionTimeout = 10;
protected TimeUnit queryTimeoutUnits = TimeUnit.SECONDS; protected TimeUnit queryTimeoutUnits = TimeUnit.SECONDS;
protected final Meter uowCacheHits; protected final Meter uowCacheHits;
@ -53,7 +56,7 @@ public abstract class Operation<E> {
Operation(AbstractSessionOperations sessionOperations) { Operation(AbstractSessionOperations sessionOperations) {
this.sessionOps = sessionOperations; this.sessionOps = sessionOperations;
this.showValues = sessionOps.showValues(); this.showValues = !sessionOps.obscureValuesInQueries();
MetricRegistry metrics = sessionOperations.getMetricRegistry(); MetricRegistry metrics = sessionOperations.getMetricRegistry();
if (metrics == null) { if (metrics == null) {
metrics = new MetricRegistry(); metrics = new MetricRegistry();
@ -67,10 +70,6 @@ public abstract class Operation<E> {
this.requestLatency = metrics.timer("net.helenus.request-latency"); this.requestLatency = metrics.timer("net.helenus.request-latency");
} }
public static String queryString(BatchOperation operation, boolean includeValues) {
return operation.toString(includeValues);
}
public static String queryString(Statement statement, boolean includeValues) { public static String queryString(Statement statement, boolean includeValues) {
String query = null; String query = null;
if (statement instanceof BuiltStatement) { if (statement instanceof BuiltStatement) {
@ -93,31 +92,31 @@ public abstract class Operation<E> {
public ResultSet execute( public ResultSet execute(
AbstractSessionOperations session, AbstractSessionOperations session,
UnitOfWork uow, UnitOfWork uow,
TraceContext traceContext,
long timeout, long timeout,
TimeUnit units, TimeUnit units,
boolean showValues, boolean showValues,
boolean cached) boolean cached)
throws TimeoutException { throws TimeoutException {
Statement statement = options(buildStatement(cached)); // Start recording in a Zipkin sub-span our execution time to perform this operation.
Tracer tracer = session.getZipkinTracer();
if (session.isShowCql()) { Span span = null;
String stmt = if (tracer != null && traceContext != null) {
(this instanceof BatchOperation) span = tracer.newChild(traceContext);
? queryString((BatchOperation) this, showValues)
: queryString(statement, showValues);
session.getPrintStream().println(stmt);
} else if (LOG.isDebugEnabled()) {
String stmt =
(this instanceof BatchOperation)
? queryString((BatchOperation) this, showValues)
: queryString(statement, showValues);
LOG.info("CQL> " + stmt);
} }
try {
if (span != null) {
span.name("cassandra");
span.start();
}
Statement statement = options(buildStatement(cached));
Stopwatch timer = Stopwatch.createStarted(); Stopwatch timer = Stopwatch.createStarted();
try { try {
ResultSetFuture futureResultSet = session.executeAsync(statement, uow, timer); ResultSetFuture futureResultSet = session.executeAsync(statement, uow, timer, showValues);
if (uow != null) uow.recordCacheAndDatabaseOperationCount(0, 1); if (uow != null) uow.recordCacheAndDatabaseOperationCount(0, 1);
ResultSet resultSet = futureResultSet.getUninterruptibly(timeout, units); ResultSet resultSet = futureResultSet.getUninterruptibly(timeout, units);
ColumnDefinitions columnDefinitions = resultSet.getColumnDefinitions(); ColumnDefinitions columnDefinitions = resultSet.getColumnDefinitions();
@ -131,14 +130,11 @@ public abstract class Operation<E> {
.map(InetAddress::toString) .map(InetAddress::toString)
.collect(Collectors.joining(", ")); .collect(Collectors.joining(", "));
ConsistencyLevel cl = ei.getAchievedConsistencyLevel(); ConsistencyLevel cl = ei.getAchievedConsistencyLevel();
if (cl == null) {
cl = statement.getConsistencyLevel();
}
int se = ei.getSpeculativeExecutions(); int se = ei.getSpeculativeExecutions();
String warn = ei.getWarnings().stream().collect(Collectors.joining(", ")); String warn = ei.getWarnings().stream().collect(Collectors.joining(", "));
String ri = String ri =
String.format( String.format(
"%s %s ~%s %s %s%s%sspec-retries: %d", "%s %s %s %s %s %s%sspec-retries: %d",
"server v" + qh.getCassandraVersion(), "server v" + qh.getCassandraVersion(),
qh.getAddress().toString(), qh.getAddress().toString(),
(oh != null && !oh.equals("")) ? " [tried: " + oh + "]" : "", (oh != null && !oh.equals("")) ? " [tried: " + oh + "]" : "",
@ -147,7 +143,6 @@ public abstract class Operation<E> {
(cl != null) (cl != null)
? (" consistency: " ? (" consistency: "
+ cl.name() + cl.name()
+ " "
+ (cl.isDCLocal() ? " DC " : "") + (cl.isDCLocal() ? " DC " : "")
+ (cl.isSerial() ? " SC " : "")) + (cl.isSerial() ? " SC " : ""))
: "", : "",
@ -167,6 +162,13 @@ public abstract class Operation<E> {
if (uow != null) uow.addDatabaseTime("Cassandra", timer); if (uow != null) uow.addDatabaseTime("Cassandra", timer);
log(statement, uow, timer, showValues); log(statement, uow, timer, showValues);
} }
} finally {
if (span != null) {
span.finish();
}
}
} }
void log(Statement statement, UnitOfWork uow, Stopwatch timer, boolean showValues) { void log(Statement statement, UnitOfWork uow, Stopwatch timer, boolean showValues) {
@ -180,15 +182,10 @@ public abstract class Operation<E> {
timerString = String.format(" %s ", timer.toString()); timerString = String.format(" %s ", timer.toString());
} }
LOG.info( LOG.info(
String.format( String.format("%s%s%s", uowString, timerString, Operation.queryString(statement, showValues)));
"%s%s%s", uowString, timerString, Operation.queryString(statement, showValues)));
} }
} }
protected boolean isIdempotentOperation() {
return false;
}
public Statement options(Statement statement) { public Statement options(Statement statement) {
return statement; return statement;
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -66,7 +65,5 @@ public final class SelectFirstOperation<E>
} }
@Override @Override
public boolean ignoreCache() { public boolean ignoreCache() { return delegate.ignoreCache(); }
return delegate.ignoreCache();
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -59,7 +58,5 @@ public final class SelectFirstTransformingOperation<R, E>
} }
@Override @Override
public boolean ignoreCache() { public boolean ignoreCache() { return delegate.ignoreCache(); }
return delegate.ignoreCache();
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -24,6 +23,7 @@ import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Select; import com.datastax.driver.core.querybuilder.Select;
import com.datastax.driver.core.querybuilder.Select.Selection; import com.datastax.driver.core.querybuilder.Select.Selection;
import com.datastax.driver.core.querybuilder.Select.Where; import com.datastax.driver.core.querybuilder.Select.Where;
import com.google.common.collect.Iterables;
import java.util.*; import java.util.*;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -97,10 +97,7 @@ public final class SelectOperation<E> extends AbstractFilterStreamOperation<E, S
this.implementsEntityType = Entity.class.isAssignableFrom(entity.getMappingInterface()); this.implementsEntityType = Entity.class.isAssignableFrom(entity.getMappingInterface());
} }
public SelectOperation( public SelectOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity, Function<Row, E> rowMapper) {
AbstractSessionOperations sessionOperations,
HelenusEntity entity,
Function<Row, E> rowMapper) {
super(sessionOperations); super(sessionOperations);
this.rowMapper = rowMapper; this.rowMapper = rowMapper;
@ -115,9 +112,7 @@ public final class SelectOperation<E> extends AbstractFilterStreamOperation<E, S
this.implementsEntityType = Entity.class.isAssignableFrom(entity.getMappingInterface()); this.implementsEntityType = Entity.class.isAssignableFrom(entity.getMappingInterface());
} }
public SelectOperation( public SelectOperation(AbstractSessionOperations sessionOperations, Function<Row, E> rowMapper,
AbstractSessionOperations sessionOperations,
Function<Row, E> rowMapper,
HelenusPropertyNode... props) { HelenusPropertyNode... props) {
super(sessionOperations); super(sessionOperations);
@ -315,9 +310,7 @@ public final class SelectOperation<E> extends AbstractFilterStreamOperation<E, S
for (Filter<?> filter : filters.values()) { for (Filter<?> filter : filters.values()) {
where.and(filter.getClause(sessionOps.getValuePreparer())); where.and(filter.getClause(sessionOps.getValuePreparer()));
HelenusProperty filterProp = filter.getNode().getProperty(); HelenusProperty filterProp = filter.getNode().getProperty();
HelenusProperty prop = HelenusProperty prop = props.stream()
props
.stream()
.map(HelenusPropertyNode::getProperty) .map(HelenusPropertyNode::getProperty)
.filter(thisProp -> thisProp.getPropertyName().equals(filterProp.getPropertyName())) .filter(thisProp -> thisProp.getPropertyName().equals(filterProp.getPropertyName()))
.findFirst() .findFirst()

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -59,12 +58,8 @@ public final class SelectTransformingOperation<R, E>
} }
@Override @Override
public boolean isSessionCacheable() { public boolean isSessionCacheable() { return delegate.isSessionCacheable(); }
return delegate.isSessionCacheable();
}
@Override @Override
public boolean ignoreCache() { public boolean ignoreCache() { return delegate.ignoreCache(); }
return delegate.ignoreCache();
}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -35,16 +34,19 @@ import net.helenus.mapping.HelenusEntity;
import net.helenus.mapping.HelenusProperty; import net.helenus.mapping.HelenusProperty;
import net.helenus.mapping.MappingUtil; import net.helenus.mapping.MappingUtil;
import net.helenus.mapping.value.BeanColumnValueProvider; import net.helenus.mapping.value.BeanColumnValueProvider;
import net.helenus.mapping.value.ValueProviderMap;
import net.helenus.support.HelenusException; import net.helenus.support.HelenusException;
import net.helenus.support.HelenusMappingException; import net.helenus.support.HelenusMappingException;
import net.helenus.support.Immutables; import net.helenus.support.Immutables;
import static net.helenus.mapping.ColumnType.CLUSTERING_COLUMN;
import static net.helenus.mapping.ColumnType.PARTITION_KEY;
public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateOperation<E>> { public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateOperation<E>> {
private final Map<Assignment, BoundFacet> assignments = new HashMap<>(); private final Map<Assignment, BoundFacet> assignments = new HashMap<>();
private final AbstractEntityDraft<E> draft; private final AbstractEntityDraft<E> draft;
private final Map<String, Object> draftMap; private final Map<String, Object> draftMap;
private final Set<String> readSet;
private HelenusEntity entity = null; private HelenusEntity entity = null;
private Object pojo; private Object pojo;
private int[] ttl; private int[] ttl;
@ -55,7 +57,6 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
super(sessionOperations); super(sessionOperations);
this.draft = null; this.draft = null;
this.draftMap = null; this.draftMap = null;
this.readSet = null;
} }
public UpdateOperation( public UpdateOperation(
@ -63,7 +64,6 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
super(sessionOperations); super(sessionOperations);
this.draft = draft; this.draft = draft;
this.draftMap = draft.toMap(); this.draftMap = draft.toMap();
this.readSet = draft.read();
} }
public UpdateOperation(AbstractSessionOperations sessionOperations, Object pojo) { public UpdateOperation(AbstractSessionOperations sessionOperations, Object pojo) {
@ -75,12 +75,7 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
this.entity = Helenus.resolve(MappingUtil.getMappingInterface(pojo)); this.entity = Helenus.resolve(MappingUtil.getMappingInterface(pojo));
if (this.entity != null && entity.isCacheable() && pojo instanceof MapExportable) { if (this.entity != null && entity.isCacheable() && pojo instanceof MapExportable) {
this.pojo = pojo; this.pojo = pojo;
this.readSet = ((MapExportable) pojo).toReadSet();
} else {
this.readSet = null;
} }
} else {
this.readSet = null;
} }
} }
@ -89,7 +84,6 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
super(sessionOperations); super(sessionOperations);
this.draft = null; this.draft = null;
this.draftMap = null; this.draftMap = null;
this.readSet = null;
Object value = sessionOps.getValuePreparer().prepareColumnValue(v, p.getProperty()); Object value = sessionOps.getValuePreparer().prepareColumnValue(v, p.getProperty());
assignments.put(QueryBuilder.set(p.getColumnName(), value), new BoundFacet(p.getProperty(), v)); assignments.put(QueryBuilder.set(p.getColumnName(), value), new BoundFacet(p.getProperty(), v));
@ -427,8 +421,7 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
Object valueObj = value; Object valueObj = value;
Optional<Function<Object, Object>> converter = Optional<Function<Object, Object>> converter = prop.getWriteConverter(sessionOps.getSessionRepository());
prop.getWriteConverter(sessionOps.getSessionRepository());
if (converter.isPresent()) { if (converter.isPresent()) {
List convertedList = (List) converter.get().apply(Immutables.listOf(value)); List convertedList = (List) converter.get().apply(Immutables.listOf(value));
valueObj = convertedList.get(0); valueObj = convertedList.get(0);
@ -443,8 +436,7 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
List valueObj = value; List valueObj = value;
Optional<Function<Object, Object>> converter = Optional<Function<Object, Object>> converter = prop.getWriteConverter(sessionOps.getSessionRepository());
prop.getWriteConverter(sessionOps.getSessionRepository());
if (converter.isPresent()) { if (converter.isPresent()) {
valueObj = (List) converter.get().apply(value); valueObj = (List) converter.get().apply(value);
} }
@ -589,8 +581,7 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
HelenusProperty prop = p.getProperty(); HelenusProperty prop = p.getProperty();
Object valueObj = value; Object valueObj = value;
Optional<Function<Object, Object>> converter = Optional<Function<Object, Object>> converter = prop.getWriteConverter(sessionOps.getSessionRepository());
prop.getWriteConverter(sessionOps.getSessionRepository());
if (converter.isPresent()) { if (converter.isPresent()) {
Set convertedSet = (Set) converter.get().apply(Immutables.setOf(value)); Set convertedSet = (Set) converter.get().apply(Immutables.setOf(value));
valueObj = convertedSet.iterator().next(); valueObj = convertedSet.iterator().next();
@ -604,8 +595,7 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
HelenusProperty prop = p.getProperty(); HelenusProperty prop = p.getProperty();
Set valueObj = value; Set valueObj = value;
Optional<Function<Object, Object>> converter = Optional<Function<Object, Object>> converter = prop.getWriteConverter(sessionOps.getSessionRepository());
prop.getWriteConverter(sessionOps.getSessionRepository());
if (converter.isPresent()) { if (converter.isPresent()) {
valueObj = (Set) converter.get().apply(value); valueObj = (Set) converter.get().apply(value);
} }
@ -644,11 +634,9 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
facet = null; facet = null;
} }
Optional<Function<Object, Object>> converter = Optional<Function<Object, Object>> converter = prop.getWriteConverter(sessionOps.getSessionRepository());
prop.getWriteConverter(sessionOps.getSessionRepository());
if (converter.isPresent()) { if (converter.isPresent()) {
Map<Object, Object> convertedMap = Map<Object, Object> convertedMap = (Map<Object, Object>) converter.get().apply(Immutables.mapOf(key, value));
(Map<Object, Object>) converter.get().apply(Immutables.mapOf(key, value));
for (Map.Entry<Object, Object> e : convertedMap.entrySet()) { for (Map.Entry<Object, Object> e : convertedMap.entrySet()) {
assignments.put(QueryBuilder.put(p.getColumnName(), e.getKey(), e.getValue()), facet); assignments.put(QueryBuilder.put(p.getColumnName(), e.getKey(), e.getValue()), facet);
} }
@ -684,8 +672,7 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
facet = null; facet = null;
} }
Optional<Function<Object, Object>> converter = Optional<Function<Object, Object>> converter = prop.getWriteConverter(sessionOps.getSessionRepository());
prop.getWriteConverter(sessionOps.getSessionRepository());
if (converter.isPresent()) { if (converter.isPresent()) {
Map convertedMap = (Map) converter.get().apply(map); Map convertedMap = (Map) converter.get().apply(map);
assignments.put(QueryBuilder.putAll(p.getColumnName(), convertedMap), facet); assignments.put(QueryBuilder.putAll(p.getColumnName(), convertedMap), facet);
@ -793,39 +780,16 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
} }
} }
@Override
protected boolean isIdempotentOperation() {
return assignments
.values()
.stream()
.allMatch(
facet -> {
if (facet != null) {
Set<HelenusProperty> props = facet.getProperties();
if (props != null && props.size() > 0) {
return props.stream().allMatch(prop -> prop.isIdempotent());
} else {
return true;
}
} else {
// In this case our UPDATE statement made mutations via the List, Set, Map methods only.
return false;
}
})
|| super.isIdempotentOperation();
}
@Override @Override
public E sync() throws TimeoutException { public E sync() throws TimeoutException {
E result = super.sync(); E result = super.sync();
if (result != null && entity.isCacheable()) { if (entity.isCacheable()) {
if (draft != null) { if (draft != null) {
sessionOps.updateCache(draft, bindFacetValues());
adjustTtlAndWriteTime(draft); adjustTtlAndWriteTime(draft);
adjustTtlAndWriteTime((MapExportable) result);
sessionOps.updateCache(result, bindFacetValues());
} else if (pojo != null) { } else if (pojo != null) {
adjustTtlAndWriteTime((MapExportable) pojo);
sessionOps.updateCache(pojo, bindFacetValues()); sessionOps.updateCache(pojo, bindFacetValues());
adjustTtlAndWriteTime((MapExportable)pojo);
} else { } else {
sessionOps.cacheEvict(bindFacetValues()); sessionOps.cacheEvict(bindFacetValues());
} }
@ -839,19 +803,17 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
return sync(); return sync();
} }
E result = super.sync(uow); E result = super.sync(uow);
if (result != null) {
if (draft != null) { if (draft != null) {
adjustTtlAndWriteTime(draft); adjustTtlAndWriteTime(draft);
}
if (entity != null && MapExportable.class.isAssignableFrom(entity.getMappingInterface())) { if (entity != null && MapExportable.class.isAssignableFrom(entity.getMappingInterface())) {
adjustTtlAndWriteTime((MapExportable) result); adjustTtlAndWriteTime((MapExportable) result);
}
cacheUpdate(uow, result, bindFacetValues()); cacheUpdate(uow, result, bindFacetValues());
} else if (pojo != null) { } else if (pojo != null) {
adjustTtlAndWriteTime((MapExportable) pojo);
cacheUpdate(uow, (E) pojo, bindFacetValues()); cacheUpdate(uow, (E) pojo, bindFacetValues());
adjustTtlAndWriteTime((MapExportable)pojo);
return (E) pojo; return (E) pojo;
} }
}
return result; return result;
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,6 +22,4 @@ public interface Drafted<T> extends MapExportable {
Set<String> mutated(); Set<String> mutated();
T build(); T build();
Set<String> read();
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,53 +20,10 @@ import net.helenus.core.Getter;
public interface Entity { public interface Entity {
String WRITTEN_AT_METHOD = "writtenAt"; String WRITTEN_AT_METHOD = "writtenAt";
String TTL_OF_METHOD = "ttlOf"; String TTL_OF_METHOD = "ttlOf";
String TOKEN_OF_METHOD = "tokenOf";
/** default Long writtenAt(Getter getter) { return 0L; }
* The write time for the property in question referenced by the getter. default Long writtenAt(String prop) { return 0L; };
*
* @param getter the property getter default Integer ttlOf(Getter getter) { return 0; };
* @return the timestamp associated with the property identified by the getter default Integer ttlOf(String prop) {return 0; };
*/
default Long writtenAt(Getter getter) {
return 0L;
}
/**
* The write time for the property in question referenced by the property name.
*
* @param prop the name of a property in this entity
* @return the timestamp associated with the property identified by the property name if it exists
*/
default Long writtenAt(String prop) {
return 0L;
};
/**
* The time-to-live for the property in question referenced by the getter.
*
* @param getter the property getter
* @return the time-to-live in seconds associated with the property identified by the getter
*/
default Integer ttlOf(Getter getter) {
return 0;
};
/**
* The time-to-live for the property in question referenced by the property name.
*
* @param prop the name of a property in this entity
* @return the time-to-live in seconds associated with the property identified by the property name if it exists
*/
default Integer ttlOf(String prop) {
return 0;
};
/**
* The token (partition identifier) for this entity which can change over time if
* the cluster grows or shrinks but should be stable otherwise.
*
* @return the token for the entity
*/
default Long tokenOf() { return 0L; }
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -64,11 +63,6 @@ public final class HelenusNamedProperty implements HelenusProperty {
return false; return false;
} }
@Override
public boolean isIdempotent() {
return false;
}
@Override @Override
public Class<?> getJavaType() { public Class<?> getJavaType() {
throw new HelenusMappingException("will never called"); throw new HelenusMappingException("will never called");

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,25 +16,12 @@
package net.helenus.core.reflect; package net.helenus.core.reflect;
import java.util.Map; import java.util.Map;
import java.util.Set;
import net.helenus.core.Getter;
public interface MapExportable { public interface MapExportable {
String TO_MAP_METHOD = "toMap"; String TO_MAP_METHOD = "toMap";
String TO_READ_SET_METHOD = "toReadSet";
String PUT_METHOD = "put"; String PUT_METHOD = "put";
Map<String, Object> toMap(); Map<String, Object> toMap();
default Map<String, Object> toMap(boolean mutable) { return null; }
default Map<String, Object> toMap(boolean mutable) {
return null;
}
default Set<String> toReadSet() {
return null;
}
default void put(String key, Object value) { } default void put(String key, Object value) { }
default <T> void put(Getter<T> getter, T value) {}
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,9 +15,14 @@
*/ */
package net.helenus.core.reflect; package net.helenus.core.reflect;
import com.google.common.collect.ImmutableList; import net.helenus.core.Getter;
import com.google.common.collect.ImmutableMap; import net.helenus.core.Helenus;
import com.google.common.collect.ImmutableSet; import net.helenus.core.cache.CacheUtil;
import net.helenus.mapping.MappingUtil;
import net.helenus.mapping.annotation.Transient;
import net.helenus.mapping.value.ValueProviderMap;
import net.helenus.support.HelenusException;
import java.io.InvalidObjectException; import java.io.InvalidObjectException;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.ObjectStreamException; import java.io.ObjectStreamException;
@ -28,20 +32,15 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.util.*; import java.util.Collections;
import net.helenus.core.Getter; import java.util.HashMap;
import net.helenus.core.Helenus; import java.util.Map;
import net.helenus.core.cache.CacheUtil; import java.util.Set;
import net.helenus.mapping.MappingUtil;
import net.helenus.mapping.annotation.Transient;
import net.helenus.mapping.value.ValueProviderMap;
import net.helenus.support.HelenusException;
public class MapperInvocationHandler<E> implements InvocationHandler, Serializable { public class MapperInvocationHandler<E> implements InvocationHandler, Serializable {
private static final long serialVersionUID = -7044209982830584984L; private static final long serialVersionUID = -7044209982830584984L;
private Map<String, Object> src; private Map<String, Object> src;
private final Set<String> read = new HashSet<String>();
private final Class<E> iface; private final Class<E> iface;
public MapperInvocationHandler(Class<E> iface, Map<String, Object> src) { public MapperInvocationHandler(Class<E> iface, Map<String, Object> src) {
@ -108,21 +107,12 @@ public class MapperInvocationHandler<E> implements InvocationHandler, Serializab
} }
if (MapExportable.PUT_METHOD.equals(methodName) && method.getParameterCount() == 2) { if (MapExportable.PUT_METHOD.equals(methodName) && method.getParameterCount() == 2) {
final String key; final String key = (String)args[0];
if (args[0] instanceof String) {
key = (String) args[0];
} else if (args[0] instanceof Getter) {
key = MappingUtil.resolveMappingProperty((Getter) args[0]).getProperty().getPropertyName();
} else {
key = null;
}
if (key != null) {
final Object value = (Object)args[1]; final Object value = (Object)args[1];
if (src instanceof ValueProviderMap) { if (src instanceof ValueProviderMap) {
this.src = fromValueProviderMap(src); this.src = fromValueProviderMap(src);
} }
src.put(key, value); src.put(key, value);
}
return null; return null;
} }
@ -132,12 +122,7 @@ public class MapperInvocationHandler<E> implements InvocationHandler, Serializab
key = CacheUtil.writeTimeKey((String)args[0]); key = CacheUtil.writeTimeKey((String)args[0]);
} else if (args[0] instanceof Getter) { } else if (args[0] instanceof Getter) {
Getter getter = (Getter)args[0]; Getter getter = (Getter)args[0];
key = key = CacheUtil.writeTimeKey(MappingUtil.resolveMappingProperty(getter).getProperty().getColumnName().toCql(false));
CacheUtil.writeTimeKey(
MappingUtil.resolveMappingProperty(getter)
.getProperty()
.getColumnName()
.toCql(false));
} else { } else {
return 0L; return 0L;
} }
@ -148,26 +133,13 @@ public class MapperInvocationHandler<E> implements InvocationHandler, Serializab
return 0L; return 0L;
} }
if (Entity.TOKEN_OF_METHOD.equals(methodName) && method.getParameterCount() == 0) {
Long v = (Long) src.get("");
if (v != null) {
return v;
}
return 0L;
}
if (Entity.TTL_OF_METHOD.equals(methodName) && method.getParameterCount() == 1) { if (Entity.TTL_OF_METHOD.equals(methodName) && method.getParameterCount() == 1) {
final String key; final String key;
if (args[0] instanceof String) { if (args[0] instanceof String) {
key = CacheUtil.ttlKey((String)args[0]); key = CacheUtil.ttlKey((String)args[0]);
} else if (args[0] instanceof Getter) { } else if (args[0] instanceof Getter) {
Getter getter = (Getter)args[0]; Getter getter = (Getter)args[0];
key = key = CacheUtil.ttlKey(MappingUtil.resolveMappingProperty(getter).getProperty().getColumnName().toCql(false));
CacheUtil.ttlKey(
MappingUtil.resolveMappingProperty(getter)
.getProperty()
.getColumnName()
.toCql(false));
} else { } else {
return 0; return 0;
} }
@ -178,19 +150,6 @@ public class MapperInvocationHandler<E> implements InvocationHandler, Serializab
return 0; return 0;
} }
if (MapExportable.TO_MAP_METHOD.equals(methodName)) {
if (method.getParameterCount() == 1 && args[0] instanceof Boolean) {
if ((boolean) args[0] == true) {
return fromValueProviderMap(src, true);
}
}
return Collections.unmodifiableMap(src);
}
if (MapExportable.TO_READ_SET_METHOD.equals(methodName)) {
return read;
}
if (method.getParameterCount() != 0 || method.getReturnType() == void.class) { if (method.getParameterCount() != 0 || method.getReturnType() == void.class) {
throw new HelenusException("invalid getter method " + method); throw new HelenusException("invalid getter method " + method);
} }
@ -215,8 +174,14 @@ public class MapperInvocationHandler<E> implements InvocationHandler, Serializab
return Helenus.dsl(iface); return Helenus.dsl(iface);
} }
if (MapExportable.TO_MAP_METHOD.equals(methodName)) {
if (method.getParameterCount() == 1 && args[0] instanceof Boolean) {
if ((boolean)args[0] == true) { return src; }
}
return Collections.unmodifiableMap(src);
}
final Object value = src.get(methodName); final Object value = src.get(methodName);
read.add(methodName);
if (value == null) { if (value == null) {
@ -243,33 +208,13 @@ public class MapperInvocationHandler<E> implements InvocationHandler, Serializab
} }
static Map<String, Object> fromValueProviderMap(Map v) { static Map<String, Object> fromValueProviderMap(Map v) {
return fromValueProviderMap(v, false);
}
static Map<String, Object> fromValueProviderMap(Map v, boolean mutable) {
if (v instanceof ValueProviderMap) {
Map<String, Object> m = new HashMap<String, Object>(v.size()); Map<String, Object> m = new HashMap<String, Object>(v.size());
Set<String> keys = v.keySet(); Set<String> keys = v.keySet();
for (String key : keys) { for (String key : keys) {
Object value = v.get(key); m.put(key, v.get(key));
if (value != null && mutable) {
if (ImmutableList.class.isAssignableFrom(value.getClass())) {
m.put(key, new ArrayList((List) value));
} else if (ImmutableMap.class.isAssignableFrom(value.getClass())) {
m.put(key, new HashMap((Map) value));
} else if (ImmutableSet.class.isAssignableFrom(value.getClass())) {
m.put(key, new HashSet((Set) value));
} else {
m.put(key, value);
}
} else {
m.put(key, value);
}
} }
return m; return m;
} }
return v;
}
static class SerializationProxy<E> implements Serializable { static class SerializationProxy<E> implements Serializable {

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -35,6 +34,4 @@ public interface HelenusEntity {
HelenusProperty getProperty(String name); HelenusProperty getProperty(String name);
List<Facet> getFacets(); List<Facet> getFacets();
boolean isDraftable();
} }

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,7 +1,6 @@
/* /*
* *
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
@ -40,7 +39,6 @@ public final class HelenusMappingEntity implements HelenusEntity {
private final HelenusEntityType type; private final HelenusEntityType type;
private final IdentityName name; private final IdentityName name;
private final boolean cacheable; private final boolean cacheable;
private final boolean draftable;
private final ImmutableMap<String, Method> methods; private final ImmutableMap<String, Method> methods;
private final ImmutableMap<String, HelenusProperty> props; private final ImmutableMap<String, HelenusProperty> props;
private final ImmutableList<HelenusProperty> orderedProps; private final ImmutableList<HelenusProperty> orderedProps;
@ -114,23 +112,12 @@ public final class HelenusMappingEntity implements HelenusEntity {
// Caching // Caching
cacheable = (null != iface.getDeclaredAnnotation(Cacheable.class)); cacheable = (null != iface.getDeclaredAnnotation(Cacheable.class));
// Draft
Class<?> draft;
try {
draft = Class.forName(iface.getName() + "$Draft");
} catch (Exception ignored) {
draft = null;
}
draftable = (draft != null);
// Materialized view
List<HelenusProperty> primaryKeyProperties = new ArrayList<>(); List<HelenusProperty> primaryKeyProperties = new ArrayList<>();
ImmutableList.Builder<Facet> facetsBuilder = ImmutableList.builder(); ImmutableList.Builder<Facet> facetsBuilder = ImmutableList.builder();
if (iface.getDeclaredAnnotation(MaterializedView.class) == null) { if (iface.getDeclaredAnnotation(MaterializedView.class) == null) {
facetsBuilder.add(new Facet("table", name.toCql()).setFixed()); facetsBuilder.add(new Facet("table", name.toCql()).setFixed());
} else { } else {
facetsBuilder.add( facetsBuilder.add(new Facet("table", Helenus.entity(iface.getInterfaces()[0]).getName().toCql())
new Facet("table", Helenus.entity(iface.getInterfaces()[0]).getName().toCql())
.setFixed()); .setFixed());
} }
for (HelenusProperty prop : orderedProps) { for (HelenusProperty prop : orderedProps) {
@ -144,9 +131,8 @@ public final class HelenusMappingEntity implements HelenusEntity {
facetsBuilder.add(new UnboundFacet(primaryKeyProperties)); facetsBuilder.add(new UnboundFacet(primaryKeyProperties));
primaryKeyProperties = null; primaryKeyProperties = null;
} }
for (ConstraintValidator<?, ?> constraint : for (ConstraintValidator<?, ?> constraint : MappingUtil.getValidators(prop.getGetterMethod())) {
MappingUtil.getValidators(prop.getGetterMethod())) { if (constraint.getClass().isAssignableFrom(DistinctValidator.class)) {
if (constraint instanceof DistinctValidator) {
DistinctValidator validator = (DistinctValidator) constraint; DistinctValidator validator = (DistinctValidator) constraint;
String[] values = validator.constraintAnnotation.value(); String[] values = validator.constraintAnnotation.value();
UnboundFacet facet; UnboundFacet facet;
@ -224,11 +210,6 @@ public final class HelenusMappingEntity implements HelenusEntity {
return cacheable; return cacheable;
} }
@Override
public boolean isDraftable() {
return draftable;
}
@Override @Override
public Class<?> getMappingInterface() { public Class<?> getMappingInterface() {
return iface; return iface;

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -36,7 +35,6 @@ public final class HelenusMappingProperty implements HelenusProperty {
private final String propertyName; private final String propertyName;
private final Optional<IdentityName> indexName; private final Optional<IdentityName> indexName;
private final boolean caseSensitiveIndex; private final boolean caseSensitiveIndex;
private final boolean idempotent;
private final ColumnInformation columnInfo; private final ColumnInformation columnInfo;
@ -58,15 +56,6 @@ public final class HelenusMappingProperty implements HelenusProperty {
this.columnInfo = new ColumnInformation(getter); this.columnInfo = new ColumnInformation(getter);
switch (this.columnInfo.getColumnType()) {
case PARTITION_KEY:
case CLUSTERING_COLUMN:
this.idempotent = true;
break;
default:
this.idempotent = MappingUtil.idempotent(getter);
}
this.genericJavaType = getter.getGenericReturnType(); this.genericJavaType = getter.getGenericReturnType();
this.javaType = getter.getReturnType(); this.javaType = getter.getReturnType();
this.abstractJavaType = MappingJavaTypes.resolveJavaType(this.javaType); this.abstractJavaType = MappingJavaTypes.resolveJavaType(this.javaType);
@ -123,11 +112,6 @@ public final class HelenusMappingProperty implements HelenusProperty {
return caseSensitiveIndex; return caseSensitiveIndex;
} }
@Override
public boolean isIdempotent() {
return idempotent;
}
@Override @Override
public String getPropertyName() { public String getPropertyName() {
return propertyName; return propertyName;

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -38,8 +37,6 @@ public interface HelenusProperty {
boolean caseSensitiveIndex(); boolean caseSensitiveIndex();
boolean isIdempotent();
Class<?> getJavaType(); Class<?> getJavaType();
AbstractDataType getDataType(); AbstractDataType getDataType();

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2015 The Casser Authors * Copyright (C) 2015 The Helenus Authors
* Copyright (C) 2015-2018 The Helenus Authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

Some files were not shown because too many files have changed in this diff Show more