=== modified file 'src/com/goldencode/p2j/persist/BufferManager.java'
--- old/src/com/goldencode/p2j/persist/BufferManager.java	2023-05-12 10:05:12 +0000
+++ new/src/com/goldencode/p2j/persist/BufferManager.java	2023-06-07 12:49:05 +0000
@@ -487,6 +487,7 @@
 **     HC  20230118          Eliminated some of the uses of String.toUpperCase and/or
 **                           String.toLowerCase for performance.
 ** 111 GBB 20230512          Logging methods replaced by CentralLogger/ConversionStatus.
+** 112 DDF 20230607          Made the size of the convertedNames LRUCache configurable.
 */
 
 /*
@@ -552,6 +553,7 @@
 
 import com.goldencode.cache.*;
 import com.goldencode.p2j.convert.*;
+import com.goldencode.p2j.directory.DirectoryService;
 import com.goldencode.p2j.oo.lang.*;
 import com.goldencode.p2j.persist.dirty.*;
 import com.goldencode.p2j.persist.id.*;
@@ -601,6 +603,9 @@
    /** Logger */
    private static final CentralLogger LOG = CentralLogger.get(BufferManager.class.getName());
    
+   /** Cache size of the LRUCache containing converted buffer names. */
+   private static final int CONVERTED_NAMES_CACHE_SIZE;
+   
    /** Stores context local instances of this class */
    private static final ContextLocal<BufferManager> context = new ContextLocal<BufferManager>()
    {
@@ -718,10 +723,34 @@
    private NameConverter nc = new NameConverter();
    
    /** Buffer names already converted. */
-   private LRUCache<String, String> convertedNames = new LRUCache<>(10000);
+   private LRUCache<String, String> convertedNames = new LRUCache<>(CONVERTED_NAMES_CACHE_SIZE);
 
    /** Track the external scopes pushed on {@link BufferManager}. */
    private final Stack<Boolean> externalScope = new Stack<>();
+   
+   /**
+    * Read the configurable value for the converted names LRUCache size.
+    */
+   static
+   {      
+      int convertedNamesCacheSize = 10000;
+      DirectoryService ds = DirectoryService.getInstance();
+      if (!ds.bind())
+      {
+         throw new RuntimeException("Directory bind failed");
+      }
+      
+      try
+      {
+         String path = "persistence/cache-size/buffer-manager";
+         convertedNamesCacheSize = Utils.getDirectoryNodeInt(ds, path, 10000, false);
+      }
+      finally
+      {
+         ds.unbind();
+         CONVERTED_NAMES_CACHE_SIZE = convertedNamesCacheSize;
+      }
+   }
 
    /**
     * Constructor; instances of this class are context-local and must be accessed using the static

=== modified file 'src/com/goldencode/p2j/persist/DynamicTablesHelper.java'
--- old/src/com/goldencode/p2j/persist/DynamicTablesHelper.java	2023-05-12 10:05:12 +0000
+++ new/src/com/goldencode/p2j/persist/DynamicTablesHelper.java	2023-06-07 12:51:33 +0000
@@ -89,6 +89,7 @@
 ** 032 CA  20230215 Improved other cases to reduce BDT usage from within FWD runtime.
 ** 033 IAS 20230427 Added 'legacyName' to the 'indexAst'.
 ** 034 GBB 20230512 Logging methods replaced by CentralLogger/ConversionStatus.
+** 035 DDF 20230607 Made the size of the DMO resources cache configurable.
 */
 
 /*
@@ -151,6 +152,7 @@
 import com.goldencode.ast.*;
 import com.goldencode.cache.*;
 import com.goldencode.p2j.convert.*;
+import com.goldencode.p2j.directory.DirectoryService;
 import com.goldencode.p2j.pattern.*;
 import com.goldencode.p2j.persist.orm.*;
 import com.goldencode.p2j.schema.*;
@@ -158,6 +160,7 @@
 import com.goldencode.p2j.uast.*;
 import com.goldencode.p2j.util.*;
 import com.goldencode.p2j.util.ErrorManager;
+import com.goldencode.p2j.util.Utils;
 import com.goldencode.p2j.util.logging.*;
 
 import java.util.*;
@@ -180,6 +183,9 @@
    
    /** Logger. */
    private static final CentralLogger LOG = CentralLogger.get(DynamicTablesHelper.class.getName());
+
+   /** Cache size of the dynamically converted and compiled DMO resources map */
+   private static final int CACHE_SIZE;
    
    /** Singleton instance. */
    private static volatile DynamicTablesHelper instance;
@@ -187,8 +193,8 @@
    /** In-memory class loader */
    private static AsmClassLoader systemInMemoryClassLoader;
    
-   /** Cache for dynamically converted and compiled DMO resources */ // TODO: make configurable
-   private final Map<CacheKey, CacheData> cache = new HashMap<>(8192);
+   /** Cache for dynamically converted and compiled DMO resources */
+   private final Map<CacheKey, CacheData> cache = new HashMap<>(CACHE_SIZE);
    
    /** Lock object on which to synchronize cache operations */
    private final Object cacheLock = new Object();
@@ -232,6 +238,25 @@
          throw new IllegalStateException("It is expected to have InMemoryClassLoader " +
                                          "in the chain of system class loaders.");
       }
