IDEMPIERE-4924 Performance issue with indirect context (#863)
* IDEMPIERE-4924 Performance issue with indirect context - added cache * IDEMPIERE-4924 Performance issue with indirect context
This commit is contained in:
parent
21c07785e8
commit
eedc3c6e35
|
@ -0,0 +1,47 @@
|
||||||
|
/***********************************************************************
|
||||||
|
* This file is part of iDempiere ERP Open Source *
|
||||||
|
* http://www.idempiere.org *
|
||||||
|
* *
|
||||||
|
* Copyright (C) Contributors *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or *
|
||||||
|
* modify it under the terms of the GNU General Public License *
|
||||||
|
* as published by the Free Software Foundation; either version 2 *
|
||||||
|
* of the License, or (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
|
||||||
|
* MA 02110-1301, USA. *
|
||||||
|
* *
|
||||||
|
* Contributors: *
|
||||||
|
* - hengsin *
|
||||||
|
**********************************************************************/
|
||||||
|
package org.compiere.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener for cache reset event.
|
||||||
|
* Note that this is ignore by CacheMgt if CCache implementation that implement this interface
|
||||||
|
* doesn't return null for getTableName().
|
||||||
|
* @author hengsin
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface CacheChangeListener {
|
||||||
|
/**
|
||||||
|
* Reset Cache
|
||||||
|
* @param tableName
|
||||||
|
*/
|
||||||
|
public void reset(String tableName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset Cache by record id
|
||||||
|
* @param tableName
|
||||||
|
* @param recordId
|
||||||
|
*/
|
||||||
|
public void reset(String tableName, int recordId);
|
||||||
|
}
|
|
@ -66,6 +66,8 @@ public class CacheMgt
|
||||||
private ArrayList<String> m_tableNames = new ArrayList<String>();
|
private ArrayList<String> m_tableNames = new ArrayList<String>();
|
||||||
/** Logger */
|
/** Logger */
|
||||||
private static CLogger log = CLogger.getCLogger(CacheMgt.class);
|
private static CLogger log = CLogger.getCLogger(CacheMgt.class);
|
||||||
|
/** Cache change listeners **/
|
||||||
|
private List<CacheChangeListener> m_listeners = new ArrayList<CacheChangeListener>();
|
||||||
|
|
||||||
public static int MAX_SIZE = 1000;
|
public static int MAX_SIZE = 1000;
|
||||||
static
|
static
|
||||||
|
@ -103,6 +105,12 @@ public class CacheMgt
|
||||||
m_tableNames.add(tableName);
|
m_tableNames.add(tableName);
|
||||||
|
|
||||||
m_instances.add (instance);
|
m_instances.add (instance);
|
||||||
|
|
||||||
|
if (tableName == null && instance instanceof CacheChangeListener)
|
||||||
|
{
|
||||||
|
m_listeners.add((CacheChangeListener) instance);
|
||||||
|
}
|
||||||
|
|
||||||
Map<K, V> map = null;
|
Map<K, V> map = null;
|
||||||
if (distributed)
|
if (distributed)
|
||||||
{
|
{
|
||||||
|
@ -305,6 +313,15 @@ public class CacheMgt
|
||||||
}
|
}
|
||||||
if (log.isLoggable(Level.FINE)) log.fine(tableName + ": #" + counter + " (" + total + ")");
|
if (log.isLoggable(Level.FINE)) log.fine(tableName + ": #" + counter + " (" + total + ")");
|
||||||
|
|
||||||
|
CacheChangeListener[] listeners = m_listeners.toArray(new CacheChangeListener[0]);
|
||||||
|
for(CacheChangeListener listener : listeners)
|
||||||
|
{
|
||||||
|
if (Record_ID == -1)
|
||||||
|
listener.reset(tableName);
|
||||||
|
else
|
||||||
|
listener.reset(tableName, Record_ID);
|
||||||
|
}
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,7 +352,7 @@ public class CacheMgt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -24,11 +24,14 @@
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
package org.compiere.util;
|
package org.compiere.util;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.compiere.model.GridTab;
|
import org.compiere.model.GridTab;
|
||||||
import org.compiere.model.MColumn;
|
import org.compiere.model.MColumn;
|
||||||
import org.compiere.model.MTable;
|
import org.compiere.model.MTable;
|
||||||
|
import org.compiere.model.PO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author hengsin
|
* @author hengsin
|
||||||
|
@ -40,6 +43,8 @@ public class DefaultEvaluatee implements Evaluatee {
|
||||||
private int m_WindowNo;
|
private int m_WindowNo;
|
||||||
private int m_TabNo;
|
private int m_TabNo;
|
||||||
|
|
||||||
|
private static final ReferenceCache s_ReferenceCache = new ReferenceCache("DefaultEvaluatee_ReferenceCache", 100, 1, 2000);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param gridTab
|
* @param gridTab
|
||||||
|
@ -106,23 +111,68 @@ public class DefaultEvaluatee implements Evaluatee {
|
||||||
}
|
}
|
||||||
if (column != null) {
|
if (column != null) {
|
||||||
String foreignTable = column.getReferenceTableName();
|
String foreignTable = column.getReferenceTableName();
|
||||||
refValue = DB.getSQLValueString(null,
|
MTable table = MTable.get(Env.getCtx(), foreignTable);
|
||||||
"SELECT " + foreignColumn + " FROM " + foreignTable + " WHERE "
|
if (table != null) {
|
||||||
+ foreignTable + "_ID = ?", id);
|
return getColumnValue(table, foreignTable, foreignColumn, id, refValue);
|
||||||
return refValue;
|
}
|
||||||
} else {
|
} else {
|
||||||
// no MColumn found, try tableName from columnName
|
// no MColumn found, try tableName from columnName
|
||||||
String foreignTable = variableName.substring(0, variableName.length()-3);
|
String foreignTable = variableName.substring(0, variableName.length()-3);
|
||||||
MTable table = MTable.get(ctx, foreignTable);
|
MTable table = MTable.get(ctx, foreignTable);
|
||||||
if (table != null) {
|
if (table != null) {
|
||||||
refValue = DB.getSQLValueString(null,
|
return getColumnValue(table, foreignTable, foreignColumn, id, refValue);
|
||||||
"SELECT " + foreignColumn + " FROM " + foreignTable + " WHERE "
|
|
||||||
+ foreignTable + "_ID = ?", id);
|
|
||||||
return refValue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getColumnValue(MTable table, String foreignTable, String foreignColumn, int id, String refValue) {
|
||||||
|
String key = foreignTable+"|"+id;
|
||||||
|
PO po = null;
|
||||||
|
if (s_ReferenceCache.containsKey(key))
|
||||||
|
{
|
||||||
|
po = s_ReferenceCache.get(key);
|
||||||
|
if (po != null && po.get_ID() == id)
|
||||||
|
refValue = po.get_ValueAsString(foreignColumn);
|
||||||
|
else
|
||||||
|
po = null;
|
||||||
|
}
|
||||||
|
if (po == null)
|
||||||
|
{
|
||||||
|
po = table.getPO(id, null);
|
||||||
|
if (po != null && po.get_ID() == id)
|
||||||
|
{
|
||||||
|
s_ReferenceCache.put(key, po);
|
||||||
|
refValue = po.get_ValueAsString(foreignColumn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return refValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class ReferenceCache extends CCache<String, PO> implements CacheChangeListener {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 6884795644185015913L;
|
||||||
|
|
||||||
|
private ReferenceCache(String name, int initialCapacity, int expireMinutes, int maxSize) {
|
||||||
|
super(null, name, initialCapacity, expireMinutes, false, maxSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset(String tableName) {
|
||||||
|
String filter = tableName + "|";
|
||||||
|
List<String> keys = keySet().stream().filter(e -> e.startsWith(filter)).collect(Collectors.toList());
|
||||||
|
if (!keys.isEmpty()) {
|
||||||
|
for(String key : keys)
|
||||||
|
remove(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset(String tableName, int recordId) {
|
||||||
|
String key = tableName + "|" + recordId;
|
||||||
|
remove(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue