/* *************************************************************************************** * Copyright (C) 2006 EsperTech, Inc. All rights reserved. * * http://www.espertech.com/esper * * http://www.espertech.com * * ---------------------------------------------------------------------------------- * * The software in this package is published under the terms of the GPL license * * a copy of which has been included with this distribution in the license.txt file. * *************************************************************************************** */ package com.espertech.esper.epl.table.mgmt; import com.espertech.esper.client.EventBean; import com.espertech.esper.client.EventType; import com.espertech.esper.collection.Pair; import com.espertech.esper.core.service.StatementContext; import com.espertech.esper.core.service.resource.StatementResourceHolder; import com.espertech.esper.core.service.resource.StatementResourceService; import com.espertech.esper.epl.agg.service.AggregationServiceTable; import com.espertech.esper.epl.expression.core.ExprEvaluatorContext; import com.espertech.esper.epl.expression.core.ExprValidationException; import com.espertech.esper.epl.join.plan.QueryPlanIndexItem; import com.espertech.esper.epl.lookup.EventTableIndexMetadata; import com.espertech.esper.epl.lookup.IndexMultiKey; import com.espertech.esper.epl.table.upd.TableUpdateStrategy; import com.espertech.esper.epl.table.upd.TableUpdateStrategyFactory; import com.espertech.esper.epl.table.upd.TableUpdateStrategyReceiver; import com.espertech.esper.epl.updatehelper.EventBeanUpdateHelper; import com.espertech.esper.event.arr.ObjectArrayEventType; import java.util.*; public class TableMetadata { private final String tableName; private final String eplExpression; private final String statementName; private final Class[] keyTypes; private final Map<String, TableMetadataColumn> tableColumns; private final TableStateRowFactory rowFactory; private final int numberMethodAggregations; private final StatementContext statementContextCreateTable; private final ObjectArrayEventType internalEventType; private final ObjectArrayEventType publicEventType; private final TableMetadataInternalEventToPublic eventToPublic; private final boolean queryPlanLogging; private final Map<String, List<TableUpdateStrategyReceiverDesc>> stmtNameToUpdateStrategyReceivers = new HashMap<String, List<TableUpdateStrategyReceiverDesc>>(); private final EventTableIndexMetadata eventTableIndexMetadataRepo = new EventTableIndexMetadata(); private TableStateFactory tableStateFactory; private TableMetadataContext tableMetadataContext; private TableRowKeyFactory tableRowKeyFactory; public TableMetadata(String tableName, String eplExpression, String statementName, Class[] keyTypes, Map<String, TableMetadataColumn> tableColumns, TableStateRowFactory rowFactory, int numberMethodAggregations, StatementContext createTableStatementContext, ObjectArrayEventType internalEventType, ObjectArrayEventType publicEventType, TableMetadataInternalEventToPublic eventToPublic, boolean queryPlanLogging) throws ExprValidationException { this.tableName = tableName; this.eplExpression = eplExpression; this.statementName = statementName; this.keyTypes = keyTypes; this.tableColumns = tableColumns; this.rowFactory = rowFactory; this.numberMethodAggregations = numberMethodAggregations; this.statementContextCreateTable = createTableStatementContext; this.internalEventType = internalEventType; this.publicEventType = publicEventType; this.eventToPublic = eventToPublic; this.queryPlanLogging = queryPlanLogging; if (keyTypes.length > 0) { Pair<int[], IndexMultiKey> pair = TableServiceUtil.getIndexMultikeyForKeys(tableColumns, internalEventType); QueryPlanIndexItem queryPlanIndexItem = QueryPlanIndexItem.fromIndexMultikeyTablePrimaryKey(pair.getSecond()); eventTableIndexMetadataRepo.addIndexExplicit(true, pair.getSecond(), tableName, queryPlanIndexItem, createTableStatementContext.getStatementName()); tableRowKeyFactory = new TableRowKeyFactory(pair.getFirst()); } } public Class[] getKeyTypes() { return keyTypes; } public TableStateFactory getTableStateFactory() { return tableStateFactory; } public Map<String, TableMetadataColumn> getTableColumns() { return tableColumns; } public TableStateRowFactory getRowFactory() { return rowFactory; } public int getNumberMethodAggregations() { return numberMethodAggregations; } public String getContextName() { return statementContextCreateTable.getContextName(); } public ObjectArrayEventType getInternalEventType() { return internalEventType; } public boolean isQueryPlanLogging() { return queryPlanLogging; } public Set<String> getUniqueKeyProps() { Set<String> keys = new LinkedHashSet<String>(); for (Map.Entry<String, TableMetadataColumn> entry : tableColumns.entrySet()) { if (entry.getValue().isKey()) { keys.add(entry.getKey()); } } return keys; } public void setTableStateFactory(TableStateFactory tableStateFactory) { this.tableStateFactory = tableStateFactory; } public String getTableName() { return tableName; } public EventTableIndexMetadata getEventTableIndexMetadataRepo() { return eventTableIndexMetadataRepo; } public EventBean getPublicEventBean(EventBean event, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context) { return eventToPublic.convert(event, eventsPerStream, isNewData, context); } public EventType getPublicEventType() { return publicEventType; } public TableMetadataInternalEventToPublic getEventToPublic() { return eventToPublic; } public void validateAddIndexAssignUpdateStrategies(String createIndexStatementName, IndexMultiKey imk, String explicitIndexName, QueryPlanIndexItem explicitIndexDesc) throws ExprValidationException { // add index - for now eventTableIndexMetadataRepo.addIndexExplicit(false, imk, explicitIndexName, explicitIndexDesc, createIndexStatementName); // validate strategies, rollback if required for (Map.Entry<String, List<TableUpdateStrategyReceiverDesc>> stmtEntry : stmtNameToUpdateStrategyReceivers.entrySet()) { for (TableUpdateStrategyReceiverDesc strategyReceiver : stmtEntry.getValue()) { try { TableUpdateStrategyFactory.validateGetTableUpdateStrategy(this, strategyReceiver.getUpdateHelper(), strategyReceiver.isOnMerge()); } catch (ExprValidationException ex) { eventTableIndexMetadataRepo.removeIndex(imk); throw new ExprValidationException("Failed to validate statement '" + stmtEntry.getKey() + "' as a recipient of the proposed index: " + ex.getMessage()); } } } // assign new strategies for (Map.Entry<String, List<TableUpdateStrategyReceiverDesc>> stmtEntry : stmtNameToUpdateStrategyReceivers.entrySet()) { for (TableUpdateStrategyReceiverDesc strategyReceiver : stmtEntry.getValue()) { TableUpdateStrategy strategy = TableUpdateStrategyFactory.validateGetTableUpdateStrategy(this, strategyReceiver.getUpdateHelper(), strategyReceiver.isOnMerge()); strategyReceiver.getReceiver().update(strategy); } } } public void addTableUpdateStrategyReceiver(String statementName, TableUpdateStrategyReceiver receiver, EventBeanUpdateHelper updateHelper, boolean onMerge) { List<TableUpdateStrategyReceiverDesc> receivers = stmtNameToUpdateStrategyReceivers.get(statementName); if (receivers == null) { receivers = new ArrayList<TableUpdateStrategyReceiverDesc>(2); stmtNameToUpdateStrategyReceivers.put(statementName, receivers); } receivers.add(new TableUpdateStrategyReceiverDesc(receiver, updateHelper, onMerge)); } public void removeTableUpdateStrategyReceivers(String statementName) { stmtNameToUpdateStrategyReceivers.remove(statementName); } public void addIndexReference(String indexName, String statementName) { eventTableIndexMetadataRepo.addIndexReference(indexName, statementName); } public void removeIndexReferencesStatement(String statementName) { Collection<String> indexesDereferenced = eventTableIndexMetadataRepo.getRemoveRefIndexesDereferenced(statementName); for (String indexDereferenced : indexesDereferenced) { // remove tables for (int agentInstanceId : getAgentInstanceIds()) { TableStateInstance state = getState(agentInstanceId); if (state != null) { IndexMultiKey mk = state.getIndexRepository().getIndexByName(indexDereferenced); if (mk != null) { state.getIndexRepository().removeIndex(mk); } } } } } public TableStateInstance getState(int agentInstanceId) { StatementResourceService createTableResources = statementContextCreateTable.getStatementExtensionServicesContext().getStmtResources(); StatementResourceHolder holder = null; if (statementContextCreateTable.getContextName() == null) { holder = createTableResources.getResourcesUnpartitioned(); } else { if (createTableResources.getResourcesPartitioned() != null) { holder = createTableResources.getResourcesPartitioned().get(agentInstanceId); } } if (holder == null) { return null; } AggregationServiceTable aggsvc = (AggregationServiceTable) holder.getAggregationService(); return aggsvc.getTableState(); } public Collection<Integer> getAgentInstanceIds() { StatementResourceService createTableResources = statementContextCreateTable.getStatementExtensionServicesContext().getStmtResources(); if (statementContextCreateTable.getContextName() == null) { return Collections.singleton(-1); } if (createTableResources.getResourcesPartitioned() != null) { return createTableResources.getResourcesPartitioned().keySet(); } return Collections.singleton(-1); } public String[][] getUniqueIndexes() { return eventTableIndexMetadataRepo.getUniqueIndexProps(); } public void setTableMetadataContext(TableMetadataContext tableMetadataContext) { this.tableMetadataContext = tableMetadataContext; } public TableMetadataContext getTableMetadataContext() { return tableMetadataContext; } public TableRowKeyFactory getTableRowKeyFactory() { return tableRowKeyFactory; } public void clearTableInstances() { for (int agentInstanceId : getAgentInstanceIds()) { TableStateInstance state = getState(agentInstanceId); if (state != null) { state.destroyInstance(); } } } public String getEplExpression() { return eplExpression; } public String getStatementName() { return statementName; } public StatementContext getStatementContextCreateTable() { return statementContextCreateTable; } }