+      
+      // Read the configurable value for the cache size.
+      int cacheSize = 8192;
+      DirectoryService ds = DirectoryService.getInstance();
+      if (!ds.bind())
+      {
+         throw new RuntimeException("Directory bind failed");
+      }
+      
+      try
+      {
+         String path = "persistence/cache-size/dynamic-tables";
+         cacheSize = Utils.getDirectoryNodeInt(ds, path, 8192, false);
+      }
+      finally
+      {
+         ds.unbind();
+         CACHE_SIZE = cacheSize;
+      }
    }
    
    /**

=== modified file 'src/com/goldencode/p2j/persist/FQLHelperCache.java'
--- old/src/com/goldencode/p2j/persist/FQLHelperCache.java	2022-11-03 00:24:27 +0000
+++ new/src/com/goldencode/p2j/persist/FQLHelperCache.java	2023-06-07 12:52:38 +0000
@@ -25,6 +25,7 @@
 ** 012 ECF 20200906          New ORM implementation.
 ** 013 CA  20200930          Cache the hash code value.
 **     OM  20221103          Renamed class to FQLHelperCache.
+** 015 DDF 20230507          Made the size of the LRUCache configurable.
 */
 
 /*
@@ -83,6 +84,8 @@
 package com.goldencode.p2j.persist;
 
 import com.goldencode.cache.*;
+import com.goldencode.p2j.directory.DirectoryService;
+import com.goldencode.p2j.util.Utils;
 
 /**
  * A cache of {@link FQLHelper} objects mapped to a complex key which encompasses the DMO
@@ -94,8 +97,35 @@
  */
 final class FQLHelperCache
 {
+   /** Cache size of the LRUCache for FQL helper objects */
+   private static final int LRUCACHE_SIZE;
+   
    /** LFU cache of FQL helper objects, which also ages its entries */
-   private final Cache<Key, FQLHelper> cache = new LRUCache<>(8192);
+   private final Cache<Key, FQLHelper> cache = new LRUCache<>(LRUCACHE_SIZE);
+   
+   /**
+    * Read the configurable value for the LRUCache size.
+    */
+   static
+   {      
+      int lruCacheSize = 8192;
+      DirectoryService ds = DirectoryService.getInstance();
+      if (!ds.bind())
+      {
+         throw new RuntimeException("Directory bind failed");
+      }
+      
+      try
+      {
+         String path = "persistence/cache-size/fql-helper-cache";
+         lruCacheSize = Utils.getDirectoryNodeInt(ds, path, 8192, false);
+      }
+      finally
+      {
+         ds.unbind();
+         LRUCACHE_SIZE = lruCacheSize;
+      }
+   }
    
    /**
     * Default constructor.

=== modified file 'src/com/goldencode/p2j/persist/FQLPreprocessor.java'
--- old/src/com/goldencode/p2j/persist/FQLPreprocessor.java	2023-05-12 10:05:12 +0000
+++ new/src/com/goldencode/p2j/persist/FQLPreprocessor.java	2023-06-07 12:53:55 +0000
@@ -292,6 +292,7 @@
 ** 092 DDF 20230411          Added back the simplifyProperties guard.
 ** 093 DDF 20230426          Use exists(select 1 from <table>) instead of exists(from <table>).
 ** 094 GBB 20230512          Logging methods replaced by CentralLogger/ConversionStatus.
+** 095 DDF 20230607          Made the size of prepared instances cache configurable.
 */
 
 /*
@@ -360,6 +361,7 @@
 import antlr.collections.*;
 import com.goldencode.ast.*;
 import com.goldencode.util.*;
+import com.goldencode.p2j.directory.DirectoryService;
 import com.goldencode.p2j.persist.dialect.*;
 import com.goldencode.p2j.persist.hql.*;
 import com.goldencode.p2j.persist.pl.*;
@@ -498,7 +500,7 @@
    private static final FQLPreprocessor NOP_INSTANCE;
    
    /** Cache of prepared instances, indexed by Persistence and where clause */
-   private static final Map<CacheKey, FQLPreprocessor> cache = new HashMap<>(2048);
+   private static final Map<CacheKey, FQLPreprocessor> cache;
    
    /** Map of FQL function keys to overloaded SQL (unique) function names */
    private static final Map<FunctionKey, String> overloadedFunctions = new HashMap<>(256);
@@ -567,6 +569,25 @@
                      HQLAst lp6 = createAstNode(LPARENS, "(", op2);
                      HQLAst lp7 = createAstNode(LPARENS, "(", op2);
       }
