http://jira.mfd.msk:8088/browse/CLS-1 storage копипаст сервисов (осторожно-тудушки и конфига нет): готовы на 98%
This commit is contained in:
parent
83463a1ebe
commit
1dee51257e
4 changed files with 356 additions and 0 deletions
|
|
@ -0,0 +1,216 @@
|
|||
package ru.spcex.clearing.storage.services;
|
||||
|
||||
import com.hazelcast.aggregation.Aggregators;
|
||||
import com.hazelcast.config.MapStoreConfig;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.core.IAtomicLong;
|
||||
import com.hazelcast.core.IMap;
|
||||
import com.hazelcast.core.IdGenerator;
|
||||
import com.hazelcast.projection.Projections;
|
||||
import com.hazelcast.query.Predicates;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import ru.clearing.classes.objects.BusinessObject;
|
||||
import ru.spcex.clearing.storage.base.DictionaryMapStore;
|
||||
import ru.spcex.clearing.storage.base.SimpleObjectMapStore;
|
||||
import ru.spcex.clearing.storage.utils.IMDGDistributedNames;
|
||||
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public abstract class AbstractHazelcastLifecycleSupport implements InitializingBean, DisposableBean {
|
||||
/**
|
||||
* Рабочая версия БД. Треьуется вручную сверять с DDL.sql и накручивать эту переменную.
|
||||
*/
|
||||
public abstract String getCheckDbVersion();
|
||||
|
||||
/**
|
||||
* Обязательная сверка у этих классов SerialVersionUID во время подключения к Storage.
|
||||
*/
|
||||
public abstract Class[] getSerialVersionUIDClasses();
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private final HazelcastInstance hazelcastServerInstance;
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
// private final HazelcastClientListener clientListener;
|
||||
// private final ITaskAdministrator startupTasksAdministrator;
|
||||
|
||||
public AbstractHazelcastLifecycleSupport(HazelcastInstance hazelcastServerInstance, JdbcTemplate jdbcTemplate) {
|
||||
this.hazelcastServerInstance = hazelcastServerInstance;
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
// HazelcastCommon.loadClassesVersionsByStorage(hazelcastServerInstance, getSerialVersionUIDClasses());
|
||||
// databaseVersionCheck();
|
||||
|
||||
long loadTime = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
List<Callable<Long>> tasks = new ArrayList<>();
|
||||
for (String mapName : hazelcastServerInstance.getConfig().getMapConfigs().keySet()) {
|
||||
tasks.add(() -> {
|
||||
Long maxKey = null;
|
||||
MapStoreConfig mapStoreConfig = hazelcastServerInstance.getConfig().getMapConfig(mapName).getMapStoreConfig();
|
||||
if (mapStoreConfig != null && mapStoreConfig.isEnabled()) {
|
||||
long start = System.currentTimeMillis();
|
||||
log.info("loading map {}", mapName);
|
||||
IMap<Long, BusinessObject> map = hazelcastServerInstance.getMap(mapName);
|
||||
map.loadAll(false);
|
||||
int size = map.size();
|
||||
long time = System.currentTimeMillis() - start;
|
||||
log.info("{} {} rows loaded in {}ms", mapName, size, time);
|
||||
|
||||
Object mapStore = mapStoreConfig.getImplementation();
|
||||
if (mapStore instanceof SimpleObjectMapStore) {
|
||||
String tableName = ((SimpleObjectMapStore) mapStore).getTableName();
|
||||
maxKey = jdbcTemplate.queryForObject("select max(id) from " + tableName, Long.class);
|
||||
} else if (mapStore instanceof DictionaryMapStore) {
|
||||
// для Dictionary не используется общий id генератор
|
||||
// } else if (mapStore instanceof FrontendUserSessionMapStore) {
|
||||
// // не используется общий id генератор
|
||||
} else {
|
||||
throw new RuntimeException("unknown map store implementation " + mapStore);
|
||||
}
|
||||
log.debug("{} max(id)={}", mapName, maxKey);
|
||||
}
|
||||
|
||||
return maxKey;
|
||||
});
|
||||
}
|
||||
int threadCount = Runtime.getRuntime().availableProcessors();// todo config * Config.get().getRoot().getSettings().getInitHazelcastThreadMultiplier();
|
||||
log.info("Initializing threads count = {}", threadCount);
|
||||
ExecutorService executor = Executors.newWorkStealingPool(threadCount);
|
||||
List<Future<Long>> results = executor.invokeAll(tasks);
|
||||
long maxKey = 0L;
|
||||
for (Future<Long> result : results) {
|
||||
Long maxKeyResult = result.get();
|
||||
if (maxKeyResult != null) {
|
||||
maxKey = Math.max(maxKey, maxKeyResult);
|
||||
}
|
||||
}
|
||||
|
||||
IdGenerator generator = hazelcastServerInstance.getIdGenerator(IMDGDistributedNames.MAP_SEQUENCE_NAME);
|
||||
boolean generatorResult = generator.init(maxKey);
|
||||
if (generatorResult) {
|
||||
log.info("IDGenerator {} success init by {}", IMDGDistributedNames.MAP_SEQUENCE_NAME, maxKey);
|
||||
// makeSchedulerAllTodayMap();
|
||||
} else {
|
||||
log.info("IDGenerator {} already initialized in other node", IMDGDistributedNames.MAP_SEQUENCE_NAME);
|
||||
}
|
||||
|
||||
// MapStoreConfig mapStoreConfig = hazelcastServerInstance.getConfig().getMapConfig(HazelcastDistributedNames.Map_FixedIncomeProductExecution).getMapStoreConfig();
|
||||
// FixedIncomeProductExecutionMapStore fixedIncomeProductExecutionMapStore = (FixedIncomeProductExecutionMapStore) mapStoreConfig.getImplementation();
|
||||
// Long maxExecutionNumber = jdbcTemplate.queryForObject("select max(executionnumber) from " + fixedIncomeProductExecutionMapStore.getTableName(), Long.class);
|
||||
// log.info("{} max(executionnumber)={}", fixedIncomeProductExecutionMapStore.getTableName(), maxExecutionNumber);
|
||||
// if (maxExecutionNumber != null) {
|
||||
// if (Integer.MAX_VALUE - maxExecutionNumber < 1000000)
|
||||
// log.error("max(executionnumber) close to int32 max value");
|
||||
// IAtomicLong executionNumberAtomicLong = hazelcastServerInstance.getAtomicLong(HazelcastDistributedNames.AtomicLong_ExecutionNumber);
|
||||
// executionNumberAtomicLong.set(maxExecutionNumber);
|
||||
// }
|
||||
//
|
||||
// if (startupTasksAdministrator != null) {
|
||||
// startupTasksAdministrator.createTasks();
|
||||
// }
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
throw new RuntimeException("MapStore multithreaded not complete.", e);
|
||||
}
|
||||
|
||||
// HazelcastCommon.otcSystem_setStorageState(true, hazelcastServerInstance); todo в других модулях может быть проверка на это, и должна быть.
|
||||
// hazelcastServerInstance.getClientService().addClientListener(clientListener);
|
||||
loadTime = System.currentTimeMillis() - loadTime;
|
||||
log.info("All map load time {} ms", loadTime);
|
||||
|
||||
// TextErrorService.setHazelcast(hazelcastServerInstance);
|
||||
|
||||
// clusterStatistic();
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Подсчитывает кол-во запусков, первый запуск. Пишет в лог.
|
||||
// * Storage note status: ...
|
||||
// */
|
||||
// protected void clusterStatistic() {
|
||||
// try {
|
||||
// boolean isFirstNodeReady = HazelcastCommon.otcSystem_setStorageInfo(new Date(), true, hazelcastServerInstance);
|
||||
// String msg = "Storage node status: " + (isFirstNodeReady ? "first Storage node" : "second node")
|
||||
// + ", first node start at " + HazelcastCommon.otcSystem_getFirstStorageTime(hazelcastServerInstance);
|
||||
// String firstOtcVersion = HazelcastCommon.otcSystem_getFirstStorageVersion(hazelcastServerInstance);
|
||||
// if (firstOtcVersion != null)
|
||||
// msg += "(OTC " + firstOtcVersion + ")";
|
||||
// msg += ", count of all storage connection " + HazelcastCommon.otcSystem_getStorageConnectCount(hazelcastServerInstance) + ".";
|
||||
// msg += " Hazelcast cluster members: " + hazelcastServerInstance.getCluster().getMembers().size() + ".";
|
||||
// log.info(msg);
|
||||
// } catch (Exception e) {
|
||||
// log.warn("Error at print Storage cluster info.", e);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
hazelcastServerInstance.shutdown();
|
||||
}
|
||||
|
||||
protected void databaseVersionCheck() throws RuntimeException, IllegalArgumentException {
|
||||
log.debug("Validate DB version, expected \"{}\"", getCheckDbVersion());
|
||||
String dbVersion = null;
|
||||
try {
|
||||
dbVersion = jdbcTemplate.queryForObject("select version from VERSIONEDID", String.class);
|
||||
log.info("DB version is \"{}\"", dbVersion);
|
||||
if (StringUtils.isBlank(dbVersion)) {
|
||||
String msg = "Database not contain version information (table VERSIONEDID)";//TextErrorService.text(StorageErrors.StorageErrors_WrongDBVersion) + " Database not contain version information (table VERSIONEDID)";
|
||||
log.error(msg);
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
if (!isAllowDBVersion(getCheckDbVersion(), dbVersion)) {
|
||||
String msg = " platform " + getCheckDbVersion() + ", db " + dbVersion;//TextErrorService.text(StorageErrors.StorageErrors_WrongDBVersion) + " platform " + getCheckDbVersion() + ", db " + dbVersion;
|
||||
log.error(msg);
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
} catch (DataAccessException | IllegalArgumentException e) { // EmptyResultDataAccessException
|
||||
String msg = e.toString();//TextErrorService.text(StorageErrors.StorageErrors_WrongDBVersion) + " platform " + getCheckDbVersion() + ", db " + dbVersion;
|
||||
log.error(msg);
|
||||
throw new RuntimeException(msg, e); // Ошибка 10002 - Версия Бд не поддерживается
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Првоерка версии. Формат: 1.2.*
|
||||
*
|
||||
* @param moduleVersion версия кода
|
||||
* @param dbVersion версия базы
|
||||
* @return true - версии правильные, false - версия БД устарела или не совпадает.
|
||||
* @throws IllegalArgumentException если неправильно распарсилась версия, в частности может случиться NumberFormatException.
|
||||
*/
|
||||
static boolean isAllowDBVersion(String moduleVersion, String dbVersion) throws IllegalArgumentException {
|
||||
Pattern versionPattern = Pattern.compile("(\\d+)\\.(\\d+)(\\..*){0,1}"); // (\d+)\.(\d+)(\..*){0,1}
|
||||
Matcher mModule = versionPattern.matcher(moduleVersion);
|
||||
Matcher mDB = versionPattern.matcher(dbVersion);
|
||||
if (!mModule.find())
|
||||
throw new IllegalArgumentException("Module version have wrong format: " + moduleVersion);
|
||||
if (!mDB.find())
|
||||
throw new IllegalArgumentException("Version from database have wrong format: " + moduleVersion);
|
||||
int majorModule = Integer.parseInt(mModule.group(1));
|
||||
int minorModule = Integer.parseInt(mModule.group(2));
|
||||
int majorDB = Integer.parseInt(mDB.group(1));
|
||||
int minorDB = Integer.parseInt(mDB.group(2));
|
||||
return majorDB == majorModule && minorDB >= minorModule;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
package ru.spcex.clearing.storage.services;
|
||||
|
||||
import com.hazelcast.core.EntryEvent;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.map.listener.EntryAddedListener;
|
||||
import com.hazelcast.map.listener.EntryRemovedListener;
|
||||
import com.hazelcast.map.listener.EntryUpdatedListener;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import ru.clearing.classes.objects.BusinessEvent;
|
||||
import ru.spcex.clearing.storage.utils.IMDGDistributedNames;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
public abstract class AbstractUpdateMapService implements InitializingBean, EntryAddedListener<Long, Object>, EntryUpdatedListener<Long, Object>, EntryRemovedListener<Long, Object> {
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
protected final String EVENT_CREATE="CREATE";
|
||||
protected final String EVENT_UPDATE="UPDATE";
|
||||
protected final String EVENT_DELETE="DELETE";
|
||||
|
||||
protected final HazelcastInstance hazelcastServerInstance;
|
||||
|
||||
public AbstractUpdateMapService(HazelcastInstance hazelcastServerInstance) {
|
||||
this.hazelcastServerInstance = hazelcastServerInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
// if (!HazelcastCommon.otcSystem_getStorageState(hazelcastServerInstance))
|
||||
// log.warn("UpdateMapService started before Storage had ready!");
|
||||
addingListenersToCards();
|
||||
log.debug("UpdateMapService started.");
|
||||
}
|
||||
|
||||
protected abstract void addingListenersToCards();
|
||||
|
||||
@Override
|
||||
public void entryAdded(EntryEvent<Long, Object> event) {
|
||||
entryModified(event, EVENT_CREATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void entryUpdated(EntryEvent<Long, Object> event) {
|
||||
entryModified(event, EVENT_UPDATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void entryRemoved(EntryEvent<Long, Object> event) {
|
||||
entryModified(event, EVENT_DELETE);
|
||||
}
|
||||
|
||||
protected abstract void entryModified(EntryEvent<Long, Object> event, String eventType);
|
||||
|
||||
protected void createBusinessEvent(BusinessEvent businessEvent, String eventType) {
|
||||
businessEvent.setId(hazelcastServerInstance.getIdGenerator(IMDGDistributedNames.MAP_SEQUENCE_NAME).newId());
|
||||
businessEvent.setEventTime(Instant.now());
|
||||
businessEvent.setUserId(0L); // todo откуда брать пользователя, причину изменений?
|
||||
log.debug("business event created {} {}", businessEvent.getClass().getName(), businessEvent);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package ru.spcex.clearing.storage.services;
|
||||
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.clearing.classes.ConstSerializable;
|
||||
import ru.clearing.platform.dictionary.ConstDictionarySerializable;
|
||||
|
||||
@Service
|
||||
public class HazelcastLifecycleSupport extends AbstractHazelcastLifecycleSupport {
|
||||
/**
|
||||
* Рабочая версия БД. Треьуется вручную сверять с DDL.sql и накручивать эту переменную.
|
||||
*/
|
||||
public static final String CHECK_DB_VERSION = "2.33";
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Autowired
|
||||
public HazelcastLifecycleSupport(HazelcastInstance hazelcastServerInstance, JdbcTemplate jdbcTemplate) {
|
||||
super(hazelcastServerInstance, jdbcTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCheckDbVersion() {
|
||||
return CHECK_DB_VERSION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class[] getSerialVersionUIDClasses() {
|
||||
return new Class[]{
|
||||
ConstSerializable.class, ConstDictionarySerializable.class
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package ru.spcex.clearing.storage.services;
|
||||
|
||||
import com.hazelcast.core.EntryEvent;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.query.Predicates;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.clearing.classes.StaticData.Company.Company;
|
||||
import ru.clearing.classes.StaticData.Company.CompanyUpdate;
|
||||
import ru.spcex.clearing.storage.utils.IMDGDistributedNames;
|
||||
|
||||
@Service
|
||||
public class UpdateMapService extends AbstractUpdateMapService {
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Autowired
|
||||
public UpdateMapService(HazelcastInstance hazelcastServerInstance, HazelcastLifecycleSupport lifecycleSupport) {
|
||||
super(hazelcastServerInstance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addingListenersToCards() {
|
||||
hazelcastServerInstance.getMap(IMDGDistributedNames.Map_Company).addLocalEntryListener(this, Predicates.alwaysTrue(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void entryModified(EntryEvent<Long, Object> event, String eventType) {
|
||||
log.debug("{} {}", event, eventType);
|
||||
Object value = (EVENT_DELETE.equals(eventType) ? event.getOldValue() : event.getValue());
|
||||
if (value instanceof Company) {
|
||||
CompanyUpdate companyUpdate = new CompanyUpdate();
|
||||
createBusinessEvent(companyUpdate, eventType);
|
||||
companyUpdate.setObject((Company) value);
|
||||
hazelcastServerInstance.getMap(IMDGDistributedNames.Map_CompanyUpdate).put(companyUpdate.getId(), companyUpdate);
|
||||
} else {
|
||||
log.error("unexpected event {}", event);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue