Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added (temporary) profiling.

Added Java helper classes.
  • Loading branch information...
commit 60bc99c4111c61f4231098a0b312afe35865d588 1 parent 538c768
@bflorian authored
Showing with 880 additions and 69 deletions.
  1. +3 −0  grails-app/conf/BuildConfig.groovy
  2. +0 −10 src/groovy/com/reachlocal/grails/plugins/cassandra/mapping/BaseUtils.groovy
  3. +10 −9 src/groovy/com/reachlocal/grails/plugins/cassandra/mapping/ClassMethods.groovy
  4. +6 −5 src/groovy/com/reachlocal/grails/plugins/cassandra/mapping/CounterUtils.groovy
  5. +3 −2 src/groovy/com/reachlocal/grails/plugins/cassandra/mapping/DataMapping.groovy
  6. +128 −10 src/groovy/com/reachlocal/grails/plugins/cassandra/mapping/InstanceMethods.groovy
  7. +2 −1  src/groovy/com/reachlocal/grails/plugins/cassandra/mapping/KeyUtils.groovy
  8. +19 −18 src/groovy/com/reachlocal/grails/plugins/cassandra/mapping/MappingUtils.groovy
  9. +2 −1  src/groovy/com/reachlocal/grails/plugins/cassandra/mapping/TraverserNode.groovy
  10. +7 −0 src/groovy/com/reachlocal/grails/plugins/cassandra/test/orm/Visit.groovy
  11. +6 −1 src/groovy/com/reachlocal/grails/plugins/cassandra/uuid/UuidDynamicMethods.groovy
  12. +351 −0 src/java/com/reachlocal/grails/plugins/cassandra/utils/KeyHelper.java
  13. +228 −0 src/java/com/reachlocal/grails/plugins/cassandra/utils/OrmHelper.java
  14. +8 −5 test/unit/com/reachlocal/grails/plugins/cassandra/test/InsertPerformanceTests.groovy
  15. +0 −7 test/unit/com/reachlocal/grails/plugins/cassandra/test/MappingUtilsTests.groovy
  16. +107 −0 test/unit/com/reachlocal/grails/plugins/cassandra/test/OrmHelperTests.groovy