+      
+      // Read the configurable value for the prepared instances cache size and initialize the cache.
+      int cacheSize = 2048;
+      DirectoryService ds = DirectoryService.getInstance();
+      if (!ds.bind())
+      {
+         throw new RuntimeException("Directory bind failed");
+      }
+      
+      try
+      {
+         String path = "persistence/cache-size/fql-preprocessor";
+         cacheSize = Utils.getDirectoryNodeInt(ds, path, 2048, false);
+      }
+      finally
+      {
+         ds.unbind();
+         cache = new HashMap<>(cacheSize);
+      }
    }
    
    /** Database associated with this object */

=== modified file 'src/com/goldencode/p2j/persist/FastFindCache.java'
--- old/src/com/goldencode/p2j/persist/FastFindCache.java	2023-02-27 14:22:01 +0000
+++ new/src/com/goldencode/p2j/persist/FastFindCache.java	2023-06-07 12:54:40 +0000
@@ -15,6 +15,7 @@
 **     CA  20220104 Node.l3Cache must be a weak reference, otherwise once the direct cache invalidates a key,
 **                  the reverse lookup has no chance of being cleaned up, as this is not done explicitly.
 **     CA  20221109 Partial/Incomplete records (loaded with EXCEPT/FIELDS options) can't be cached.
+** 003 DDF 20230607 Made the size of the L2 and L3 caches configurable.
 */
 
 /*
@@ -73,6 +74,7 @@
 package com.goldencode.p2j.persist;
 
 import com.goldencode.cache.*;
+import com.goldencode.p2j.directory.DirectoryService;
 import com.goldencode.p2j.persist.orm.*;
 import com.goldencode.p2j.security.*;
 import com.goldencode.p2j.util.*;
@@ -125,6 +127,12 @@
       }
    };
    
+   /** Cache size for l2Cache */
+   private static final int L2CACHE_SIZE;
+   
+   /** Cache size for l3Cache */
+   private static final int L3CACHE_SIZE;
+   
    /** The internal data, as a triple-level cache: table-uid x index x other-information. */
    private final Map<Long, Map<Integer, Cache<L2Key, RecordIdentifier<String>>>> cache = new HashMap<>();
    
