Skip to content

Commit

Permalink
+ Improvements from ATM CR.
Browse files Browse the repository at this point in the history
+ Show Expiry info for caches in admin panel
  • Loading branch information
lbwexler committed Jul 16, 2024
1 parent 0cacbd7 commit d8e72e5
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 16 deletions.
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
## 21.0-SNAPSHOT - unreleased

### ⚙️ Technical

* Improvements to the ability to configure Hibernate Caches for 2nd-level and connection caches.
*
* Improvements to the ability to configure Hibernate 2nd-level caches. See `ClusterConfig` for more
information.

## 20.2.1 - 2024-07-09

Expand Down
6 changes: 0 additions & 6 deletions grails-app/domain/io/xh/hoist/role/provided/Role.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,6 @@ class Role implements JSONFormat {
lastUpdatedBy maxSize: 50
}

// We don't expect a huge number of roles.
// Tighten as example of a custom cache config being applied to a collection cache (Role.members)
static cache = {
evictionConfig.size = 1000
}

static beforeInsert = {
if (Role.findByNameIlike(name)) {
throw new RoutineRuntimeException('Role Name must be case-insensitive unique.')
Expand Down
25 changes: 18 additions & 7 deletions grails-app/init/io/xh/hoist/ClusterConfig.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,17 @@ class ClusterConfig {
}

/**
* Override this to create additional default configs in the application.
* Override this to create additional default Hazelcast configs in the application.
*
* Note that Hoist also introduces two properties for declarative configuration:
*
* - a static 'cache' property on Grails domain objects to customize associated
* Hibernate caches.
* - a static 'clusterConfigs' property on Grails services to customize any Hazelcast
* Distributed Objects associated with the service e.g. Hoist caches
*
* See toolbox's `Phase` object and Hoist Core's `ClientErrorService` for examples of these
* customizations.
*/
protected void createDefaultConfigs(Config config) {
config.getMapConfig('default').with {
Expand Down Expand Up @@ -162,21 +172,21 @@ class ClusterConfig {
//------------------------
private void createHibernateConfigs(Config config) {
grailsApplication.domainClasses.each { GrailsClass gc ->
// Pre-access cache for all domain classes to ensure we capture the common 'default'
// (Not clear why this is needed -- but hibernate would otherwise create these differently)
// Pre-access cache config for all domain classes to ensure we capture the common 'default'
// (not clear why this is needed -- but hibernate would otherwise create these differently)
def configs = [
// 1) Main 2nd-level entity cache
config.getCacheConfig(gc.fullName),
// 2) Collection caches
// 2) any related collection caches
config.getCacheConfig(gc.fullName + '.*')
]

// apply any app customization
// Apply any app customization specified by new static prop introduced by Hoist
// note we apply the same for both the entity cache [1] and any collection caches [2].
Closure customizer = gc.getPropertyValue('cache') as Closure
if (customizer) {
configs.each { cfg ->
// workaround - hz does not clone evictionConfig
cfg.evictionConfig = new EvictionConfig(cfg.evictionConfig)
cfg.evictionConfig = new EvictionConfig(cfg.evictionConfig) // workaround - hz does not clone
customizer.delegate = cfg
customizer.resolveStrategy = Closure.DELEGATE_FIRST
customizer(cfg)
Expand All @@ -187,6 +197,7 @@ class ClusterConfig {

private void createServiceConfigs(Config config) {
grailsApplication.serviceClasses.each { GrailsClass gc ->
// Apply any app customization specified by new static prop introduced by Hoist
Map objs = gc.getPropertyValue('clusterConfigs')
if (!objs) return
objs.forEach {String key, List value ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import com.hazelcast.topic.ITopic
import io.xh.hoist.BaseService
import io.xh.hoist.util.Utils

import javax.cache.expiry.ExpiryPolicy
import javax.cache.expiry.Duration

import static io.xh.hoist.util.Utils.appContext
import static io.xh.hoist.util.Utils.getExceptionHandler

Expand Down Expand Up @@ -142,6 +145,7 @@ class ClusterAdminService extends BaseService {
]
case CacheProxy:
def evictionConfig = obj.cacheConfig.evictionConfig,
expiryPolicy = obj.cacheConfig.expiryPolicyFactory.create(),
stats = obj.localCacheStatistics
return [
name : obj.getName(),
Expand All @@ -156,7 +160,8 @@ class ClusterAdminService extends BaseService {
config : [
size : evictionConfig.size,
maxSizePolicy : evictionConfig.maxSizePolicy,
evictionPolicy: evictionConfig.evictionPolicy
evictionPolicy: evictionConfig.evictionPolicy,
expiryPolicy : formatExpiryPolicy(expiryPolicy)
]
]
default:
Expand All @@ -180,4 +185,20 @@ class ClusterAdminService extends BaseService {
ratio : stats.ratio.round(2)
]
}

private Map formatExpiryPolicy(ExpiryPolicy policy) {
def ret = [:]
if (policy.expiryForCreation) ret.creation = formatDuration(policy.expiryForCreation)
if (policy.expiryForAccess) ret.access = formatDuration(policy.expiryForAccess)
if (policy.expiryForUpdate) ret.update = formatDuration(policy.expiryForUpdate)
return ret
}


private String formatDuration(Duration duration) {
if (duration.isZero()) return 0
if (duration.isEternal()) return 'eternal'
return duration.timeUnit.toSeconds(duration.durationAmount) + 's'
}

}

0 comments on commit d8e72e5

Please sign in to comment.