View
3  grails-app/conf/BuildConfig.groovy
@@ -52,5 +52,8 @@ grails.project.dependency.resolution = {
build (":svn:1.0.2") {
export = false
}
+ test (":spock:0.6") {
+ export = false
+ }
}
}
View
10 src/groovy/com/reachlocal/grails/plugins/cassandra/mapping/BaseUtils.groovy
@@ -20,16 +20,6 @@ class BaseUtils
static protected final CLUSTER_PROP = "_cassandra_cluster_"
static protected final GLOBAL_TRANSIENTS = ["class","id","cassandra","indexColumnFamily","columnFamily","counterColumnFamily","metaClass","keySpace","cassandraCluster",DIRTY_SUFFIX,CLUSTER_PROP] as Set
- static String stringValue(String s)
- {
- '"' + s.replaceAll('"','\\"') + '"'
- }
-
- static String stringValue(s)
- {
- String.valueOf(s)
- }
-
static String methodForPropertyName(prefix, propertyName)
{
return "${prefix}${propertyName[0].toUpperCase()}${propertyName.size() > 1 ? propertyName[1..-1] : ''}"
View
19 src/groovy/com/reachlocal/grails/plugins/cassandra/mapping/ClassMethods.groovy
@@ -17,6 +17,7 @@
package com.reachlocal.grails.plugins.cassandra.mapping
import com.reachlocal.grails.plugins.cassandra.utils.DateHelper
+import com.reachlocal.grails.plugins.cassandra.utils.OrmHelper
/**
* @author: Bob Florian
@@ -63,7 +64,7 @@ class ClassMethods extends MappingUtils
// initialize counter types
clazz.cassandraMapping.counters?.eachWithIndex {ctr, index ->
if (ctr.groupBy) {
- ctr.groupBy = collection(ctr.groupBy)
+ ctr.groupBy = OrmHelper.collection(ctr.groupBy)
def prop = clazz.metaClass.getMetaProperty(ctr.groupBy[0])
if (prop) {
ctr.isDateIndex = prop.type.isAssignableFrom(Date)
@@ -145,7 +146,7 @@ class ClassMethods extends MappingUtils
def rowKeys = ids.collect{primaryRowKey(it)}
def cluster = opts.cluster ?: cassandraCluster
cassandra.withKeyspace(keySpace, cluster) {ks ->
- def options = addOptionDefaults(opts, MAX_ROWS)
+ def options = OrmHelper.addOptionDefaults(opts, MAX_ROWS)
def names = columnNames(options)
if (names) {
def rows = cassandra.persistence.getRowsColumnSlice(ks, clazz.columnFamily, rowKeys, names, opts.consistencyLevel)
@@ -163,7 +164,7 @@ class ClassMethods extends MappingUtils
clazz.metaClass.'static'.findOrCreate = {id, opts=[:] ->
def result = get(id, opts)
if (!result) {
- def names = collection(cassandraMapping.primaryKey ?: cassandraMapping.unindexedPrimaryKey)
+ def names = OrmHelper.collection(cassandraMapping.primaryKey ?: cassandraMapping.unindexedPrimaryKey)
if (names.size() > 1) {
throw new CassandraMappingException("findOrCreate() and findOrSave() methods not defined for classes with compound keys")
}
@@ -195,7 +196,7 @@ class ClassMethods extends MappingUtils
// list(start: id1, finish: id1, reversed: true, max: max_rows)
clazz.metaClass.'static'.list = {opts=[:] ->
- def options = addOptionDefaults(opts, MAX_ROWS)
+ def options = OrmHelper.addOptionDefaults(opts, MAX_ROWS)
def cluster = opts.cluster ?: cassandraCluster
def start = options.startAfter ?: options.start
def max = options.startAfter ? options.max + 1 : options.max
@@ -212,7 +213,7 @@ class ClassMethods extends MappingUtils
)
def keys = columns.collect{cassandra.persistence.name(it)}
- checkForDefaultRowsInsufficient(opts.max, keys.size())
+ OrmHelper.checkForDefaultRowsInsufficient(opts.max, keys.size())
def rows = cassandra.persistence.getRows(ks, columnFamily, keys, opts.consistencyLevel)
def result = cassandra.mapping.makeResult(keys, rows, options, LinkedList)
@@ -356,7 +357,7 @@ class ClassMethods extends MappingUtils
count = true
}
if (str) {
- def propertyList = propertyListFromMethodName(str)
+ def propertyList = OrmHelper.propertyListFromMethodName(str)
def params = [:]
propertyList.eachWithIndex {it, i ->
params[it] = args[i]
@@ -402,11 +403,11 @@ class ClassMethods extends MappingUtils
else {
def pos = str.indexOf("GroupBy")
if (pos > 0) {
- groupByPropList = propertyListFromMethodName(str[pos+7..-1])
+ groupByPropList = OrmHelper.propertyListFromMethodName(str[pos+7..-1])
str = str[0..pos-1]
}
}
- wherePropList = propertyListFromMethodName(str)
+ wherePropList = OrmHelper.propertyListFromMethodName(str)
}
else if (name.startsWith("getCountsGroupBy")) {
str = name - "getCountsGroupBy"
@@ -414,7 +415,7 @@ class ClassMethods extends MappingUtils
if (total) {
str = str - "Total"
}
- groupByPropList = propertyListFromMethodName(str)
+ groupByPropList = OrmHelper.propertyListFromMethodName(str)
}
else if (name == "getCountsTotal") {
total = true
View
11 src/groovy/com/reachlocal/grails/plugins/cassandra/mapping/CounterUtils.groovy
@@ -6,6 +6,7 @@ import java.text.SimpleDateFormat
import java.text.DateFormat
import com.reachlocal.grails.plugins.cassandra.utils.DateHelper
import com.reachlocal.grails.plugins.cassandra.utils.CounterHelper
+import com.reachlocal.grails.plugins.cassandra.utils.OrmHelper
/**
* @author: Bob Florian
@@ -100,7 +101,7 @@ class CounterUtils extends KeyUtils
def keys = groupKeys.collect{
counterColumnKey(bean.getProperty(it), dateFormat)
}
- expandNestedArray(keys).each {
+ OrmHelper.expandNestedArray(keys).each {
result << makeComposite(it)
}
return result
@@ -114,7 +115,7 @@ class CounterUtils extends KeyUtils
{
def cf = clazz.counterColumnFamily
def persistence = clazz.cassandra.persistence
- def groupBy = collection(counterDef.groupBy)
+ def groupBy = OrmHelper.collection(counterDef.groupBy)
def matchIndexes = columnFilter ? CounterHelper.filterMatchIndexes(columnFilter, groupBy) : null
def cluster = clusterName ?: clazz.cassandraCluster
@@ -169,7 +170,7 @@ class CounterUtils extends KeyUtils
{
def cf = clazz.counterColumnFamily
def persistence = clazz.cassandra.persistence
- def groupBy = collection(counterDef.groupBy)
+ def groupBy = OrmHelper.collection(counterDef.groupBy)
def matchIndexes = columnFilter ? CounterHelper.filterMatchIndexes(columnFilter, groupBy) : null
def cluster = clusterName ?: clazz.cassandraCluster
@@ -218,7 +219,7 @@ class CounterUtils extends KeyUtils
}
}
if (sortResult) {
- sort(result);
+ OrmHelper.sort(result);
}
else {
return result;
@@ -230,7 +231,7 @@ class CounterUtils extends KeyUtils
{
def cf = clazz.counterColumnFamily
def persistence = clazz.cassandra.persistence
- def groupBy = collection(counterDef.groupBy)
+ def groupBy = OrmHelper.collection(counterDef.groupBy)
def matchIndexes = columnFilter ? CounterHelper.filterMatchIndexes(columnFilter, groupBy) : null
def cluster = clusterName ?: clazz.cassandraCluster
View
5 src/groovy/com/reachlocal/grails/plugins/cassandra/mapping/DataMapping.groovy
@@ -17,6 +17,7 @@
package com.reachlocal.grails.plugins.cassandra.mapping
import com.reachlocal.grails.plugins.cassandra.utils.DataMapper
+import com.reachlocal.grails.plugins.cassandra.utils.OrmHelper
/**
* @author: Bob Florian
@@ -31,8 +32,8 @@ class DataMapping extends MappingUtils
return DataMapper.dataProperties((Map<String, Object>)data);
}
else {
- List<String> transients = (List<String>)MappingUtils.safeGetProperty(data, 'transients', List, [])
- Map<String, Class> hasMany = (Map<String, Class>)MappingUtils.safeGetProperty(data, 'hasMany', Map, [:])
+ List<String> transients = (List<String>)OrmHelper.safeGetProperty(data, 'transients', List, [])
+ Map<String, Class> hasMany = (Map<String, Class>)OrmHelper.safeGetProperty(data, 'hasMany', Map, [:])
String expandoMapName = data.getClass().cassandraMapping.expandoMap
return DataMapper.dataProperties(data, transients, hasMany, expandoMapName);
}
View
138 src/groovy/com/reachlocal/grails/plugins/cassandra/mapping/InstanceMethods.groovy
@@ -19,12 +19,34 @@ package com.reachlocal.grails.plugins.cassandra.mapping
import org.codehaus.groovy.grails.commons.GrailsClassUtils
import org.apache.commons.beanutils.PropertyUtils
import com.reachlocal.grails.plugins.cassandra.utils.DataMapper
+import com.reachlocal.grails.plugins.cassandra.utils.NestedHashMap
+import com.reachlocal.grails.plugins.cassandra.utils.OrmHelper
/**
* @author: Bob Florian
*/
class InstanceMethods extends MappingUtils
{
+ static profiler = new NestedHashMap()
+
+ static void dumpProfiler()
+ {
+ def total = 0L
+ println "PROFILER, ${profiler.Iterations} ITERATIONS (msec):"
+ profiler.each {name, value ->
+ if (name != "Iterations") {
+ println "$name: \t$value"
+ total += value
+ }
+ }
+ println "TOTAL: \t$total \t${total/profiler.Iterations} \t${profiler.Iterations/(total/1000.0)}\trec/sec"
+ }
+
+ static void clearProfiler()
+ {
+ profiler = new NestedHashMap()
+ }
+
static void addDynamicOrmMethods(clazz, ctx)
{
// cassandra
@@ -59,7 +81,7 @@ class InstanceMethods extends MappingUtils
// cassandra row key
clazz.metaClass.ident = {
def thisObj = delegate
- def names = collection(cassandraMapping.primaryKey ?: cassandraMapping.unindexedPrimaryKey)
+ def names = OrmHelper.collection(cassandraMapping.primaryKey ?: cassandraMapping.unindexedPrimaryKey)
def values = names.collect {
def value = thisObj.getProperty(it)
primaryRowKey(value)
@@ -76,6 +98,10 @@ class InstanceMethods extends MappingUtils
// save()
clazz.metaClass.save = {args ->
+ profiler.increment("Iterations", 1)
+
+ def t0 = System.currentTimeMillis()
+
def thisObj = delegate
def ttl = args?.ttl ?: cassandraMapping.timeToLive
if (args?.cluster) {
@@ -83,30 +109,69 @@ class InstanceMethods extends MappingUtils
}
def cluster = thisObj.cassandraCluster
def persistence = cassandra.persistence
+
+ // TIMER
+ def t1 = System.currentTimeMillis()
+ profiler.increment("Save - Header", t1-t0)
+ t0 = t1
+
cassandra.withKeyspace(thisObj.keySpace, cluster) {ks ->
def m = persistence.prepareMutationBatch(ks, args?.consistencyLevel)
+ // TIMER
+ t1 = System.currentTimeMillis()
+ profiler.increment("Save - Prepare Mutation", t1-t0)
+ t0 = t1
+
// get the primary row key
def id
try {
id = thisObj.id
+
+ t1 = System.currentTimeMillis()
+ profiler.increment("Save - Primary Key", t1-t0)
+ t0 = t1
}
catch (CassandraMappingNullIndexException e) {
// if primary key is a UUID and its null, set it
- def keyNames = collection(cassandraMapping.primaryKey ?: cassandraMapping.unindexedPrimaryKey)
+ def keyNames = OrmHelper.collection(cassandraMapping.primaryKey ?: cassandraMapping.unindexedPrimaryKey)
def keyClass = keyNames.size() == 1 ? clazz.getDeclaredField(keyNames[0]).type : null
+
+ t1 = System.currentTimeMillis()
+ profiler.increment("Save - Primary Key 1", t1-t0)
+ t0 = t1
+
if (keyClass == UUID) {
- thisObj.setProperty(keyNames[0], UUID.timeUUID())
+ def uuid = UUID.timeUUID()
+
+ t1 = System.currentTimeMillis()
+ profiler.increment("Save - Primary Key UUID", t1-t0)
+ t0 = t1
+
+ thisObj.setProperty(keyNames[0], uuid)
id = thisObj.id
}
else {
throw e
}
+ t1 = System.currentTimeMillis()
+ profiler.increment("Save - Primary Key 2", t1-t0)
+ t0 = t1
}
+ // TIMER
+ t1 = System.currentTimeMillis()
+ profiler.increment("Save - Primary Key", t1-t0)
+ t0 = t1
+
// see if it exists
def oldObj = args?.nocheck ? null : clazz.get(id, [cluster:cluster])
+ // TIMER
+ t1 = System.currentTimeMillis()
+ profiler.increment("Save - Old Object", t1-t0)
+ t0 = t1
+
// one-to-one relationships
def keyDeleted = false
DataMapper.dirtyPropertyNames(thisObj).each {name ->
@@ -146,12 +211,22 @@ class InstanceMethods extends MappingUtils
}
}
+ // TIMER
+ t1 = System.currentTimeMillis()
+ profiler.increment("Save - 1:1 Relationships", t1-t0)
+ t0 = t1
+
// commit deletion of relationship keys
if (keyDeleted) {
persistence.execute(m)
m = persistence.prepareMutationBatch(ks, args?.consistencyLevel)
}
+ // TIMER
+ t1 = System.currentTimeMillis()
+ profiler.increment("Save - Delete Old Keys", t1-t0)
+ t0 = t1
+
// manage index rows
def indexRows = [:]
def oldIndexRows = [:]
@@ -162,6 +237,12 @@ class InstanceMethods extends MappingUtils
indexRows[primaryKeyIndexRowKey()] = [(thisObj.id):'']
}
+ // TIMER
+ t1 = System.currentTimeMillis()
+ profiler.increment("Save - Primary Key Index", t1-t0)
+ t0 = t1
+
+
// explicit indexes
cassandraMapping.explicitIndexes?.each {propName ->
if (oldObj) {
@@ -184,16 +265,38 @@ class InstanceMethods extends MappingUtils
}
}
+ // TIMER
+ t1 = System.currentTimeMillis()
+ profiler.increment("Save - Explicit Index Generation", t1-t0)
+ t0 = t1
+
+
// delete old index row keys
if (oldIndexRows) {
persistence.execute(m)
m = persistence.prepareMutationBatch(ks, args?.consistencyLevel)
}
+ // TIMER
+ t1 = System.currentTimeMillis()
+ profiler.increment("Save - Explicit Delete Old", t1-t0)
+ t0 = t1
+
// insert this object
def dataProperties = cassandra.mapping.dataProperties(thisObj)
+
+ t1 = System.currentTimeMillis()
+ profiler.increment("Save - Convert Properties", t1-t0)
+ t0 = t1
+
persistence.putColumns(m, thisObj.columnFamily, id, dataProperties, ttl)
+ // TIMER
+ t1 = System.currentTimeMillis()
+ profiler.increment("Save - Save Object", t1-t0)
+ t0 = t1
+
+
// insert new index row keys
if (indexRows) {
indexRows.each {rowKey, cols ->
@@ -201,12 +304,27 @@ class InstanceMethods extends MappingUtils
}
}
+ // TIMER
+ t1 = System.currentTimeMillis()
+ profiler.increment("Save - Explicit Index Setup", t1-t0)
+ t0 = t1
+
// counters
cassandraMapping.counters?.each {ctr ->
updateCounterColumns(clazz, ctr, m, oldObj, thisObj)
}
+ // TIMER
+ t1 = System.currentTimeMillis()
+ profiler.increment("Save - Counter Setup", t1-t0)
+ t0 = t1
+
persistence.execute(m)
+
+ // TIMER
+ t1 = System.currentTimeMillis()
+ profiler.increment("Save - Cassandra Save", t1-t0)
+ t0 = t1
}
thisObj
}
@@ -247,7 +365,7 @@ class InstanceMethods extends MappingUtils
// remove old explicit indexes
def propertyNames = properties.keySet()
cassandraMapping.explicitIndexes?.each {propName ->
- def names = collection(propName)
+ def names = OrmHelper.collection(propName)
if (!Collections.disjoint(propertyNames, names)) {
def oldIndexRowKeys = objectIndexRowKeys(propName, thisObj)
oldIndexRowKeys.each {oldIndexRowKey ->
@@ -269,7 +387,7 @@ class InstanceMethods extends MappingUtils
// add new explicit indexes
cassandraMapping.explicitIndexes?.each {propName ->
- def names = collection(propName)
+ def names = OrmHelper.collection(propName)
if (!Collections.disjoint(propertyNames, names)) {
def indexRowKeys = objectIndexRowKeys(propName, thisObj)
indexRowKeys.each {indexRowKey ->
@@ -350,7 +468,7 @@ class InstanceMethods extends MappingUtils
def pName = propClass.belongsToPropName(clazz)
if (propClass.belongsToClass(clazz)) {
items.each {
- safeSetProperty(it, pName, null)
+ OrmHelper.safeSetProperty(it, pName, null)
}
cascadedDeletes.addAll(items)
}
@@ -446,8 +564,8 @@ class InstanceMethods extends MappingUtils
def getterName = GrailsClassUtils.getGetterName(propName)
def setterName = GrailsClassUtils.getSetterName(propName)
def counterFunctionName = "${propName}Count".toString()
- def addToName = methodForPropertyName("addTo", propName)
- def removeFromName = methodForPropertyName("removeFrom", propName)
+ def addToName = OrmHelper.methodForPropertyName("addTo", propName)
+ def removeFromName = OrmHelper.methodForPropertyName("removeFrom", propName)
// setter
clazz.metaClass."${setterName}" = {
@@ -504,7 +622,7 @@ class InstanceMethods extends MappingUtils
item.save()
// null this property so that it is lazy-evaluated the next time
- safeSetProperty(thisObj, propName, null)
+ OrmHelper.safeSetProperty(thisObj, propName, null)
// add the indexes
cassandra.withKeyspace(delegate.keySpace, delegate.cassandraCluster) {ks ->
@@ -522,7 +640,7 @@ class InstanceMethods extends MappingUtils
clazz.metaClass."${removeFromName}" = { item, consistencyLevel=null ->
def thisObj = delegate
def persistence = cassandra.persistence
- safeSetProperty(thisObj, propName, null)
+ OrmHelper.safeSetProperty(thisObj, propName, null)
cassandra.withKeyspace(delegate.keySpace, delegate.cassandraCluster) {ks ->
def m = persistence.prepareMutationBatch(ks, consistencyLevel)
View
3  src/groovy/com/reachlocal/grails/plugins/cassandra/mapping/KeyUtils.groovy
@@ -4,6 +4,7 @@ import java.text.DateFormat
import java.nio.ByteBuffer
import java.text.SimpleDateFormat
import java.text.DecimalFormat
+import com.reachlocal.grails.plugins.cassandra.utils.OrmHelper
/**
* @author: Bob Florian
@@ -126,7 +127,7 @@ class KeyUtils extends BaseUtils
try {
def valueList = propNames.collect{bean.getProperty(it)}
def result = []
- def v2 = expandNestedArray(valueList)
+ def v2 = OrmHelper.expandNestedArray(valueList)
v2.each {values ->
def pairs = []
propNames.eachWithIndex {name, index ->
View
37 src/groovy/com/reachlocal/grails/plugins/cassandra/mapping/MappingUtils.groovy
@@ -17,6 +17,7 @@
package com.reachlocal.grails.plugins.cassandra.mapping
import com.reachlocal.grails.plugins.cassandra.utils.DateHelper
+import com.reachlocal.grails.plugins.cassandra.utils.OrmHelper
/**
* @author: Bob Florian
@@ -38,12 +39,12 @@ class MappingUtils extends CounterUtils
// TODO - combine with rowFilterList
def multiWhereKeys = []
whereFilter.each {key, values ->
- if (collection(values).size() > 1) {
+ if (OrmHelper.collection(values).size() > 1) {
multiWhereKeys << key
}
}
- def counterDef = findCounter(counterDefs, whereFilter, collection(byPropNames), multiWhereKeys)
+ def counterDef = findCounter(counterDefs, whereFilter, OrmHelper.collection(byPropNames), multiWhereKeys)
if (counterDef == null) {
throw new CassandraMappingException("Counter definition not found, where: ${whereFilter}, groupBy: ${byPropNames}")
}
@@ -52,7 +53,7 @@ class MappingUtils extends CounterUtils
def columnFilter = counterColumnFilter(whereFilter, counterDef)
def value
- def groupByPropNames = byPropNames ? collection(byPropNames) : []
+ def groupByPropNames = byPropNames ? OrmHelper.collection(byPropNames) : []
if (groupByPropNames) {
def i = 0
def indexes = []
@@ -131,7 +132,7 @@ class MappingUtils extends CounterUtils
byPropNames, start, finish, consistencyLevel, clusterName)
{
def cluster = clusterName ?: clazz.cassandraCluster
- def counterDef = findCounter(counterDefs, whereFilter, collection(byPropNames))
+ def counterDef = findCounter(counterDefs, whereFilter, OrmHelper.collection(byPropNames))
def rowFilterList = expandFilters(counterRowFilter(whereFilter, counterDef))
def columnFilter = counterColumnFilter(whereFilter, counterDef)
def cols = getDateCounterColumnsForTotals (clazz, rowFilterList, [], columnFilter, counterDef, start, finish, consistencyLevel, cluster)
@@ -142,7 +143,7 @@ class MappingUtils extends CounterUtils
static updateCounterColumns(Class clazz, Map counterDef, m, oldObj, thisObj)
{
def whereKeys = counterDef.findBy
- def groupKeys = collection(counterDef.groupBy)
+ def groupKeys = OrmHelper.collection(counterDef.groupBy)
def counterColumnFamily = clazz.counterColumnFamily
def cassandra = clazz.cassandra
@@ -397,7 +398,7 @@ class MappingUtils extends CounterUtils
def filter1 = filterList[0]
for (counter in counterList) {
def findBy = counter.findBy ?: [] //TODO - right?
- def groupBy = collection(counter.groupBy)
+ def groupBy = OrmHelper.collection(counter.groupBy)
def params = findBy instanceof List ? findBy : [findBy]
if (params.size() == filter1.size()) {
def all = true
@@ -443,7 +444,7 @@ class MappingUtils extends CounterUtils
def result = [:]
whereFilter.each {name, values ->
if (!findByNames?.contains(name)) {
- result[name] = collection(values).collect{it.toString()}
+ result[name] = OrmHelper.collection(values).collect{it.toString()}
}
}
return result
@@ -457,7 +458,7 @@ class MappingUtils extends CounterUtils
for (counter in counterList) {
def counterFindBy = counter.findBy ?: [] //TODO - right?
def counterFilterPropNames = counterFindBy instanceof List ? counterFindBy : [counterFindBy]
- def counterGroupPropNames = collection(counter.groupBy)
+ def counterGroupPropNames = OrmHelper.collection(counter.groupBy)
def queryFilterPropsRemaining = new LinkedHashSet()
queryFilterPropsRemaining.addAll(queryFilterPropNames)
def found = true
@@ -544,7 +545,7 @@ class MappingUtils extends CounterUtils
static queryByExplicitIndex(clazz, filterList, index, opts)
{
- def options = addOptionDefaults(opts, MAX_ROWS)
+ def options = OrmHelper.addOptionDefaults(opts, MAX_ROWS)
def start = nullablePrimaryRowKey(options.startAfter ?: options.start)
def max = options.startAfter ? options.max + 1 : options.max
def indexCf = clazz.indexColumnFamily
@@ -567,7 +568,7 @@ class MappingUtils extends CounterUtils
columns << cols.collect{persistence.name(it)}
}
def keys = mergeKeys(columns, max, options.reversed)
- checkForDefaultRowsInsufficient(opts.max, keys.size())
+ OrmHelper.checkForDefaultRowsInsufficient(opts.max, keys.size())
def result
def names = columnNames(options)
@@ -586,7 +587,7 @@ class MappingUtils extends CounterUtils
static countByExplicitIndex(clazz, filterList, index, opts)
{
- def options = addOptionDefaults(opts, MAX_ROWS)
+ def options = OrmHelper.addOptionDefaults(opts, MAX_ROWS)
def start = nullablePrimaryRowKey(options.startAfter ?: options.start)
def indexCf = clazz.indexColumnFamily
def persistence = clazz.cassandra.persistence
@@ -611,7 +612,7 @@ class MappingUtils extends CounterUtils
static queryBySecondaryIndex(clazz, propertyMap, opts)
{
- def options = addOptionDefaults(opts, MAX_ROWS)
+ def options = OrmHelper.addOptionDefaults(opts, MAX_ROWS)
def cluster = opts.cluster ?: clazz.cassandraCluster
clazz.cassandra.withKeyspace(clazz.keySpace, cluster) {ks ->
def properties = [:]
@@ -619,7 +620,7 @@ class MappingUtils extends CounterUtils
properties[k] = primaryRowKey(v)
}
def rows = clazz.cassandra.persistence.getRowsWithEqualityIndex(ks, clazz.columnFamily, properties, options.max, opts.consistencyLevel)
- checkForDefaultRowsInsufficient(opts.max, rows.size())
+ OrmHelper.checkForDefaultRowsInsufficient(opts.max, rows.size())
return clazz.cassandra.mapping.makeResult(rows, options)
}
}
@@ -638,7 +639,7 @@ class MappingUtils extends CounterUtils
static queryByCql(clazz, opts) throws IllegalArgumentException
{
- def options = addOptionDefaults(opts, MAX_ROWS)
+ def options = OrmHelper.addOptionDefaults(opts, MAX_ROWS)
def cluster = opts.cluster ?: clazz.cassandraCluster
clazz.cassandra.withKeyspace(clazz.keySpace, cluster) {ks ->
if (options.columns) {
@@ -658,7 +659,7 @@ class MappingUtils extends CounterUtils
static countByCql(clazz, opts) throws IllegalArgumentException
{
- def options = addOptionDefaults(opts, MAX_ROWS)
+ def options = OrmHelper.addOptionDefaults(opts, MAX_ROWS)
def cluster = opts.cluster ?: clazz.cassandraCluster
clazz.cassandra.withKeyspace(clazz.keySpace, cluster) {ks ->
return clazz.cassandra.persistence.getRowsWithCqlWhereClause(ks, clazz.columnFamily, options.where, opts.consistencyLevel)
@@ -692,7 +693,7 @@ class MappingUtils extends CounterUtils
static getByMappedObject(thisObj, propName, itemClass, opts=[:], listClass=LinkedHashSet)
{
def result = []
- def options = addOptionDefaults(opts, MAX_ROWS, thisObj.getProperty(CLUSTER_PROP))
+ def options = OrmHelper.addOptionDefaults(opts, MAX_ROWS, thisObj.getProperty(CLUSTER_PROP))
def start = nullablePrimaryRowKey(options.startAfter ?: options.start)
def finish = nullablePrimaryRowKey(options.finish)
def max = options.startAfter ? options.max + 1 : options.max
@@ -729,7 +730,7 @@ class MappingUtils extends CounterUtils
static getKeysForMappedObject(thisClass, thisId, propName, itemClass, opts=[:])
{
def result = []
- def options = addOptionDefaults(opts, MAX_ROWS, thisClass.cassandraCluster)
+ def options = OrmHelper.addOptionDefaults(opts, MAX_ROWS, thisClass.cassandraCluster)
def start = nullablePrimaryRowKey(options.startAfter ?: options.start)
def finish = nullablePrimaryRowKey(options.finish)
def max = options.startAfter ? options.max + 1 : options.max
@@ -748,7 +749,7 @@ class MappingUtils extends CounterUtils
static countByMappedObject(thisObj, propName, itemClass, opts=[:])
{
def result = []
- def options = addOptionDefaults(opts, MAX_ROWS)
+ def options = OrmHelper.addOptionDefaults(opts, MAX_ROWS)
def persistence = thisObj.cassandra.persistence
def start = nullablePrimaryRowKey(options.startAfter ?: options.start)
def finish = nullablePrimaryRowKey(options.finish)
View
3  src/groovy/com/reachlocal/grails/plugins/cassandra/mapping/TraverserNode.groovy
@@ -1,6 +1,7 @@
package com.reachlocal.grails.plugins.cassandra.mapping
import org.apache.commons.beanutils.PropertyUtils
+import com.reachlocal.grails.plugins.cassandra.utils.OrmHelper
/**
* @author: Bob Florian
@@ -86,7 +87,7 @@ class TraverserNode
}
def result = []
- def options = BaseUtils.addOptionDefaults(opts, BaseUtils.MAX_ROWS)
+ def options = OrmHelper.addOptionDefaults(opts, BaseUtils.MAX_ROWS)
def cassandra = traverser.object.cassandra
def persistence = cassandra.persistence
def names = MappingUtils.columnNames(options)
View
7 src/groovy/com/reachlocal/grails/plugins/cassandra/test/orm/Visit.groovy
@@ -15,10 +15,17 @@ class Visit
String userAgent
Date occurTime
+ static transients = ["ageInDays"]
+
static cassandraMapping = [
unindexedPrimaryKey: 'uuid',
explicitIndexes: [
'siteName'
]
]
+
+ Integer getAgeInDays()
+ {
+ return new Date() - occurTime
+ }
}
View
7 src/groovy/com/reachlocal/grails/plugins/cassandra/uuid/UuidDynamicMethods.groovy
@@ -66,9 +66,14 @@ class UuidDynamicMethods
}
UUID.metaClass.getTime = {
- return (delegate.timestamp() - UuidHelper.NUM_100NS_INTERVALS_SINCE_UUID_EPOCH) / 10000 as Long
+ return time(delegate)
}
}
+ static Long time(UUID uuid)
+ {
+ return (uuid.timestamp() - UuidHelper.NUM_100NS_INTERVALS_SINCE_UUID_EPOCH) / 10000 as Long
+ }
+
static rand = new Random()
}
View
351 src/java/com/reachlocal/grails/plugins/cassandra/utils/KeyHelper.java
@@ -0,0 +1,351 @@
+package com.reachlocal.grails.plugins.cassandra.utils;
+
+import com.reachlocal.grails.plugins.cassandra.mapping.CassandraMappingNullIndexException;
+import com.reachlocal.grails.plugins.cassandra.uuid.UuidDynamicMethods;
+import groovy.lang.GroovyObject;
+import org.codehaus.jackson.JsonGenerationException;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.URLEncoder;
+import java.nio.ByteBuffer;
+import java.text.DateFormat;
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * @author: Bob Florian
+ */
+public class KeyHelper
+{
+ static String makeComposite(List<String> list)
+ {
+ int len = list.size();
+ if (len == 1) {
+ return list.get(0);
+ }
+ else {
+ StringBuilder sb = new StringBuilder(list.get(0));
+ for (int i=1; i < len; i++) {
+ sb.append("__");
+ sb.append(list.get(i));
+ }
+ return sb.toString();
+ }
+ }
+
+ static String[] parseComposite(String value)
+ {
+ return value.split("__");
+ }
+
+ static String joinRowKey(Class fromClass, Class toClass, String propName, GroovyObject object) throws UnsupportedEncodingException
+ {
+ //def fromClassName = fromClass.name.split("\\.")[-1]
+ //"${fromClassName}?${propName}=${URLEncoder.encode(object.id)}".toString()
+ return joinRowKeyFromId(fromClass, toClass, propName, String.valueOf(object.getProperty("id")));
+ }
+
+ static String joinRowKeyFromId(Class fromClass, Class toClass, String propName, String objectId) throws UnsupportedEncodingException
+ {
+ String fromClassName = fromClass.getSimpleName();
+ return fromClassName + "?" + propName + "=" + URLEncoder.encode(objectId, ENC);
+ }
+
+ static String primaryKeyIndexRowKey()
+ {
+ return "this";
+ }
+
+ static String counterRowKey(List whereKeys, List<String> groupKeys, Map map) throws IOException
+ {
+ String key = objectIndexRowKey(whereKeys, map);
+ return key != null ? key + "#" + makeComposite(groupKeys) : null;
+ }
+
+ static String counterRowKey(List whereKeys, List<String> groupKeys, GroovyObject bean) throws IOException
+ {
+ String key = objectIndexRowKey(whereKeys, bean);
+ return key != null ? key + "#" + makeComposite(groupKeys) : null;
+ }
+
+ static List<String> makeGroupKeyList(List<String>keys, String dateSuffix)
+ {
+ List<String> result = new ArrayList<String>(keys.size());
+ result.add(0, keys.get(0) + "[" + dateSuffix + "]");
+ return result;
+ }
+
+ static String objectIndexRowKey(String propName, Map map) throws IOException
+ {
+ try {
+ return indexRowKey(propName, map.get(propName));
+ }
+ catch (CassandraMappingNullIndexException e) {
+ return null;
+ }
+ }
+
+ static String objectIndexRowKey(List propNames, Map map) throws IOException
+ {
+ try {
+ List<List<Object>> items = new ArrayList<List<Object>>();
+ for (Object it: propNames) {
+ List<Object> tuple = new ArrayList<Object>(2);
+ tuple.add(it);
+ tuple.add(map.get(it));
+ items.add(tuple);
+ }
+ return indexRowKey(items);
+ }
+ catch (CassandraMappingNullIndexException e) {
+ return null;
+ }
+ }
+
+ static String objectIndexRowKey(String propName, GroovyObject bean) throws IOException
+ {
+ try {
+ return indexRowKey(propName, bean.getProperty(propName));
+ }
+ catch (CassandraMappingNullIndexException e) {
+ return null;
+ }
+ }
+
+ static String objectIndexRowKey(List<String> propNames, GroovyObject bean) throws IOException
+ {
+ try {
+ List<List<Object>> items = new ArrayList<List<Object>>(propNames.size());
+ for (String it: propNames) {
+ List<Object> tuple = new ArrayList<Object>(2);
+ tuple.add(it);
+ tuple.add(bean.getProperty(it));
+ items.add(tuple);
+ }
+ return indexRowKey(items);
+ }
+ catch (CassandraMappingNullIndexException e) {
+ return null;
+ }
+ }
+
+
+ static Collection objectIndexRowKeys(String propName, GroovyObject bean) throws IOException
+ {
+ try {
+ Object value = bean.getProperty(propName);
+ if (value instanceof Collection) {
+ Collection c = (Collection)value;
+ List<String> result = new ArrayList<String>();
+ for (Object it: c) {
+ result.add(indexRowKey(propName, it));
+ }
+ return result;
+ }
+ else if (value != null) {
+ List<String> result = new ArrayList<String>();
+ result.add(indexRowKey(propName, value));
+ return result;
+ }
+ else {
+ return new ArrayList<String>();
+ }
+ }
+ catch (CassandraMappingNullIndexException e) {
+ return null;
+ }
+ }
+
+ static Collection<String> objectIndexRowKeys(List<String> propNames, GroovyObject bean) throws IOException
+ {
+ try {
+ List<Object> valueList = new ArrayList<Object>(propNames.size());
+ for (String it: propNames) {
+ valueList.add(bean.getProperty(it));
+ }
+ List<String> result = new ArrayList<String>(valueList.size());
+ List<List<Object>> v2 = OrmHelper.expandNestedArray(valueList);
+ for (List values: v2) {
+ List<List<Object>> pairs = new ArrayList<List<Object>>();
+ int index = 0;
+ for (String name: propNames) {
+ List<Object> tuple = new ArrayList<Object>(2);
+ tuple.add(name);
+ tuple.add(values.get(index));
+ pairs.add(tuple);
+ index++;
+ }
+ String key = indexRowKey(pairs);
+ if (key != null) {
+ result.add(key);
+ }
+ }
+ return result;
+ }
+ catch (CassandraMappingNullIndexException e) {
+ return null;
+ }
+ }
+
+ static String indexRowKey(String name, Object value) throws CassandraMappingNullIndexException, IOException
+ {
+ try {
+ //"this?${name}=${URLEncoder.encode(primaryRowKey(value))}".toString()
+ return "this?" + name + "=" + URLEncoder.encode(primaryRowKey(value), ENC);
+ }
+ catch (CassandraMappingNullIndexException e) {
+ return null;
+ }
+ }
+
+ static String manyBackIndexRowKey(String objectId)
+ {
+ return "this#" + objectId;
+ }
+
+ static String oneBackIndexRowKey(String objectId)
+ {
+ return "this@" + objectId;
+ }
+
+ static String oneBackIndexColumnName(String columnFamily, String propertyName, String objectKey)
+ {
+ //"${objectKey}${END_CHAR}${propertyName}${END_CHAR}${columnFamily}".toString()
+ return objectKey + END_CHAR + propertyName + END_CHAR + columnFamily;
+ }
+
+ static List<String> oneBackIndexColumnValues(String name)
+ {
+ String[] array = name.split(END_CHAR);
+ List<String> result = new ArrayList<String>(array.length);
+ for (int i=array.length-1; i >= 0; i--) {
+ result.add(array[i]);
+ }
+ return result;
+ }
+
+ static String indexRowKey(List<List<Object>> pairs) throws CassandraMappingNullIndexException, IOException
+ {
+ try {
+ String sep = "?";
+ StringBuilder sb = new StringBuilder("this");
+ for (List<Object> it: pairs) {
+ sb.append(sep);
+ sb.append(it.get(0));
+ sb.append("=");
+ sb.append(URLEncoder.encode(primaryRowKey(it.get(1)), ENC));
+ sep = "&";
+ }
+ return sb.toString();
+ }
+ catch (CassandraMappingNullIndexException e) {
+ return null;
+ }
+ }
+ static String counterColumnKey(List items, DateFormat dateFormat) throws CassandraMappingNullIndexException, IOException
+ {
+ if (items != null && items.size() > 0) {
+ List<String> list = new ArrayList<String>(items.size());
+ for (Object it: items) {
+ list.add(counterColumnKey(it, dateFormat));
+ }
+ return makeComposite(list);
+
+ }
+ else {
+ throw new CassandraMappingNullIndexException("Counter column keys cannot bean null or blank");
+ }
+ }
+
+ static String counterColumnKey(Date date, DateFormat dateFormat) throws CassandraMappingNullIndexException
+ {
+ if (date != null) {
+ return dateFormat.format(date);
+ }
+ else {
+ throw new CassandraMappingNullIndexException("Counter column keys cannot bean null or blank");
+ }
+ }
+
+ static String counterColumnKey(String str, DateFormat dateFormat) throws CassandraMappingNullIndexException
+ {
+ if (str != null && str.length() > 0) {
+ return str;
+ }
+ else {
+ throw new CassandraMappingNullIndexException("Counter column keys cannot bean null or blank");
+ }
+ }
+
+ static String counterColumnKey(Object obj, DateFormat dateFormat) throws CassandraMappingNullIndexException, IOException
+ {
+ return primaryRowKey(obj); //TODO - dateFormat???
+ }
+
+ static String nullablePrimaryRowKey(Object obj) throws CassandraMappingNullIndexException, IOException
+ {
+ return obj == null ? null : primaryRowKey(obj);
+ }
+
+ static String primaryRowKey(Object obj) throws CassandraMappingNullIndexException, IOException
+ {
+ if (obj instanceof String) {
+ return (String)obj;
+ }
+ else if (obj instanceof UUID) {
+ UUID id = (UUID)obj;
+ if (id.version() == 1) {
+ long time = UuidDynamicMethods.time(id);
+ String ts = time < 0L ? INT_KEY_FMT2.format(time) : INT_KEY_FMT1.format(time);
+ return ts + "_" + id.toString();
+ }
+ else {
+ return id.toString();
+ }
+
+ }
+ else if (obj instanceof GroovyObject) {
+ GroovyObject g = (GroovyObject)obj;
+ if (OrmHelper.isMappedObject(g)) {
+ return (String)g.getProperty("id");
+ }
+ }
+ else if (obj == null) {
+ throw new CassandraMappingNullIndexException("Primary keys and indexed properties cannot have null values");
+ }
+ else if (obj instanceof Collection) {
+ Collection c = (Collection)obj;
+ List<String> items = new ArrayList<String>(c.size());
+ for (Object it: c) {
+ items.add(primaryRowKey(it));
+ }
+ return makeComposite(items);
+ }
+ else if (obj instanceof Number || obj instanceof Boolean) {
+ return obj.toString();
+ }
+
+ try {
+ return String.valueOf(DataMapper.dataProperty(obj));
+ }
+ catch (IllegalArgumentException e) {
+ // TODO - why do we get this for enums in counters and not in simple properties?
+ return obj.toString();
+ }
+ }
+
+ static final String ENC = "UTF-8";
+ static final String END_CHAR = "\u00ff";
+
+ static final DecimalFormat INT_KEY_FMT1 = new DecimalFormat("000000000000000");
+ static final DecimalFormat INT_KEY_FMT2 = new DecimalFormat("00000000000000");
+
+ static DateFormat ISO_TS = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
+ static {
+ ISO_TS.setTimeZone(TimeZone.getTimeZone("GMT"));
+ }
+}
View
228 src/java/com/reachlocal/grails/plugins/cassandra/utils/OrmHelper.java
@@ -0,0 +1,228 @@
+package com.reachlocal.grails.plugins.cassandra.utils;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.*;
+import com.reachlocal.grails.plugins.cassandra.mapping.CassandraMappingException;
+import groovy.lang.GroovyObject;
+import groovy.lang.MissingMethodException;
+import groovy.lang.MissingPropertyException;
+import org.apache.commons.beanutils.PropertyUtils;
+
+import java.util.List;
+
+/**
+ * @author: Bob Florian
+ */
+public class OrmHelper
+{
+ public static final String END_CHAR = "\u00ff";
+ public static final int MAX_ROWS = 5000;
+ public static final String CLASS_NAME_KEY = "_class_name_";
+ public static final String KEY_SUFFIX = "Id";
+ public static final String DIRTY_SUFFIX = "_dirty";
+ public static final String CLUSTER_PROP = "_cassandra_cluster_";
+
+ public static String methodForPropertyName(String prefix, String propertyName)
+ {
+ String result = prefix + propertyName.substring(0,1);
+ if (propertyName.length() > 1) {
+ return prefix + propertyName.substring(0,1).toUpperCase() + propertyName.substring(1);
+ }
+ else {
+ return prefix + propertyName.toUpperCase();
+ }
+ }
+
+ public static List propertyListFromMethodName(String name)
+ {
+ String[] exps = name.replaceAll("([a-z,0-9])And([A-Z])","$1,$2").split(",");
+ List<String> result = new ArrayList<String>(exps.length);
+ for (String it: exps) {
+ if (it.length() > 1) {
+ result.add(it.substring(0, 1).toLowerCase() + it.substring(1));
+ }
+ else {
+ result.add(it.toLowerCase());
+ }
+ }
+ return result;
+ }
+
+ public static String propertyNameFromClassName(String name)
+ {
+ return name.substring(0,1).toLowerCase() + name.substring(1);
+ }
+
+ public static Collection collection(Object value)
+ {
+ // TODO handle arrays?
+ if (value instanceof Collection) {
+ return (Collection)value;
+ }
+ else {
+ List<Object> list = new ArrayList<Object>(1);
+ list.add(value);
+ return list;
+ }
+ }
+
+ public static boolean containsElement(Collection col1, Collection col2)
+ {
+ for (Object obj: col1) {
+ if (col2.contains(obj)) {
+ return true;
+ }
+ }
+ return false;
+ }
+/*
+ public static boolean isMappedClass(Class clazz) {
+ return clazz.metaClass.hasMetaProperty("cassandraMapping")
+ }
+*/
+ public static boolean isMappedObject(GroovyObject object) {
+ // TODO - doesn't test for static!
+ //return object ? object.getClass().metaClass.hasMetaProperty("cassandraMapping") : false
+ Object value = object.getProperty("cassandraMapping");
+ return value != null && value instanceof Map;
+ }
+/*
+ public static boolean isMappedProperty(Class clazz, String name) {
+ try {
+ def propClass = clazz.getDeclaredField(name)?.type // TODO - support superclasses?
+ return propClass ? isMappedClass(propClass) : false
+ }
+ catch (NoSuchFieldException e) {
+ return false
+ }
+ }
+
+ public static safeGetStaticProperty(clazz, name)
+ {
+ if (clazz.metaClass.hasMetaProperty(name)) {
+ return clazz.metaClass.getMetaProperty(name).getProperty()
+ }
+ return null
+ }
+*/
+ public static Object safeGetProperty(GroovyObject data, String name, Class clazz, Object defaultValue)
+ {
+ Object value;
+ try {
+ value = data.getProperty(name);
+ if (!clazz.isInstance(value)) {
+ value = defaultValue;
+ }
+ }
+ catch (MissingPropertyException e) {
+ value = defaultValue;
+ }
+ catch (MissingMethodException e) {
+ value = defaultValue;
+ }
+ return value;
+ }
+
+ public static void safeSetProperty(Object object, String name, Object value) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException
+ {
+ if (PropertyUtils.getPropertyType(object, name) != null) {
+ PropertyUtils.setProperty(object, name, value);
+ }
+ }
+
+ public static Map addOptionDefaults(Map<String, Object>options, Integer defaultCount)
+ {
+ return addOptionDefaults(options, defaultCount, null);
+ }
+
+ public static Map addOptionDefaults(Map<String, Object>options, Integer defaultCount, String cluster)
+ {
+ Map<String, Object> result = new LinkedHashMap<String, Object>();
+ result.putAll(options);
+
+ Object reversed = options.get("reversed");
+ if (reversed == null) {
+ reversed = false;
+ }
+ result.put("reversed", reversed);
+
+ Object max = options.get("max");
+ if (max == null) {
+ max = defaultCount;
+ }
+ result.put("max", max);
+
+ Object clstr = options.get("cluster");
+ if (clstr == null && cluster != null) {
+ result.put("cluster", cluster);
+ }
+ return result;
+ }
+
+ public static Map<String, Object> sort(Map<String, Object> map)
+ {
+ Map<String, Object> sorted = new LinkedHashMap<String, Object>();
+ List<String> keys = new ArrayList<String>(map.size());
+ keys.addAll(map.keySet());
+ Collections.sort(keys);
+ for (String key: keys) {
+ sorted.put(key, map.get(key));
+ }
+ return sorted;
+ }
+
+ public static List<List<Object>> expandNestedArray(List params)
+ {
+ List<List<Object>> result = new ArrayList<List<Object>>(params.size());
+ Integer len = 1;
+ List<Integer> lengths = new ArrayList<Integer>(params.size());
+
+ for (Object value: params) {
+ if (value instanceof List) {
+ len = len * ((List)value).size();
+ }
+ else if (value != null && value.getClass().isArray()) {
+ len = len * ((Object[])value).length;
+ }
+ lengths.add(len);
+ }
+
+ for (int i=0; i < len; i++) {
+ result.add(new ArrayList<Object>());
+ }
+
+ int pindex = 0;
+ for (Object value: params) {
+ if (value instanceof List) {
+ List valueList = (List)value;
+ int index = 0;
+ for (List<Object> item: result) {
+ int i = (index * lengths.get(pindex) / len) % valueList.size();
+ item.add(valueList.get(i));
+ }
+ }
+ else if (value != null && value.getClass().isArray()) {
+ String[] valueList = (String[])value;
+ int index = 0;
+ for (List<Object> item: result) {
+ int i = (index * lengths.get(pindex) / len) % valueList.length;
+ item.add(valueList[i]);
+ }
+ }
+ else {
+ for (List<Object> item: result) {
+ item.add(value);
+ }
+ }
+ pindex++;
+ }
+ return result;
+ }
+
+ public static void checkForDefaultRowsInsufficient(Integer max, Integer count) throws CassandraMappingException
+ {
+ if (max == null && count == MAX_ROWS) {
+ throw new CassandraMappingException("Query failed because default row limit of ${MAX_ROWS} is potentially insuficient. Specify an explicit max option.");
+ }
+ }
+}
View
13 test/unit/com/reachlocal/grails/plugins/cassandra/test/InsertPerformanceTests.groovy
@@ -5,12 +5,13 @@ import static org.junit.Assert.*
import com.reachlocal.grails.plugins.cassandra.test.orm.Visit
import com.reachlocal.grails.plugins.cassandra.test.orm.WebsiteVisit
import com.reachlocal.grails.plugins.cassandra.mapping.DataMapping
+import com.reachlocal.grails.plugins.cassandra.mapping.InstanceMethods
class InsertPerformanceTests extends OrmTestCase
{
static iterations = 5
- static num = 1000
-
+ static num = 100
+/*
@Test
void testOne()
{
@@ -80,17 +81,17 @@ class InsertPerformanceTests extends OrmTestCase
println m1
//println m2
}
-
+*/
@Test
void testFour()
{
initialize()
-
+ def uuid = UUID.timeUUID()
for (k in 1..iterations) {
- def num = 1
def t0 = System.currentTimeMillis()
for (i in 1..num) {
def v = new Visit(
+ //uuid: uuid,
siteName: "SITE_01",
occurTime: new Date(),
referrerType: "Search",
@@ -105,5 +106,7 @@ class InsertPerformanceTests extends OrmTestCase
def elapsed = System.currentTimeMillis() - t0
println "Inserted $num records in $elapsed msec, ${(num / (elapsed / 1000.0)).toInteger()} rec/sec, ${elapsed / num} msec/rec"
}
+
+ InstanceMethods.dumpProfiler()
}
}
View
7 test/unit/com/reachlocal/grails/plugins/cassandra/test/MappingUtilsTests.groovy
@@ -29,13 +29,6 @@ import static org.junit.Assert.*
class MappingUtilsTests extends GrailsUnitTestCase
{
@Test
- void testStringValue()
- {
- assertEquals '"value"', MappingUtils.stringValue("value")
- assertEquals '123', MappingUtils.stringValue(123)
- }
-
- @Test
void testMethodForPropertyName()
{
assertEquals "getSomeOtherProperty", MappingUtils.methodForPropertyName("get", "someOtherProperty")
View
107 test/unit/com/reachlocal/grails/plugins/cassandra/test/OrmHelperTests.groovy
@@ -0,0 +1,107 @@
+package com.reachlocal.grails.plugins.cassandra.test
+
+import org.junit.Test
+import static org.junit.Assert.*
+import com.reachlocal.grails.plugins.cassandra.mapping.MappingUtils
+import com.reachlocal.grails.plugins.cassandra.utils.OrmHelper
+import com.reachlocal.grails.plugins.cassandra.test.orm.Visit
+import com.reachlocal.grails.plugins.cassandra.test.orm.User
+import com.reachlocal.grails.plugins.cassandra.mapping.BaseUtils
+
+/**
+ * @author: Bob Florian
+ */
+class OrmHelperTests
+{
+
+ @Test
+ void testMethodForPropertyName()
+ {
+ assertEquals "getSomeOtherProperty", OrmHelper.methodForPropertyName("get", "someOtherProperty")
+ assertEquals "setX", OrmHelper.methodForPropertyName("set", "x")
+ }
+
+ @Test
+ void testPropertyListFromMethodName()
+ {
+ assertEquals "name", OrmHelper.propertyListFromMethodName("Name")[0]
+ assertEquals "name", OrmHelper.propertyListFromMethodName("NameAndRank")[0]
+ assertEquals "rank", OrmHelper.propertyListFromMethodName("NameAndRank")[1]
+ }
+
+ @Test
+ void testPropertyPropertyNameFromClassName()
+ {
+ assertEquals "websiteVisit", OrmHelper.propertyNameFromClassName("WebsiteVisit")
+ assertEquals "visit", OrmHelper.propertyNameFromClassName("Visit")
+ assertEquals "pD", OrmHelper.propertyNameFromClassName("PD")
+ }
+
+ @Test
+ void testCollection()
+ {
+ assertEquals "name", OrmHelper.collection("name")[0]
+ assertEquals "rank", OrmHelper.collection(["rank"])[0]
+ }
+
+ @Test
+ void testContainsElement()
+ {
+ assertTrue OrmHelper.containsElement([1,2,3,4],[4,16,32])
+ assertFalse OrmHelper.containsElement([1,3,5,7],[2,4,6,8])
+ }
+
+ @Test
+ void testSafeGetProperty()
+ {
+ def visit = new Visit()
+ def user = new User()
+
+ assertEquals 0, OrmHelper.safeGetProperty(user, "transients", List, []).size()
+ assertEquals "ageInDays", OrmHelper.safeGetProperty(visit, "transients", List, [])[0]
+ }
+
+ @Test
+ void testAddOptionDefaults()
+ {
+ assertEquals 1000, OrmHelper.addOptionDefaults([:], 1000).max
+ assertEquals 50, OrmHelper.addOptionDefaults([max:50], 1000).max
+ assertEquals false, OrmHelper.addOptionDefaults([max:50], 1000).reversed
+ assertEquals true, OrmHelper.addOptionDefaults([max:50, reversed:true], 1000).reversed
+ assertEquals false, OrmHelper.addOptionDefaults([max:50, reversed:false], 1000).reversed
+ assertNull OrmHelper.addOptionDefaults([max:50], 1000).cluster
+ assertEquals "xxx", OrmHelper.addOptionDefaults([max:50], 1000, "xxx").cluster
+ assertEquals "yyy", OrmHelper.addOptionDefaults([max:50, cluster: "yyy"], 1000, "xxx").cluster
+ assertEquals "foobar", OrmHelper.addOptionDefaults([max:50, cluster:"xxx", foo:"foobar"], 1000).foo
+ }
+
+ @Test
+ void testExpandedNestedArray()
+ {
+ def key1 = OrmHelper.expandNestedArray(["one","two","three"])
+ println key1
+ assertEquals 1, key1.size()
+
+ def key2 = OrmHelper.expandNestedArray(["one",["twoA","twoB"],"three"])
+ println key2
+ assertEquals 2, key2.size()
+
+ def key3 = OrmHelper.expandNestedArray(["one",["twoA","twoB"],["threeX","threeY"]])
+ println key3
+ assertEquals 4, key3.size()
+
+ def t0 = System.currentTimeMillis()
+ for (i in 1..1000) {
+ key3 = MappingUtils.expandNestedArray(["one",["twoA","twoB"],["threeX","threeY"]])
+ }
+ def elapsed = System.currentTimeMillis() - t0
+ println "$elapsed msec (OLD)"
+
+ t0 = System.currentTimeMillis()
+ for (i in 1..1000) {
+ key3 = OrmHelper.expandNestedArray(["one",["twoA","twoB"],["threeX","threeY"]])
+ }
+ elapsed = System.currentTimeMillis() - t0
+ println "$elapsed msec (NEW)"
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.