@@ -132,6 +140,34 @@
    private final ReverseLookup reverseLookup = new ReverseLookup();
    
    /**
+    * Read the configurable value for the L2 and L3 cache size.
+    */
+   static
+   {      
+      int l2CacheSize = 10;
+      int l3CacheSize = 100;
+      DirectoryService ds = DirectoryService.getInstance();
+      if (!ds.bind())
+      {
+         throw new RuntimeException("Directory bind failed");
+      }
+      
+      try
+      {
+         String l2Path = "persistence/cache-size/fast-find/l2";
+         l2CacheSize = Utils.getDirectoryNodeInt(ds, l2Path, 10, false);
+         String l3Path = "persistence/cache-size/fast-find/l3";
+         l3CacheSize = Utils.getDirectoryNodeInt(ds, l3Path, 10, false);
+      }
+      finally
+      {
+         ds.unbind();
+         L2CACHE_SIZE = l2CacheSize;
+         L3CACHE_SIZE = l3CacheSize;
+      }
+   }
+   
+   /**
     * Obtain the singleton instance, if FastFind mode enabled. 
     * Return {@code null} to disable FastFind mode.
     * 
@@ -274,10 +310,10 @@
       synchronize(() ->
       {
          Map<Integer, Cache<L2Key, RecordIdentifier<String>>> l2Cache =
-            cache.computeIfAbsent(k.tableId, x -> new HashMap<>(10));
+            cache.computeIfAbsent(k.tableId, x -> new HashMap<>(L2CACHE_SIZE));
          
          Cache<L2Key, RecordIdentifier<String>> l3Cache =
-            l2Cache.computeIfAbsent(k.indexId, x -> new LRUCache<>(100));
+            l2Cache.computeIfAbsent(k.indexId, x -> new LRUCache<>(L3CACHE_SIZE));
          
          // for a positive result (i.e., a record was found), ensure we use the canonical instance of the
          // record identifier, so that if it is stored in the reverse lookup cache, the weak keys can be

=== modified file 'src/com/goldencode/p2j/persist/Persistence.java'
--- old/src/com/goldencode/p2j/persist/Persistence.java	2023-05-23 09:43:33 +0000
+++ new/src/com/goldencode/p2j/persist/Persistence.java	2023-06-07 12:55:36 +0000
@@ -593,6 +593,7 @@
 ** 176 IAS 20230410          Added 'old' methods w/o DataRelation argument.
 ** 177 GBB 20230512          Logging methods replaced by CentralLogger/ConversionStatus.
 ** 178 RAA 20230518          Replaced lambdas with method referencing when using SQLStatementLogger.
+** 179 DDF 20230607          Made the size of the Context.staticQueryCache configurable.
 */
 
 /*
@@ -657,6 +658,7 @@
 import java.util.function.*;
 import java.util.logging.*;
 import com.goldencode.cache.*;
+import com.goldencode.p2j.directory.DirectoryService;
 import com.goldencode.p2j.main.*;
 import com.goldencode.p2j.persist.deploy.*;
 import com.goldencode.p2j.persist.dialect.*;
@@ -712,6 +714,9 @@
    /** Logger */
    private static final CentralLogger LOG = CentralLogger.get(Persistence.class.getName());
    
+   /** Cache size for Context.staticQueryCache */
+   private static final int STATIC_QUERY_CACHE_SIZE;
+   
    /** Default lock manager implementation */
    private static final String DEFAULT_LOCK_MANAGER =
       "com.goldencode.p2j.persist.lock.InMemoryLockManager";
@@ -773,6 +778,30 @@
    private IdentityManager identityManager;
    
    /**
+    * Read the configurable value for the static query cache size.
+    */
+   static
+   {      
+      int staticQueryCacheSize = 1000;
+      DirectoryService ds = DirectoryService.getInstance();
+      if (!ds.bind())
+      {
+         throw new RuntimeException("Directory bind failed");
+      }
+      
+      try
+      {
+         String path = "persistence/cache-size/persistence";
+         staticQueryCacheSize = Utils.getDirectoryNodeInt(ds, path, 8192, false);
+      }
+      finally
+      {
+         ds.unbind();
+         STATIC_QUERY_CACHE_SIZE = staticQueryCacheSize;
+      }
+   }
+   
+   /**
     * Construct an instance for a particular, physical database, storing the dialect which is used to create
     * a portability layer.
     *
@@ -4525,7 +4554,7 @@
    class Context
    {
       /** Cache of FQL strings, with or without max results and start offsets, to queries. */
-      private final ExpiryCache<QueryKey, Query> staticQueryCache = new LRUCache<>(1000);
+      private final ExpiryCache<QueryKey, Query> staticQueryCache = new LRUCache<>(STATIC_QUERY_CACHE_SIZE);
       
       /** Context-local buffer manager */
       private final BufferManager bufferManager = BufferManager.get();

=== modified file 'src/com/goldencode/p2j/persist/orm/Persister.java'
--- old/src/com/goldencode/p2j/persist/orm/Persister.java	2023-05-23 09:43:33 +0000
+++ new/src/com/goldencode/p2j/persist/orm/Persister.java	2023-06-07 12:56:47 +0000
@@ -23,6 +23,7 @@
 **     CA  20230116 Increased updateCache size to 4096.
 ** 003 GBB 20230512 Logging methods replaced by CentralLogger/ConversionStatus.
 ** 004 RAA 20230518 Replaced lambdas with method referencing when using SQLStatementLogger.
+** 005 DDF 20230607 Made the size of the updateCache configurable.
 */
 
 /*
@@ -84,9 +85,12 @@
 import java.util.*;
 import java.util.logging.*;
 import com.goldencode.cache.*;
+import com.goldencode.p2j.cfg.Configuration;
+import com.goldencode.p2j.directory.DirectoryService;
 import com.goldencode.p2j.persist.*;
 import com.goldencode.p2j.persist.orm.SQLStatementLogger.*;
 import com.goldencode.p2j.persist.orm.types.*;
+import com.goldencode.p2j.util.Utils;
 import com.goldencode.p2j.util.logging.*;
 
 /**
@@ -107,7 +111,34 @@
    private final Session session;
    
    /** Cache of FQL strings, with or without max results and start offsets, to queries. */
