mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
ACS-6329 Move generate-hazelcast-config.py to community-repo (#2328)
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -39,6 +39,9 @@ dependency-reduced-pom.xml
|
|||||||
|
|
||||||
hs_err_pid*
|
hs_err_pid*
|
||||||
|
|
||||||
|
# Development
|
||||||
|
repository/scripts/hazelcast-init/alfresco-hazelcast-config.xml
|
||||||
|
|
||||||
# Alfresco runtime
|
# Alfresco runtime
|
||||||
alf_data
|
alf_data
|
||||||
|
|
||||||
|
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<hazelcast xmlns="http://www.hazelcast.com/schema/config"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.hazelcast.com/schema/config
|
||||||
|
http://www.hazelcast.com/schema/config/hazelcast-config-5.3.xsd">
|
||||||
|
|
||||||
|
<cluster-name>Replace this with a secure value</cluster-name>
|
||||||
|
<management-center data-access-enabled="${alfresco.hazelcast.mancenter.enabled}">
|
||||||
|
<trusted-interfaces>
|
||||||
|
<interface>${alfresco.hazelcast.mancenter.url}</interface>
|
||||||
|
</trusted-interfaces>
|
||||||
|
</management-center>
|
||||||
|
<!-- Ephemeral lock store map definition -->
|
||||||
|
<map name="lockStore">
|
||||||
|
<backup-count>1</backup-count>
|
||||||
|
<!-- No overall size limit, since this would result in ephemeral locks being evicted. -->
|
||||||
|
<merge-policy>com.hazelcast.spi.merge.PutIfAbsentMergePolicy</merge-policy>
|
||||||
|
<eviction eviction-policy="NONE" max-size-policy="PER_NODE" size="0"/>
|
||||||
|
<!-- TTL here must match LockServiceImpl.MAX_EPHEMERAL_LOCK_SECONDS -->
|
||||||
|
<time-to-live-seconds>172800</time-to-live-seconds>
|
||||||
|
<max-idle-seconds>0</max-idle-seconds>
|
||||||
|
</map>
|
||||||
|
<!-- CACHES DEFINITION (DO NOT REMOVE THIS PLACEHOLDER) -->
|
||||||
|
</hazelcast>
|
21
repository/scripts/hazelcast-init/ci-caches.properties
Normal file
21
repository/scripts/hazelcast-init/ci-caches.properties
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# These caches definitions are automatically adapted to XML configuration
|
||||||
|
# and used for integration test purposes. Be mindful when changing these!
|
||||||
|
|
||||||
|
# cache to test max items setting
|
||||||
|
cache.maxItemsCache.maxItems=1000
|
||||||
|
cache.maxItemsCache.timeToLiveSeconds=0
|
||||||
|
cache.maxItemsCache.maxIdleSeconds=0
|
||||||
|
cache.maxItemsCache.cluster.type=fully-distributed
|
||||||
|
cache.maxItemsCache.backup-count=1
|
||||||
|
cache.maxItemsCache.eviction-policy=LRU
|
||||||
|
cache.maxItemsCache.merge-policy=com.hazelcast.spi.merge.PutIfAbsentMergePolicy
|
||||||
|
cache.maxItemsCache.readBackupData=false
|
||||||
|
|
||||||
|
# cache to test time to live setting
|
||||||
|
cache.ttlCache.timeToLiveSeconds=1
|
||||||
|
cache.ttlCache.maxIdleSeconds=0
|
||||||
|
cache.ttlCache.cluster.type=fully-distributed
|
||||||
|
cache.ttlCache.backup-count=1
|
||||||
|
cache.ttlCache.eviction-policy=LRU
|
||||||
|
cache.ttlCache.merge-policy=com.hazelcast.spi.merge.PutIfAbsentMergePolicy
|
||||||
|
cache.ttlCache.readBackupData=false
|
141
repository/scripts/hazelcast-init/generate-hazelcast-config.py
Executable file
141
repository/scripts/hazelcast-init/generate-hazelcast-config.py
Executable file
@@ -0,0 +1,141 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
"""Python script to convert Hazelcast cache definitions from Java properties to XML"""
|
||||||
|
__author__="Domenico Sibilio"
|
||||||
|
|
||||||
|
import collections
|
||||||
|
import configparser
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
from xml.dom import minidom
|
||||||
|
from typing import List
|
||||||
|
from pathlib import Path
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
ROOT_PATH = Path(__file__).parent
|
||||||
|
CONFIG_PATH = ROOT_PATH / 'ci-caches.properties'
|
||||||
|
OUTPUT_PATH = ROOT_PATH / 'alfresco-hazelcast-config.xml'
|
||||||
|
TEMPLATE_PATH = ROOT_PATH / 'alfresco-hazelcast-template.xml'
|
||||||
|
TEMPLATE_PLACEHOLDER = '<!-- CACHES DEFINITION (DO NOT REMOVE THIS PLACEHOLDER) -->'
|
||||||
|
PROPS_TO_XML = {
|
||||||
|
# time-to-live-seconds with value = x
|
||||||
|
'timeToLiveSeconds': 'time-to-live-seconds',
|
||||||
|
# max-idle-seconds with value = x
|
||||||
|
'maxIdleSeconds': 'max-idle-seconds',
|
||||||
|
# backup-count with value = x
|
||||||
|
'backup-count': 'backup-count',
|
||||||
|
# read-backup-data with value = x
|
||||||
|
'readBackupData': 'read-backup-data',
|
||||||
|
# merge-policy with value = x
|
||||||
|
'merge-policy': 'merge-policy',
|
||||||
|
# eviction with eviction-policy=x and max-size-policy=PER_NODE and size=${maxItems}
|
||||||
|
'eviction-policy': 'eviction',
|
||||||
|
# near-cache.eviction max-size-policy=ENTRY_COUNT, eviction-policy=LRU and size = x
|
||||||
|
'nearCache.maxSize': 'size',
|
||||||
|
# near-cache.max-idle-seconds with value = x
|
||||||
|
'nearCache.maxIdleSeconds': 'max-idle-seconds',
|
||||||
|
# near-cache.time-to-live-seconds with value = x
|
||||||
|
'nearCache.timeToLiveSeconds': 'time-to-live-seconds',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_prop(prop_key: str):
|
||||||
|
# shortcut to get the property within the default section
|
||||||
|
return config.get('default', prop_key)
|
||||||
|
|
||||||
|
|
||||||
|
def get_cache_name(sections: List[str]):
|
||||||
|
# get the cache name given the full property string split by '.'
|
||||||
|
return '.'.join(sections[0:get_cache_name_index(sections)+1])
|
||||||
|
|
||||||
|
|
||||||
|
def get_cache_name_index(sections: List[str]):
|
||||||
|
# returns the index where the cache name ends
|
||||||
|
# given the full property string split by '.'
|
||||||
|
for i, e in enumerate(sections):
|
||||||
|
if e.endswith('Cache'):
|
||||||
|
return i
|
||||||
|
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
def get_key(sections: List[str]):
|
||||||
|
# get the property key name given the full property string split by '.'
|
||||||
|
cn_index = get_cache_name_index(sections)
|
||||||
|
key_sections = sections[cn_index+1::]
|
||||||
|
return '.'.join(key_sections)
|
||||||
|
|
||||||
|
|
||||||
|
def prettify(xml_string: str):
|
||||||
|
# format and indent an xml string
|
||||||
|
prettified_xml = minidom.parseString(xml_string).toprettyxml(indent=' ')
|
||||||
|
return '\n'.join([line for line in prettified_xml.splitlines() if line.strip()])
|
||||||
|
|
||||||
|
|
||||||
|
# entrypoint
|
||||||
|
parser = argparse.ArgumentParser(description='A Python script to generate XML Hazelcast cache definitions starting from Java properties.')
|
||||||
|
parser.add_argument('-s', '--source', default=CONFIG_PATH, help='path to the Java properties file to convert')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
source_path = args.source
|
||||||
|
|
||||||
|
# add dummy section to properties
|
||||||
|
with open(source_path, 'r') as f:
|
||||||
|
cache_props = '[default]\n' + f.read()
|
||||||
|
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
# preserve property case
|
||||||
|
config.optionxform = str
|
||||||
|
# parse config file
|
||||||
|
config.read_string(cache_props)
|
||||||
|
|
||||||
|
# group properties by cache name
|
||||||
|
props_by_cache = collections.defaultdict(list)
|
||||||
|
for item in config.items('default'):
|
||||||
|
sections = item[0].split('.')
|
||||||
|
if sections[0] == 'cache':
|
||||||
|
cache_name = get_cache_name(sections)
|
||||||
|
key = get_key(sections)
|
||||||
|
value = item[1]
|
||||||
|
props_by_cache[cache_name].append((key, value))
|
||||||
|
|
||||||
|
# read template file
|
||||||
|
with open(TEMPLATE_PATH, 'r') as input:
|
||||||
|
template = input.read()
|
||||||
|
|
||||||
|
# perform template substitutions to apply the caches.properties configuration
|
||||||
|
map_configs = ''
|
||||||
|
for cache, props in props_by_cache.items():
|
||||||
|
props = dict(props)
|
||||||
|
if(props.get('cluster.type') == 'fully-distributed'):
|
||||||
|
map = ET.Element('map', name=cache)
|
||||||
|
near_cache = None
|
||||||
|
for prop, value in props.items():
|
||||||
|
xml_prop = PROPS_TO_XML.get(prop)
|
||||||
|
# handle eviction configuration
|
||||||
|
if prop == 'eviction-policy':
|
||||||
|
ET.SubElement(map, xml_prop,
|
||||||
|
{'eviction-policy': value,
|
||||||
|
'max-size-policy': 'PER_NODE',
|
||||||
|
'size': props.get('maxItems') if props.get('maxItems') else '0'})
|
||||||
|
# handle near-cache configuration
|
||||||
|
elif prop.startswith('nearCache'):
|
||||||
|
if near_cache is None:
|
||||||
|
near_cache = ET.SubElement(map, 'near-cache')
|
||||||
|
if prop.split('.')[1] == 'maxSize':
|
||||||
|
ET.SubElement(near_cache, 'eviction',
|
||||||
|
{'max-size-policy': 'ENTRY_COUNT',
|
||||||
|
'eviction-policy': 'LRU',
|
||||||
|
xml_prop: value})
|
||||||
|
else:
|
||||||
|
ET.SubElement(near_cache, xml_prop).text = value
|
||||||
|
# handle basic map configuration
|
||||||
|
elif xml_prop:
|
||||||
|
ET.SubElement(map, xml_prop).text = value
|
||||||
|
ET.SubElement(map, 'per-entry-stats-enabled').text = 'true'
|
||||||
|
map_configs += minidom.parseString(ET.tostring(map)).childNodes[0].toprettyxml(indent=' ')
|
||||||
|
|
||||||
|
template = template.replace(TEMPLATE_PLACEHOLDER, map_configs)
|
||||||
|
|
||||||
|
# produce actual Hazelcast config file
|
||||||
|
with open(OUTPUT_PATH, 'w') as output:
|
||||||
|
output.write(prettify(template))
|
||||||
|
print(f"Generated XML Hazelcast config: {OUTPUT_PATH}")
|
@@ -686,7 +686,6 @@ cache.hbClusterUsageCache.backup-count=1
|
|||||||
cache.hbClusterUsageCache.eviction-policy=NONE
|
cache.hbClusterUsageCache.eviction-policy=NONE
|
||||||
cache.hbClusterUsageCache.merge-policy=com.hazelcast.spi.merge.PutIfAbsentMergePolicy
|
cache.hbClusterUsageCache.merge-policy=com.hazelcast.spi.merge.PutIfAbsentMergePolicy
|
||||||
cache.hbClusterUsageCache.readBackupData=false
|
cache.hbClusterUsageCache.readBackupData=false
|
||||||
q
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Query accelerator cluster cache
|
# Query accelerator cluster cache
|
||||||
|
Reference in New Issue
Block a user