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>(); 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
} }
} }
} }
} }
} }
/** /**

View File

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