-   private static ExpiryCache<UpdateInfo, UpdateInfo> updateCache = new LRUCache<>(4096);
+   private static ExpiryCache<UpdateInfo, UpdateInfo> updateCache;
+   
+   /**
+    * Read the configurable value for the update cache size and initialize the cache.
+    */
+   static
+   {      
+      int updateCacheSize = 4096;
+      if (Configuration.isRuntimeConfig())
+      {
+         DirectoryService ds = DirectoryService.getInstance();
+         if (!ds.bind())
+         {
+            throw new RuntimeException("Directory bind failed");
+         }
+         
+         try
+         {
+            String path = "persistence/cache-size/persister";
+            updateCacheSize = Utils.getDirectoryNodeInt(ds, path, 4096, false);
+         }
+         finally
+         {
+            ds.unbind();
+         }
+      }
+      updateCache = new LRUCache<>(updateCacheSize);
+   }
    
    /**
     * Constructor.

=== modified file 'src/com/goldencode/p2j/persist/orm/Session.java'
--- old/src/com/goldencode/p2j/persist/orm/Session.java	2023-05-26 14:37:01 +0000
+++ new/src/com/goldencode/p2j/persist/orm/Session.java	2023-06-07 12:59:02 +0000
@@ -44,6 +44,7 @@
 **     SR  20230522 Moved the deregister operation above the state check so it will happen regardless of 
 **                  how we exit the method.
 **     AL2 20230525 Added cache extension to support the cache pruning faster.
+** 006 DDF 20230607 Made the size of the session cache configurable.
 */
 
 /*
@@ -145,6 +146,9 @@
    /** Logger */
    private static final CentralLogger log = CentralLogger.get(Session.class.getName());
    
+   /** Size of the Session cache */
+   private static final int SESSION_CACHE_SIZE;
+   
    /** Object which tracks the current versions of DMOs to enable stale checking */
    private final DmoVersioning versioning;
    
@@ -181,7 +185,7 @@
    static
    {
       String primaryKey = null;
-      
+      int sessionCacheSize = 1024;
       if (Configuration.isRuntimeConfig())
       {
          DirectoryService ds = DirectoryService.getInstance();
@@ -195,6 +199,8 @@
             // configure primary key column name from directory, if available
             String path = "persistence/primary-key-name";
             primaryKey = Utils.getDirectoryNodeString(ds, path, null, false);
+            String recordsPath = "persistence/cache-size/session";
+            sessionCacheSize = Utils.getDirectoryNodeInt(ds, recordsPath, 1024, false);
          }
          finally
          {
@@ -220,6 +226,8 @@
       
       // finally, set the value into the static final field:
       PK = primaryKey;
+      
+      SESSION_CACHE_SIZE = sessionCacheSize;
    }
    
    /**
@@ -1736,7 +1744,7 @@
    {
       ExpiryCache<RecordIdentifier<String>, BaseRecord> c =
          new LRUCache<>(database.toString() + " database session cache",
-                        1024, // TODO: make configurable
+                        SESSION_CACHE_SIZE,
                         (dmo) -> !dmo.isInUse(),
                         CapacityPolicy.LENIENT);
       c.addCacheExpiryListener(this);

=== modified file 'src/com/goldencode/p2j/persist/orm/TempTableDataSourceProvider.java'
--- old/src/com/goldencode/p2j/persist/orm/TempTableDataSourceProvider.java	2023-05-12 13:51:40 +0000
+++ new/src/com/goldencode/p2j/persist/orm/TempTableDataSourceProvider.java	2023-06-07 13:00:09 +0000
@@ -19,6 +19,7 @@
 **                  to identify if the connection is proxied or not.
 ** 004 GBB 20230512 Logging methods replaced by CentralLogger/ConversionStatus.
 ** 005 AL2 20230512 Made psCache size configurable. Set default to 8196.
+** 006 DDF 20230607 Changed the configuration path for the psCache size.
 */
 
 /*
@@ -119,7 +120,7 @@
       
       try
       {
-         String path = "persistence/ps-cache-size";
+         String path = "persistence/cache-size/ps-cache-size";
          psCacheSize = Utils.getDirectoryNodeInt(ds, path, 8192, false);
       }
       finally
@@ -127,7 +128,6 @@
          ds.unbind();
          PS_CACHE_SIZE = psCacheSize;
       }
-      
    }
    
    /**

