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:
hengsin 2021-09-14 20:32:20 +08:00 committed by GitHub
parent 21c07785e8
commit eedc3c6e35
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 123 additions and 9 deletions

View File

@ -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);
}

View File

@ -66,6 +66,8 @@ public class CacheMgt
private ArrayList<String> m_tableNames = new ArrayList<String>();
/** Logger */
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;
static
@ -103,6 +105,12 @@ public class CacheMgt
m_tableNames.add(tableName);
m_instances.add (instance);
if (tableName == null && instance instanceof CacheChangeListener)
{
m_listeners.add((CacheChangeListener) instance);
}
Map<K, V> map = null;
if (distributed)
{
@ -305,6 +313,15 @@ public class CacheMgt
}
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;
}
@ -335,7 +352,7 @@ public class CacheMgt
}
}
}
}
}
}
/**

View File

@ -24,11 +24,14 @@
**********************************************************************/
package org.compiere.util;
import java.util.List;
import java.util.Properties;
import java.util.stream.Collectors;
import org.compiere.model.GridTab;
import org.compiere.model.MColumn;
import org.compiere.model.MTable;
import org.compiere.model.PO;
/**
* @author hengsin
@ -40,6 +43,8 @@ public class DefaultEvaluatee implements Evaluatee {
private int m_WindowNo;
private int m_TabNo;
private static final ReferenceCache s_ReferenceCache = new ReferenceCache("DefaultEvaluatee_ReferenceCache", 100, 1, 2000);
/**
*
* @param gridTab
@ -106,23 +111,68 @@ public class DefaultEvaluatee implements Evaluatee {
}
if (column != null) {
String foreignTable = column.getReferenceTableName();
refValue = DB.getSQLValueString(null,
"SELECT " + foreignColumn + " FROM " + foreignTable + " WHERE "
+ foreignTable + "_ID = ?", id);
return refValue;
MTable table = MTable.get(Env.getCtx(), foreignTable);
if (table != null) {
return getColumnValue(table, foreignTable, foreignColumn, id, refValue);
}
} else {
// no MColumn found, try tableName from columnName
String foreignTable = variableName.substring(0, variableName.length()-3);
MTable table = MTable.get(ctx, foreignTable);
if (table != null) {
refValue = DB.getSQLValueString(null,
"SELECT " + foreignColumn + " FROM " + foreignTable + " WHERE "
+ foreignTable + "_ID = ?", id);
return refValue;
return getColumnValue(table, foreignTable, foreignColumn, id, refValue);
}
}
}
}
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);
}
}
}