1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2002, 2014 Oracle and/or its affiliates.  All rights reserved.
5  *
6  */
7 
8 package com.sleepycat.je.dbi;
9 
10 import static com.sleepycat.je.dbi.DbiStatDefinition.MB_ADMIN_BYTES;
11 import static com.sleepycat.je.dbi.DbiStatDefinition.MB_DATA_BYTES;
12 import static com.sleepycat.je.dbi.DbiStatDefinition.MB_DATA_ADMIN_BYTES;
13 import static com.sleepycat.je.dbi.DbiStatDefinition.MB_GROUP_DESC;
14 import static com.sleepycat.je.dbi.DbiStatDefinition.MB_GROUP_NAME;
15 import static com.sleepycat.je.dbi.DbiStatDefinition.MB_LOCK_BYTES;
16 import static com.sleepycat.je.dbi.DbiStatDefinition.MB_SHARED_CACHE_TOTAL_BYTES;
17 import static com.sleepycat.je.dbi.DbiStatDefinition.MB_TOTAL_BYTES;
18 
19 import java.lang.management.ManagementFactory;
20 import java.util.List;
21 import java.util.concurrent.atomic.AtomicLong;
22 
23 import com.sleepycat.bind.tuple.TupleOutput;
24 import com.sleepycat.je.DatabaseException;
25 import com.sleepycat.je.EnvironmentMutableConfig;
26 import com.sleepycat.je.config.EnvironmentParams;
27 import com.sleepycat.je.tree.IN;
28 import com.sleepycat.je.utilint.LoggerUtils;
29 import com.sleepycat.je.utilint.LongStat;
30 import com.sleepycat.je.utilint.StatGroup;
31 
32 /**
33  * MemoryBudget calculates the available memory for JE and how to apportion
34  * it between cache and log buffers. It is meant to centralize all memory
35  * calculations. Objects that ask for memory budgets should get settings from
36  * this class, rather than using the configuration parameter values directly.
37  */
38 public class MemoryBudget implements EnvConfigObserver {
39 
40     /*
41      * CLEANUP_DONE can be set to false for unit test debugging
42      * that is still in progress. When we do the final regression,
43      * this should be removed to be assured that it is never false.
44      */
45     public static boolean CLEANUP_DONE = false;
46 
47     /*
48      * These DEBUG variables are public so unit tests can easily turn them
49      * on and off for different sections of code.
50      */
51     public static boolean DEBUG_ADMIN = Boolean.getBoolean("memAdmin");
52     public static boolean DEBUG_LOCK = Boolean.getBoolean("memLock");
53     public static boolean DEBUG_TXN = Boolean.getBoolean("memTxn");
54     public static boolean DEBUG_TREEADMIN = Boolean.getBoolean("memTreeAdmin");
55     public static boolean DEBUG_TREE = Boolean.getBoolean("memTree");
56 
57     /*
58      * Object overheads. These are set statically with advance measurements.
59      * Java doesn't provide a way of assessing object size dynamically. These
60      * overheads will not be precise, but are close enough to let the system
61      * behave predictably.
62      *
63      * _32 values are the same on Windows and Solaris.
64      * _64 values are from Linux (were previously 1.5.0_05 on Solaris).
65      * _OOPS are on a 64b JVM with -XX:+UseCompressedOops
66      *
67      * The integer following the // below is the Sizeof argument used to
68      * compute the value.
69      */
70 
71     // 7
72     private final static int LONG_OVERHEAD_32 = 16;
73     private final static int LONG_OVERHEAD_64 = 24;
74     private final static int LONG_OVERHEAD_OOPS = 24;
75 
76     // 8
77     private final static int ARRAY_OVERHEAD_32 = 16;
78     private final static int ARRAY_OVERHEAD_64 = 24;
79     private final static int ARRAY_OVERHEAD_OOPS = 16;
80 
81     // see byteArraySize
82     private final static int ARRAY_SIZE_INCLUDED_32 = 4;
83     private final static int ARRAY_SIZE_INCLUDED_64 = 0;
84     private final static int ARRAY_SIZE_INCLUDED_OOPS = 0;
85 
86     // 2
87     private final static int OBJECT_OVERHEAD_32 = 8;
88     private final static int OBJECT_OVERHEAD_64 = 16;
89     private final static int OBJECT_OVERHEAD_OOPS = 16;
90 
91     // (4 - ARRAY_OVERHEAD) / 256
92     // 32b: 4 is 1040
93     // 64b: 4 is 2078
94     // Oops: 4 is 1040
95     private final static int OBJECT_ARRAY_ITEM_OVERHEAD_32 = 4;
96     private final static int OBJECT_ARRAY_ITEM_OVERHEAD_64 = 8;
97     private final static int OBJECT_ARRAY_ITEM_OVERHEAD_OOPS = 4;
98 
99     // 20
100     private final static int HASHMAP_OVERHEAD_32 = 120;
101     private final static int HASHMAP_OVERHEAD_64 = 219;
102     private final static int HASHMAP_OVERHEAD_OOPS = 128;
103 
104     // 21 - OBJECT_OVERHEAD - HASHMAP_OVERHEAD
105     // 32b: 21 is 152
106     // 64b: 21 is max(280,...,287) on Linux/Solaris 1.5/1.6
107     // Oops: 21 is 176
108     private final static int HASHMAP_ENTRY_OVERHEAD_32 = 24;
109     private final static int HASHMAP_ENTRY_OVERHEAD_64 = 52;
110     private final static int HASHMAP_ENTRY_OVERHEAD_OOPS = 32;
111 
112     // 22
113     private final static int HASHSET_OVERHEAD_32 = 136;
114     private final static int HASHSET_OVERHEAD_64 = 240;
115     private final static int HASHSET_OVERHEAD_OOPS = 144;
116 
117     // 23 - OBJECT_OVERHEAD - HASHSET_OVERHEAD
118     // 32b: 23 is 168
119     // 64b: 23 is max(304,...,311) on Linux/Solaris
120     // Oops: 23 is 192
121     private final static int HASHSET_ENTRY_OVERHEAD_32 = 24;
122     private final static int HASHSET_ENTRY_OVERHEAD_64 = 55;
123     private final static int HASHSET_ENTRY_OVERHEAD_OOPS = 32;
124 
125     // HASHMAP_OVERHEAD * 2
126     private final static int TWOHASHMAPS_OVERHEAD_32 = 240;
127     private final static int TWOHASHMAPS_OVERHEAD_64 = 438;
128     private final static int TWOHASHMAPS_OVERHEAD_OOPS = 256;
129 
130     // 34
131     private final static int TREEMAP_OVERHEAD_32 = 48;
132     private final static int TREEMAP_OVERHEAD_64 = 80;
133     private final static int TREEMAP_OVERHEAD_OOPS = 48;
134 
135     // 35 - OBJECT_OVERHEAD - TREEMAP_OVERHEAD
136     // 32b: 35 is 88
137     // 64b: 35 is 160
138     // Oops: 35 is 104
139     private final static int TREEMAP_ENTRY_OVERHEAD_32 = 32;
140     private final static int TREEMAP_ENTRY_OVERHEAD_64 = 64;
141     private final static int TREEMAP_ENTRY_OVERHEAD_OOPS = 40;
142 
143     // 36
144     // 32b JDK 1.7 is 928
145     private final static int MAPLN_OVERHEAD_32 = 920;
146     private final static int MAPLN_OVERHEAD_64 = 1624;
147     private final static int MAPLN_OVERHEAD_OOPS = 1016;
148 
149     // 9
150     private final static int LN_OVERHEAD_32 = 16;
151     private final static int LN_OVERHEAD_64 = 32;
152     private final static int LN_OVERHEAD_OOPS = 24;
153 
154     // 17 minus 9
155     // 32b: 17 is 24
156     // 64b: 17 is 40
157     // Oops: 17 is 32
158     private final static int VERSIONEDLN_OVERHEAD_32 = 8;
159     private final static int VERSIONEDLN_OVERHEAD_64 = 8;
160     private final static int VERSIONEDLN_OVERHEAD_OOPS = 8;
161 
162     // No longer updated, as dups are no longer used except during conversion.
163     private final static int DUPCOUNTLN_OVERHEAD_32 = 32;
164     private final static int DUPCOUNTLN_OVERHEAD_64 = 48;
165     private final static int DUPCOUNTLN_OVERHEAD_OOPS = 40;
166 
167     // 12
168     private final static int BIN_FIXED_OVERHEAD_32 = 208;
169     private final static int BIN_FIXED_OVERHEAD_64 = 328;
170     private final static int BIN_FIXED_OVERHEAD_OOPS = 224;
171 
172     // 18
173     private final static int BINDELTA_OVERHEAD_32 = 48;
174     private final static int BINDELTA_OVERHEAD_64 = 72;
175     private final static int BINDELTA_OVERHEAD_OOPS = 64;
176 
177     // 19
178     private final static int DELTAINFO_OVERHEAD_32 = 24;
179     private final static int DELTAINFO_OVERHEAD_64 = 40;
180     private final static int DELTAINFO_OVERHEAD_OOPS = 32;
181 
182     // 47
183     private final static int SPARSE_TARGET_ENTRY_OVERHEAD_32 = 72;
184     private final static int SPARSE_TARGET_ENTRY_OVERHEAD_64 = 120;
185     private final static int SPARSE_TARGET_ENTRY_OVERHEAD_OOPS = 80;
186 
187     // 48
188     private final static int DEFAULT_TARGET_ENTRY_OVERHEAD_32 = 16;
189     private final static int DEFAULT_TARGET_ENTRY_OVERHEAD_64 = 24;
190     private final static int DEFAULT_TARGET_ENTRY_OVERHEAD_OOPS = 16;
191 
192     // 49
193     private final static int MAX_KEY_SIZE_KEYVALS_OVERHEAD_32 = 16;
194     private final static int MAX_KEY_SIZE_KEYVALS_OVERHEAD_64 = 32;
195     private final static int MAX_KEY_SIZE_KEYVALS_OVERHEAD_OOPS = 24;
196 
197     // 50
198     private final static int DEFAULT_KEYVALS_OVERHEAD_32 = 16;
199     private final static int DEFAULT_KEYVALS_OVERHEAD_64 = 24;
200     private final static int DEFAULT_KEYVALS_OVERHEAD_OOPS = 16;
201 
202     // 52
203     private final static int DEFAULT_LONG_REP_OVERHEAD_32 = 16;
204     private final static int DEFAULT_LONG_REP_OVERHEAD_64 = 32;
205     private final static int DEFAULT_LONG_REP_OVERHEAD_OOPS = 24;
206 
207     // 54
208     private final static int DIN_FIXED_OVERHEAD_32 = 120;
209     private final static int DIN_FIXED_OVERHEAD_64 = 176;
210     private final static int DIN_FIXED_OVERHEAD_OOPS = 120;
211 
212     // 53
213     private final static int DBIN_FIXED_OVERHEAD_32 = 152;
214     private final static int DBIN_FIXED_OVERHEAD_64 = 232;
215     private final static int DBIN_FIXED_OVERHEAD_OOPS = 168;
216 
217     // 13
218     private final static int IN_FIXED_OVERHEAD_32 = 296;
219     private final static int IN_FIXED_OVERHEAD_64 = 392;
220     private final static int IN_FIXED_OVERHEAD_OOPS = 256;
221 
222     // 6
223     private final static int KEY_OVERHEAD_32 = 16;
224     private final static int KEY_OVERHEAD_64 = 24;
225     private final static int KEY_OVERHEAD_OOPS = 16;
226 
227     // 24
228     private final static int LOCKIMPL_OVERHEAD_32 = 24;
229     private final static int LOCKIMPL_OVERHEAD_64 = 48;
230     private final static int LOCKIMPL_OVERHEAD_OOPS = 32;
231 
232     // 42
233     private final static int THINLOCKIMPL_OVERHEAD_32 = 16;
234     private final static int THINLOCKIMPL_OVERHEAD_64 = 32;
235     private final static int THINLOCKIMPL_OVERHEAD_OOPS = 24;
236 
237     // 25
238     private final static int LOCKINFO_OVERHEAD_32 = 16;
239     private final static int LOCKINFO_OVERHEAD_64 = 32;
240     private final static int LOCKINFO_OVERHEAD_OOPS = 24;
241 
242     // 37
243     private final static int WRITE_LOCKINFO_OVERHEAD_32 = 32;
244     private final static int WRITE_LOCKINFO_OVERHEAD_64 = 40;
245     private final static int WRITE_LOCKINFO_OVERHEAD_OOPS = 32;
246 
247     /*
248      * Txn memory is the size for the Txn + a hashmap entry
249      * overhead for being part of the transaction table.
250      */
251     // 15
252     private final static int TXN_OVERHEAD_32 = 224;
253     private final static int TXN_OVERHEAD_64 = 353;
254     private final static int TXN_OVERHEAD_OOPS = 232;
255 
256     // 26
257     private final static int CHECKPOINT_REFERENCE_SIZE_32 = 32 +
258         HASHSET_ENTRY_OVERHEAD_32;
259     private final static int CHECKPOINT_REFERENCE_SIZE_64 = 48 +
260         HASHSET_ENTRY_OVERHEAD_64;
261     private final static int CHECKPOINT_REFERENCE_SIZE_OOPS = 32 +
262         HASHSET_ENTRY_OVERHEAD_OOPS;
263 
264     /* The per-log-file bytes used in UtilizationProfile. */
265     // 29 / 10.0 (That is the number 10, not the Sizeof type 10)
266     // 32b: 29 is 1088
267     // 64b: 29 is 1605
268     // Oops: 29 is 1248
269     private final static int UTILIZATION_PROFILE_ENTRY_32 = 109;
270     private final static int UTILIZATION_PROFILE_ENTRY_64 = 161;
271     private final static int UTILIZATION_PROFILE_ENTRY_OOPS = 125;
272 
273     // 38
274     private final static int DBFILESUMMARY_OVERHEAD_32 = 40;
275     private final static int DBFILESUMMARY_OVERHEAD_64 = 48;
276     private final static int DBFILESUMMARY_OVERHEAD_OOPS = 48;
277 
278     /* Tracked File Summary overheads. */
279     // 31
280     private final static int TFS_LIST_INITIAL_OVERHEAD_32 = 464;
281     private final static int TFS_LIST_INITIAL_OVERHEAD_64 = 504;
282     private final static int TFS_LIST_INITIAL_OVERHEAD_OOPS = 464;
283 
284     // 30
285     // 64b: 30 is max(464,464,464,465) on Linux/Solaris on 1.5/1.6
286     private final static int TFS_LIST_SEGMENT_OVERHEAD_32 = 440;
287     private final static int TFS_LIST_SEGMENT_OVERHEAD_64 = 465;
288     private final static int TFS_LIST_SEGMENT_OVERHEAD_OOPS = 440;
289 
290     // 33
291     private final static int LN_INFO_OVERHEAD_32 = 24;
292     private final static int LN_INFO_OVERHEAD_64 = 40;
293     private final static int LN_INFO_OVERHEAD_OOPS = 24;
294 
295     // 43
296     private final static int FILESUMMARYLN_OVERHEAD_32 = 112;
297     private final static int FILESUMMARYLN_OVERHEAD_64 = 168;
298     private final static int FILESUMMARYLN_OVERHEAD_OOPS = 128;
299 
300     // 51
301     private final static int INENTRY_OVERHEAD_32 = 16;
302     private final static int INENTRY_OVERHEAD_64 = 32;
303     private final static int INENTRY_OVERHEAD_OOPS= 24;
304 
305     // 46
306     private final static int DELTAINENTRY_OVERHEAD_32 = 32;
307     private final static int DELTAINENTRY_OVERHEAD_64 = 48;
308     private final static int DELTAINENTRY_OVERHEAD_OOPS= 32;
309 
310     // 27 minus zero length Object array
311     private final static int EMPTY_OBJ_ARRAY = objectArraySize(0);
312     private final static int ARRAYLIST_OVERHEAD_32 = 40 - EMPTY_OBJ_ARRAY;
313     private final static int ARRAYLIST_OVERHEAD_64 = 64 - EMPTY_OBJ_ARRAY;
314     private final static int ARRAYLIST_OVERHEAD_OOPS = 40 - EMPTY_OBJ_ARRAY;
315 
316     // 44 minus 45
317     // 32b: 44 and 45 are 40 and 16, resp.
318     // 64b: 44 and 45 are 56 and 24, resp.
319     // Oops: 44 and 45 are 40 and 16, resp.
320     private final static int TUPLE_OUTPUT_OVERHEAD_32 = 24;
321     private final static int TUPLE_OUTPUT_OVERHEAD_64 = 32;
322     private final static int TUPLE_OUTPUT_OVERHEAD_OOPS = 24;
323 
324     public final static int LONG_OVERHEAD;
325     public final static int ARRAY_OVERHEAD;
326     public final static int ARRAY_SIZE_INCLUDED;
327     public final static int OBJECT_OVERHEAD;
328     public final static int OBJECT_ARRAY_ITEM_OVERHEAD;
329     public final static int HASHMAP_OVERHEAD;
330     public final static int HASHMAP_ENTRY_OVERHEAD;
331     public final static int HASHSET_OVERHEAD;
332     public final static int HASHSET_ENTRY_OVERHEAD;
333     public final static int TWOHASHMAPS_OVERHEAD;
334     public final static int TREEMAP_OVERHEAD;
335     public final static int TREEMAP_ENTRY_OVERHEAD;
336     public final static int MAPLN_OVERHEAD;
337     public final static int LN_OVERHEAD;
338     public final static int VERSIONEDLN_OVERHEAD;
339     public final static int DUPCOUNTLN_OVERHEAD;
340     public final static int BIN_FIXED_OVERHEAD;
341     public final static int BINDELTA_OVERHEAD;
342     public final static int DELTAINFO_OVERHEAD;
343     public final static int SPARSE_TARGET_ENTRY_OVERHEAD;
344     public final static int DEFAULT_TARGET_ENTRY_OVERHEAD;
345     public final static int DEFAULT_KEYVALS_OVERHEAD;
346     public final static int MAX_KEY_SIZE_KEYVALS_OVERHEAD;
347     public final static int DEFAULT_LONG_REP_OVERHEAD;
348     public final static int DIN_FIXED_OVERHEAD;
349     public final static int DBIN_FIXED_OVERHEAD;
350     public final static int IN_FIXED_OVERHEAD;
351     public final static int KEY_OVERHEAD;
352     public final static int LOCKIMPL_OVERHEAD;
353     public final static int THINLOCKIMPL_OVERHEAD;
354     public final static int LOCKINFO_OVERHEAD;
355     public final static int WRITE_LOCKINFO_OVERHEAD;
356     public final static int TXN_OVERHEAD;
357     public final static int CHECKPOINT_REFERENCE_SIZE;
358     public final static int UTILIZATION_PROFILE_ENTRY;
359     public final static int DBFILESUMMARY_OVERHEAD;
360     public final static int TFS_LIST_INITIAL_OVERHEAD;
361     public final static int TFS_LIST_SEGMENT_OVERHEAD;
362     public final static int LN_INFO_OVERHEAD;
363     public final static int FILESUMMARYLN_OVERHEAD;
364     public final static int INENTRY_OVERHEAD;
365     public final static int DELTAINENTRY_OVERHEAD;
366     public final static int ARRAYLIST_OVERHEAD;
367     public final static int TUPLE_OUTPUT_OVERHEAD;
368 
369     /* Primitive long array item size is the same on all platforms. */
370     public final static int PRIMITIVE_LONG_ARRAY_ITEM_OVERHEAD = 8;
371 
372     private final static String JVM_ARCH_PROPERTY = "sun.arch.data.model";
373     private final static String FORCE_JVM_ARCH = "je.forceJVMArch";
374     private static boolean COMPRESSED_OOPS_REQUESTED = false;
375     private static boolean COMPRESSED_OOPS_KNOWN = false;
376     private static boolean COMPRESSED_OOPS_KNOWN_ON = false;
377 
378     static {
379         String javaVersion = System.getProperty("java.version");
380         boolean is64 = false;
381         String overrideArch = System.getProperty(FORCE_JVM_ARCH);
382 
383         try {
384             if (overrideArch == null) {
385                 String arch = System.getProperty(JVM_ARCH_PROPERTY);
386                 if (arch != null) {
387                     is64 = Integer.parseInt(arch) == 64;
388                 }
389             } else {
390                 is64 = Integer.parseInt(overrideArch) == 64;
391             }
392         } catch (NumberFormatException NFE) {
393             NFE.printStackTrace(System.err);
394         }
395 
396         final Boolean checkCompressedOops =
397             CompressedOopsDetector.isEnabled();
398         if (checkCompressedOops != null) {
399             COMPRESSED_OOPS_KNOWN = true;
400             COMPRESSED_OOPS_KNOWN_ON = checkCompressedOops;
401         }
402 
403         //ONEJAVA/*
404         List<String> args =
405             ManagementFactory.getRuntimeMXBean().getInputArguments();
406         for (String arg : args) {
407             if ("-XX:+UseCompressedOops".equals(arg)) {
408                 COMPRESSED_OOPS_REQUESTED = true;
409                 break;
410             }
411         }
412         //ONEJAVA*/
413 
414         final boolean useCompressedOops = COMPRESSED_OOPS_KNOWN ?
415             COMPRESSED_OOPS_KNOWN_ON :
416             COMPRESSED_OOPS_REQUESTED;
417 
418         if (useCompressedOops) {
419             LONG_OVERHEAD = LONG_OVERHEAD_OOPS;
420             ARRAY_OVERHEAD = ARRAY_OVERHEAD_OOPS;
421             ARRAY_SIZE_INCLUDED = ARRAY_SIZE_INCLUDED_OOPS;
422             OBJECT_OVERHEAD = OBJECT_OVERHEAD_OOPS;
423             OBJECT_ARRAY_ITEM_OVERHEAD = OBJECT_ARRAY_ITEM_OVERHEAD_OOPS;
424             HASHMAP_ENTRY_OVERHEAD = HASHMAP_ENTRY_OVERHEAD_OOPS;
425             HASHSET_OVERHEAD = HASHSET_OVERHEAD_OOPS;
426             HASHSET_ENTRY_OVERHEAD = HASHSET_ENTRY_OVERHEAD_OOPS;
427             TREEMAP_OVERHEAD = TREEMAP_OVERHEAD_OOPS;
428             MAPLN_OVERHEAD = MAPLN_OVERHEAD_OOPS;
429             BIN_FIXED_OVERHEAD = BIN_FIXED_OVERHEAD_OOPS;
430             BINDELTA_OVERHEAD = BINDELTA_OVERHEAD_OOPS;
431             DELTAINFO_OVERHEAD = DELTAINFO_OVERHEAD_OOPS;
432             SPARSE_TARGET_ENTRY_OVERHEAD =
433                 SPARSE_TARGET_ENTRY_OVERHEAD_OOPS;
434             DEFAULT_TARGET_ENTRY_OVERHEAD =
435                 DEFAULT_TARGET_ENTRY_OVERHEAD_OOPS;
436             DEFAULT_KEYVALS_OVERHEAD = DEFAULT_KEYVALS_OVERHEAD_OOPS;
437             MAX_KEY_SIZE_KEYVALS_OVERHEAD =
438                 MAX_KEY_SIZE_KEYVALS_OVERHEAD_OOPS;
439             DEFAULT_LONG_REP_OVERHEAD = DEFAULT_LONG_REP_OVERHEAD_OOPS;
440             DIN_FIXED_OVERHEAD = DIN_FIXED_OVERHEAD_OOPS;
441             DBIN_FIXED_OVERHEAD = DBIN_FIXED_OVERHEAD_OOPS;
442             IN_FIXED_OVERHEAD = IN_FIXED_OVERHEAD_OOPS;
443             HASHMAP_OVERHEAD = HASHMAP_OVERHEAD_OOPS;
444             TWOHASHMAPS_OVERHEAD = TWOHASHMAPS_OVERHEAD_OOPS;
445             TREEMAP_ENTRY_OVERHEAD = TREEMAP_ENTRY_OVERHEAD_OOPS;
446             LN_OVERHEAD = LN_OVERHEAD_OOPS;
447             VERSIONEDLN_OVERHEAD = VERSIONEDLN_OVERHEAD_OOPS;
448             DUPCOUNTLN_OVERHEAD = DUPCOUNTLN_OVERHEAD_OOPS;
449             TXN_OVERHEAD = TXN_OVERHEAD_OOPS;
450             CHECKPOINT_REFERENCE_SIZE = CHECKPOINT_REFERENCE_SIZE_OOPS;
451             KEY_OVERHEAD = KEY_OVERHEAD_OOPS;
452             LOCKIMPL_OVERHEAD = LOCKIMPL_OVERHEAD_OOPS;
453             THINLOCKIMPL_OVERHEAD = THINLOCKIMPL_OVERHEAD_OOPS;
454             LOCKINFO_OVERHEAD = LOCKINFO_OVERHEAD_OOPS;
455             WRITE_LOCKINFO_OVERHEAD = WRITE_LOCKINFO_OVERHEAD_OOPS;
456             UTILIZATION_PROFILE_ENTRY = UTILIZATION_PROFILE_ENTRY_OOPS;
457             DBFILESUMMARY_OVERHEAD = DBFILESUMMARY_OVERHEAD_OOPS;
458             TFS_LIST_INITIAL_OVERHEAD = TFS_LIST_INITIAL_OVERHEAD_OOPS;
459             TFS_LIST_SEGMENT_OVERHEAD = TFS_LIST_SEGMENT_OVERHEAD_OOPS;
460             LN_INFO_OVERHEAD = LN_INFO_OVERHEAD_OOPS;
461             FILESUMMARYLN_OVERHEAD = FILESUMMARYLN_OVERHEAD_OOPS;
462             INENTRY_OVERHEAD = INENTRY_OVERHEAD_OOPS;
463             DELTAINENTRY_OVERHEAD = DELTAINENTRY_OVERHEAD_OOPS;
464             ARRAYLIST_OVERHEAD = ARRAYLIST_OVERHEAD_OOPS;
465             TUPLE_OUTPUT_OVERHEAD = TUPLE_OUTPUT_OVERHEAD_OOPS;
466         } else if (is64) {
467             LONG_OVERHEAD = LONG_OVERHEAD_64;
468             ARRAY_OVERHEAD = ARRAY_OVERHEAD_64;
469             ARRAY_SIZE_INCLUDED = ARRAY_SIZE_INCLUDED_64;
470             OBJECT_OVERHEAD = OBJECT_OVERHEAD_64;
471             OBJECT_ARRAY_ITEM_OVERHEAD = OBJECT_ARRAY_ITEM_OVERHEAD_64;
472             HASHMAP_ENTRY_OVERHEAD = HASHMAP_ENTRY_OVERHEAD_64;
473             HASHSET_OVERHEAD = HASHSET_OVERHEAD_64;
474             HASHSET_ENTRY_OVERHEAD = HASHSET_ENTRY_OVERHEAD_64;
475             TREEMAP_OVERHEAD = TREEMAP_OVERHEAD_64;
476             MAPLN_OVERHEAD = MAPLN_OVERHEAD_64;
477             BIN_FIXED_OVERHEAD = BIN_FIXED_OVERHEAD_64;
478             DIN_FIXED_OVERHEAD = DIN_FIXED_OVERHEAD_64;
479             DBIN_FIXED_OVERHEAD = DBIN_FIXED_OVERHEAD_64;
480             IN_FIXED_OVERHEAD = IN_FIXED_OVERHEAD_64;
481             HASHMAP_OVERHEAD = HASHMAP_OVERHEAD_64;
482             TWOHASHMAPS_OVERHEAD = TWOHASHMAPS_OVERHEAD_64;
483             BINDELTA_OVERHEAD = BINDELTA_OVERHEAD_64;
484             DELTAINFO_OVERHEAD = DELTAINFO_OVERHEAD_64;
485             SPARSE_TARGET_ENTRY_OVERHEAD = SPARSE_TARGET_ENTRY_OVERHEAD_64;
486             DEFAULT_TARGET_ENTRY_OVERHEAD =
487                 DEFAULT_TARGET_ENTRY_OVERHEAD_64;
488             DEFAULT_KEYVALS_OVERHEAD = DEFAULT_KEYVALS_OVERHEAD_64;
489             MAX_KEY_SIZE_KEYVALS_OVERHEAD =
490                 MAX_KEY_SIZE_KEYVALS_OVERHEAD_64;
491             DEFAULT_LONG_REP_OVERHEAD = DEFAULT_LONG_REP_OVERHEAD_64;
492             TREEMAP_ENTRY_OVERHEAD = TREEMAP_ENTRY_OVERHEAD_64;
493             LN_OVERHEAD = LN_OVERHEAD_64;
494             VERSIONEDLN_OVERHEAD = VERSIONEDLN_OVERHEAD_64;
495             DUPCOUNTLN_OVERHEAD = DUPCOUNTLN_OVERHEAD_64;
496             TXN_OVERHEAD = TXN_OVERHEAD_64;
497             CHECKPOINT_REFERENCE_SIZE = CHECKPOINT_REFERENCE_SIZE_64;
498             KEY_OVERHEAD = KEY_OVERHEAD_64;
499             LOCKIMPL_OVERHEAD = LOCKIMPL_OVERHEAD_64;
500             THINLOCKIMPL_OVERHEAD = THINLOCKIMPL_OVERHEAD_64;
501             LOCKINFO_OVERHEAD = LOCKINFO_OVERHEAD_64;
502             WRITE_LOCKINFO_OVERHEAD = WRITE_LOCKINFO_OVERHEAD_64;
503             UTILIZATION_PROFILE_ENTRY = UTILIZATION_PROFILE_ENTRY_64;
504             DBFILESUMMARY_OVERHEAD = DBFILESUMMARY_OVERHEAD_64;
505             TFS_LIST_INITIAL_OVERHEAD = TFS_LIST_INITIAL_OVERHEAD_64;
506             TFS_LIST_SEGMENT_OVERHEAD = TFS_LIST_SEGMENT_OVERHEAD_64;
507             LN_INFO_OVERHEAD = LN_INFO_OVERHEAD_64;
508             FILESUMMARYLN_OVERHEAD = FILESUMMARYLN_OVERHEAD_64;
509             INENTRY_OVERHEAD = INENTRY_OVERHEAD_64;
510             DELTAINENTRY_OVERHEAD = DELTAINENTRY_OVERHEAD_64;
511             ARRAYLIST_OVERHEAD = ARRAYLIST_OVERHEAD_64;
512             TUPLE_OUTPUT_OVERHEAD = TUPLE_OUTPUT_OVERHEAD_64;
513         } else {
514             LONG_OVERHEAD = LONG_OVERHEAD_32;
515             ARRAY_OVERHEAD = ARRAY_OVERHEAD_32;
516             ARRAY_SIZE_INCLUDED = ARRAY_SIZE_INCLUDED_32;
517             OBJECT_OVERHEAD = OBJECT_OVERHEAD_32;
518             OBJECT_ARRAY_ITEM_OVERHEAD = OBJECT_ARRAY_ITEM_OVERHEAD_32;
519             HASHMAP_OVERHEAD = HASHMAP_OVERHEAD_32;
520             HASHMAP_ENTRY_OVERHEAD = HASHMAP_ENTRY_OVERHEAD_32;
521             HASHSET_OVERHEAD = HASHSET_OVERHEAD_32;
522             HASHSET_ENTRY_OVERHEAD = HASHSET_ENTRY_OVERHEAD_32;
523             TWOHASHMAPS_OVERHEAD = TWOHASHMAPS_OVERHEAD_32;
524             TREEMAP_OVERHEAD = TREEMAP_OVERHEAD_32;
525             MAPLN_OVERHEAD = MAPLN_OVERHEAD_32;
526             TREEMAP_ENTRY_OVERHEAD = TREEMAP_ENTRY_OVERHEAD_32;
527             LN_OVERHEAD = LN_OVERHEAD_32;
528             VERSIONEDLN_OVERHEAD = VERSIONEDLN_OVERHEAD_32;
529             DUPCOUNTLN_OVERHEAD = DUPCOUNTLN_OVERHEAD_32;
530             BIN_FIXED_OVERHEAD = BIN_FIXED_OVERHEAD_32;
531             BINDELTA_OVERHEAD = BINDELTA_OVERHEAD_32;
532             DELTAINFO_OVERHEAD = DELTAINFO_OVERHEAD_32;
533             SPARSE_TARGET_ENTRY_OVERHEAD = SPARSE_TARGET_ENTRY_OVERHEAD_32;
534             DEFAULT_TARGET_ENTRY_OVERHEAD =
535                 DEFAULT_TARGET_ENTRY_OVERHEAD_32;
536             DEFAULT_KEYVALS_OVERHEAD = DEFAULT_KEYVALS_OVERHEAD_32;
537             MAX_KEY_SIZE_KEYVALS_OVERHEAD =
538                 MAX_KEY_SIZE_KEYVALS_OVERHEAD_32;
539             DEFAULT_LONG_REP_OVERHEAD = DEFAULT_LONG_REP_OVERHEAD_32;
540             DIN_FIXED_OVERHEAD = DIN_FIXED_OVERHEAD_32;
541             DBIN_FIXED_OVERHEAD = DBIN_FIXED_OVERHEAD_32;
542             IN_FIXED_OVERHEAD = IN_FIXED_OVERHEAD_32;
543             TXN_OVERHEAD = TXN_OVERHEAD_32;
544             CHECKPOINT_REFERENCE_SIZE = CHECKPOINT_REFERENCE_SIZE_32;
545             KEY_OVERHEAD = KEY_OVERHEAD_32;
546             LOCKIMPL_OVERHEAD = LOCKIMPL_OVERHEAD_32;
547             THINLOCKIMPL_OVERHEAD = THINLOCKIMPL_OVERHEAD_32;
548             LOCKINFO_OVERHEAD = LOCKINFO_OVERHEAD_32;
549             WRITE_LOCKINFO_OVERHEAD = WRITE_LOCKINFO_OVERHEAD_32;
550             UTILIZATION_PROFILE_ENTRY = UTILIZATION_PROFILE_ENTRY_32;
551             DBFILESUMMARY_OVERHEAD = DBFILESUMMARY_OVERHEAD_32;
552             TFS_LIST_INITIAL_OVERHEAD = TFS_LIST_INITIAL_OVERHEAD_32;
553             TFS_LIST_SEGMENT_OVERHEAD = TFS_LIST_SEGMENT_OVERHEAD_32;
554             LN_INFO_OVERHEAD = LN_INFO_OVERHEAD_32;
555             FILESUMMARYLN_OVERHEAD = FILESUMMARYLN_OVERHEAD_32;
556             INENTRY_OVERHEAD = INENTRY_OVERHEAD_32;
557             DELTAINENTRY_OVERHEAD = DELTAINENTRY_OVERHEAD_32;
558             ARRAYLIST_OVERHEAD = ARRAYLIST_OVERHEAD_32;
559             TUPLE_OUTPUT_OVERHEAD = TUPLE_OUTPUT_OVERHEAD_32;
560         }
561     }
562 
563     /* public for unit tests. */
564     public final static long MIN_MAX_MEMORY_SIZE = 96 * 1024;
565     public final static String MIN_MAX_MEMORY_SIZE_STRING =
566         Long.toString(MIN_MAX_MEMORY_SIZE);
567 
568     /* This value prevents cache churn for apps with a high write rate. */
569     @SuppressWarnings("unused")
570     private final static int DEFAULT_MIN_BTREE_CACHE_SIZE = 500 * 1024;
571 
572     private final static long N_64MB = (1 << 26);
573 
574     /*
575      * Note that this class contains long fields that are accessed by multiple
576      * threads.  Access to these fields is synchronized when changing them but
577      * not when reading them to detect cache overflow or get stats.  Although
578      * inaccuracies may occur when reading the values, correcting this is not
579      * worth the cost of synchronizing every time we access them.  The worst
580      * that can happen is that we may invoke eviction unnecessarily.
581      */
582 
583     /*
584      * Amount of memory cached for tree objects.
585      */
586     private final AtomicLong treeMemoryUsage = new AtomicLong(0);
587 
588     /*
589      * Amount of memory cached for txn usage.
590      */
591     private final AtomicLong txnMemoryUsage = new AtomicLong(0);
592 
593     /*
594      * Amount of memory cached for log cleaning, dirty IN list, and other admin
595      * functions.
596      */
597     private final AtomicLong adminMemoryUsage = new AtomicLong(0);
598 
599     /*
600      * Amount of memory cached for admininstrative structures that are
601      * sometimes housed within tree nodes. Right now, that's
602      * DbFileSummaryMap, which is sometimes referenced by a MapLN by
603      * way of a DatabaseImpl, and sometimes is just referenced by
604      * a DatabaseImpl without a MapLN (the id and name databases.)
605      */
606     private final AtomicLong treeAdminMemoryUsage = new AtomicLong(0);
607 
608     /*
609      * Amount of memory cached for locks. Protected by the
610      * LockManager.lockTableLatches[lockTableIndex].
611      */
612     private final AtomicLong lockMemoryUsage = new AtomicLong(0);
613 
614     /*
615      * Memory available to JE, based on je.maxMemory and the memory available
616      * to this process.
617      */
618     private final Totals totals;
619 
620     /* Memory available to log buffers. */
621     private long logBufferBudget;
622 
623     /* Maximum allowed use of the admin budget by the UtilizationTracker. */
624     private long trackerBudget;
625 
626     /* Mininum to prevent cache churn. */
627     private long minTreeMemoryUsage;
628 
629     private final EnvironmentImpl envImpl;
630 
MemoryBudget(EnvironmentImpl envImpl, EnvironmentImpl sharedCacheEnv, DbConfigManager configManager)631     MemoryBudget(EnvironmentImpl envImpl,
632                  EnvironmentImpl sharedCacheEnv,
633                  DbConfigManager configManager)
634         throws DatabaseException {
635 
636         this.envImpl = envImpl;
637 
638         /* Request notification of mutable property changes. */
639         envImpl.addConfigObserver(this);
640 
641         /* Perform first time budget initialization. */
642         long newMaxMemory;
643         if (envImpl.getSharedCache()) {
644             if (sharedCacheEnv != null) {
645                 totals = sharedCacheEnv.getMemoryBudget().totals;
646                 /* For a new environment, do not override existing budget. */
647                 newMaxMemory = -1;
648             } else {
649                 totals = new SharedTotals();
650                 newMaxMemory = calcMaxMemory(configManager);
651             }
652         } else {
653             totals = new PrivateTotals(this);
654             newMaxMemory = calcMaxMemory(configManager);
655         }
656         reset(newMaxMemory, true /*newEnv*/, configManager);
657 
658         checkCompressedOops();
659     }
660 
661     /**
662      * Logs a SEVERE message if compressed oops was specified but did not take
663      * effect.  Must be called after the environment is initialized so the
664      * message makes it to the output file.
665      */
checkCompressedOops()666     private void checkCompressedOops() {
667         if (COMPRESSED_OOPS_REQUESTED &&
668             COMPRESSED_OOPS_KNOWN &&
669             !COMPRESSED_OOPS_KNOWN_ON) {
670             LoggerUtils.severe(envImpl.getLogger(), envImpl,
671                 "-XX:+UseCompressedOops was specified but is not in effect," +
672                 " probably because the heap size is too large for this JVM" +
673                 " option on this platform.  This is likely to cause an" +
674                 " OutOfMemoryError!");
675         }
676     }
677 
678     /**
679      * Respond to config updates.
680      */
envConfigUpdate(DbConfigManager configManager, EnvironmentMutableConfig ignore)681     public void envConfigUpdate(DbConfigManager configManager,
682                                 EnvironmentMutableConfig ignore)
683         throws DatabaseException {
684 
685         /* Reinitialize the cache budget and the log buffer pool. */
686         reset(calcMaxMemory(configManager), false /*newEnv*/, configManager);
687     }
688 
689     /**
690      * @throws IllegalArgumentException via Environment ctor and
691      * setMutableConfig.
692      */
calcMaxMemory(DbConfigManager configManager)693     private long calcMaxMemory(DbConfigManager configManager) {
694 
695         /*
696          * Calculate the total memory allotted to JE.
697          * 1. If je.maxMemory is specified, use that. Check that it's not more
698          * than the JVM memory.
699          * 2. Otherwise, take je.maxMemoryPercent * JVM max memory.
700          */
701         long newMaxMemory =
702             configManager.getLong(EnvironmentParams.MAX_MEMORY);
703         long jvmMemory = getRuntimeMaxMemory();
704 
705         if (newMaxMemory != 0) {
706             /* Application specified a cache size number, validate it. */
707             if (jvmMemory < newMaxMemory) {
708                 throw new IllegalArgumentException
709                     (EnvironmentParams.MAX_MEMORY.getName() +
710                      " has a value of " + newMaxMemory +
711                      " but the JVM is only configured for " +
712                      jvmMemory +
713                      ". Consider using je.maxMemoryPercent.");
714             }
715             if (newMaxMemory < MIN_MAX_MEMORY_SIZE) {
716                 throw new IllegalArgumentException
717                     (EnvironmentParams.MAX_MEMORY.getName() +
718                      " is " + newMaxMemory +
719                      " which is less than the minimum: " +
720                      MIN_MAX_MEMORY_SIZE);
721             }
722         } else {
723 
724             /*
725              * When no explicit cache size is specified and the JVM memory size
726              * is unknown, assume a default sized (64 MB) heap.  This produces
727              * a reasonable cache size when no heap size is known.
728              */
729             if (jvmMemory == Long.MAX_VALUE) {
730                 jvmMemory = N_64MB;
731             }
732 
733             /* Use the configured percentage of the JVM memory size. */
734             int maxMemoryPercent =
735                 configManager.getInt(EnvironmentParams.MAX_MEMORY_PERCENT);
736             newMaxMemory = (maxMemoryPercent * jvmMemory) / 100;
737         }
738 
739         return newMaxMemory;
740     }
741 
742     /**
743      * Initialize at construction time and when the cache is resized.
744      *
745      * @param newMaxMemory is the new total cache budget or is less than 0 if
746      * the total should remain unchanged.
747      *
748      * @param newEnv is true if this is the first time we are resetting the
749      * budget for a new environment.  Note that a new environment has not yet
750      * been added to the set of shared cache environments.
751      */
reset(long newMaxMemory, boolean newEnv, DbConfigManager configManager)752     void reset(long newMaxMemory,
753                boolean newEnv,
754                DbConfigManager configManager)
755         throws DatabaseException {
756 
757         long oldLogBufferBudget = logBufferBudget;
758 
759         /*
760          * Update the new total cache budget.
761          */
762         if (newMaxMemory < 0) {
763             newMaxMemory = getMaxMemory();
764         } else {
765             totals.setMaxMemory(newMaxMemory);
766         }
767 
768         /*
769          * This environment's portion is adjusted for a shared cache.  Further
770          * below we make buffer and tracker sizes a fixed percentage (7% and
771          * 2%, by default) of the total shared cache size.  The math for this
772          * starts by dividing the total size by number of environments to get
773          * myCachePortion.  Then we take 7% or 2% of myCachePortion to get each
774          * environment's portion.  In other words, if there are 10 environments
775          * then each gets 7%/10 and 2%/10 of the total cache size, by default.
776          *
777          * Note that when we resize the shared cache, we resize the buffer
778          * pools and tracker budgets for all environments.  Resizing the
779          * tracker budget has no overhead, but resizing the buffer pools causes
780          * new buffers to be allocated.  If reallocation of the log buffers is
781          * not desirable, the user can configure a byte amount rather than a
782          * percentage.
783          */
784         long myCachePortion;
785         if (envImpl.getSharedCache()) {
786             int nEnvs = DbEnvPool.getInstance().getNSharedCacheEnvironments();
787             if (newEnv) {
788                 nEnvs += 1;
789             }
790             myCachePortion = newMaxMemory / nEnvs;
791         } else {
792             myCachePortion = newMaxMemory;
793         }
794 
795         /*
796          * Calculate the memory budget for log buffering.  If the LOG_MEM_SIZE
797          * parameter is not set, start by using 7% (1/16th) of the cache
798          * size. If it is set, use that explicit setting.
799          *
800          * No point in having more log buffers than the maximum size. If
801          * this starting point results in overly large log buffers,
802          * reduce the log buffer budget again.
803          */
804         long newLogBufferBudget =
805             configManager.getLong(EnvironmentParams.LOG_MEM_SIZE);
806         if (newLogBufferBudget == 0) {
807             newLogBufferBudget = myCachePortion >> 4;
808         } else if (newLogBufferBudget > myCachePortion / 2) {
809             newLogBufferBudget = myCachePortion / 2;
810         }
811 
812         /*
813          * We have a first pass at the log buffer budget. See what
814          * size log buffers result. Don't let them be too big, it would
815          * be a waste.
816          */
817         int numBuffers =
818             configManager.getInt(EnvironmentParams.NUM_LOG_BUFFERS);
819         long startingBufferSize = newLogBufferBudget / numBuffers;
820         int logBufferSize =
821             configManager.getInt(EnvironmentParams.LOG_BUFFER_MAX_SIZE);
822         if (startingBufferSize > logBufferSize) {
823             startingBufferSize = logBufferSize;
824             newLogBufferBudget = numBuffers * startingBufferSize;
825         } else if (startingBufferSize <
826                    EnvironmentParams.MIN_LOG_BUFFER_SIZE) {
827             startingBufferSize = EnvironmentParams.MIN_LOG_BUFFER_SIZE;
828             newLogBufferBudget = numBuffers * startingBufferSize;
829         }
830 
831         long newCriticalThreshold =
832             (newMaxMemory *
833              envImpl.getConfigManager().getInt
834                 (EnvironmentParams.EVICTOR_CRITICAL_PERCENTAGE))/100;
835 
836         long newTrackerBudget =
837             (myCachePortion *
838              envImpl.getConfigManager().getInt
839                 (EnvironmentParams.CLEANER_DETAIL_MAX_MEMORY_PERCENTAGE))/100;
840 
841         long newMinTreeMemoryUsage = Math.min
842             (configManager.getLong(EnvironmentParams.MIN_TREE_MEMORY),
843              myCachePortion - newLogBufferBudget);
844 
845         /*
846          * If all has gone well, update the budget fields.  Once the log buffer
847          * budget is determined, the remainder of the memory is left for tree
848          * nodes.
849          */
850         logBufferBudget = newLogBufferBudget;
851         totals.setCriticalThreshold(newCriticalThreshold);
852         trackerBudget = newTrackerBudget;
853         minTreeMemoryUsage = newMinTreeMemoryUsage;
854 
855         /* The log buffer budget is counted in the cache usage. */
856         totals.updateCacheUsage(logBufferBudget - oldLogBufferBudget);
857 
858         /*
859          * Only reset the log buffer pool if the log buffer has already been
860          * initialized (we're updating an existing budget) and the log buffer
861          * budget has changed (resetting it is expensive and may cause I/O).
862          */
863         if (!newEnv && oldLogBufferBudget != logBufferBudget) {
864             envImpl.getLogManager().resetPool(configManager);
865         }
866     }
867 
868     /**
869      * Returns Runtime.maxMemory(), accounting for a MacOS bug.
870      * May return Long.MAX_VALUE if there is no inherent limit.
871      * Used by unit tests as well as by this class.
872      */
getRuntimeMaxMemory()873     public static long getRuntimeMaxMemory() {
874 
875         /* Runtime.maxMemory is unreliable on MacOS Java 1.4.2. */
876         if ("Mac OS X".equals(System.getProperty("os.name"))) {
877             String jvmVersion = System.getProperty("java.version");
878             if (jvmVersion != null && jvmVersion.startsWith("1.4.2")) {
879                 return Long.MAX_VALUE; /* Undetermined heap size. */
880             }
881         }
882 
883         return Runtime.getRuntime().maxMemory();
884     }
885 
886     /**
887      * Initialize the starting environment memory state. We really only need to
888      * recalibrate the tree and treeAdmin categories, since there are no locks
889      * and txns yet, and the items in the admin category are cleaner items and
890      * aren't affected by the recovery splicing process.
891      */
initCacheMemoryUsage(long dbTreeAdminMemory)892     void initCacheMemoryUsage(long dbTreeAdminMemory)  {
893         long totalTree = 0;
894         long treeAdmin = 0;
895         for (IN in : envImpl.getInMemoryINs()) {
896             totalTree += in.getBudgetedMemorySize();
897             treeAdmin += in.getTreeAdminMemorySize();
898         }
899         refreshTreeMemoryUsage(totalTree);
900         refreshTreeAdminMemoryUsage(treeAdmin + dbTreeAdminMemory);
901     }
902 
903     /**
904      * Called by INList when clearing  tree memory usage.
905      */
refreshTreeAdminMemoryUsage(long newSize)906     void refreshTreeAdminMemoryUsage(long newSize) {
907         long oldSize = treeAdminMemoryUsage.getAndSet(newSize);
908         long diff = (newSize - oldSize);
909 
910         if (DEBUG_TREEADMIN) {
911             System.err.println("RESET = " + newSize);
912         }
913         if (totals.updateCacheUsage(diff)) {
914             envImpl.alertEvictor();
915         }
916     }
917 
918     /**
919      * Called by INList when recalculating tree memory usage.
920      */
refreshTreeMemoryUsage(long newSize)921     void refreshTreeMemoryUsage(long newSize) {
922         long oldSize = treeMemoryUsage.getAndSet(newSize);
923         long diff = (newSize - oldSize);
924 
925         if (totals.updateCacheUsage(diff)) {
926             envImpl.alertEvictor();
927         }
928     }
929 
930     /**
931      * Returns whether eviction of INList information is allowed.
932      * To prevent extreme cache churn, eviction of Btree information is
933      * prohibited unless the tree memory usage is above this minimum value.
934      */
isTreeUsageAboveMinimum()935     public boolean isTreeUsageAboveMinimum() {
936         return treeMemoryUsage.get() > minTreeMemoryUsage;
937     }
938 
939     /**
940      * For unit tests.
941      */
getMinTreeMemoryUsage()942     public long getMinTreeMemoryUsage() {
943         return minTreeMemoryUsage;
944     }
945 
946     /**
947      * Update the environment wide tree memory count, wake up the evictor if
948      * necessary.
949      * @param increment note that increment may be negative.
950      */
updateTreeMemoryUsage(long increment)951     public void updateTreeMemoryUsage(long increment) {
952         updateCounter(increment, treeMemoryUsage, "tree", DEBUG_TREE);
953     }
954 
955     /**
956      * Update the environment wide txn memory count, wake up the evictor if
957      * necessary.
958      * @param increment note that increment may be negative.
959      */
updateTxnMemoryUsage(long increment)960     public void updateTxnMemoryUsage(long increment) {
961         updateCounter(increment, txnMemoryUsage, "txn", DEBUG_TXN);
962     }
963 
964     /**
965      * Update the environment wide admin memory count, wake up the evictor if
966      * necessary.
967      * @param increment note that increment may be negative.
968      */
updateAdminMemoryUsage(long increment)969     public void updateAdminMemoryUsage(long increment) {
970         updateCounter(increment, adminMemoryUsage, "admin", DEBUG_ADMIN);
971     }
972 
973     /**
974      * Update the treeAdmin memory count, wake up the evictor if necessary.
975      * @param increment note that increment may be negative.
976      */
updateTreeAdminMemoryUsage(long increment)977     public void updateTreeAdminMemoryUsage(long increment) {
978         updateCounter(increment, treeAdminMemoryUsage, "treeAdmin",
979                       DEBUG_TREEADMIN);
980     }
981 
updateCounter(long increment, AtomicLong counter, String debugName, boolean debug)982     private void updateCounter(long increment,
983                                AtomicLong counter,
984                                String debugName,
985                                boolean debug) {
986         if (increment != 0) {
987             long newSize = counter.addAndGet(increment);
988 
989             assert (sizeNotNegative(newSize)) :
990                    makeErrorMessage(debugName, newSize, increment);
991 
992             if (debug) {
993                 if (increment > 0) {
994                     System.err.println("INC-------- =" + increment + " " +
995                                        debugName + " "  + newSize);
996                 } else {
997                     System.err.println("-------DEC=" + increment + " " +
998                                        debugName + " "  + newSize);
999                 }
1000             }
1001 
1002             if (totals.updateCacheUsage(increment)) {
1003                 envImpl.alertEvictor();
1004             }
1005         }
1006     }
1007 
sizeNotNegative(long newSize)1008     private boolean sizeNotNegative(long newSize) {
1009 
1010         if (CLEANUP_DONE)  {
1011             return (newSize >= 0);
1012         }
1013     	return true;
1014     }
1015 
updateLockMemoryUsage(long increment, int lockTableIndex)1016     public void updateLockMemoryUsage(long increment, int lockTableIndex) {
1017         if (increment != 0) {
1018             lockMemoryUsage.addAndGet(increment);
1019 
1020             assert lockMemoryUsage.get() >= 0:
1021                    makeErrorMessage("lockMem",
1022                                     lockMemoryUsage.get(),
1023                                     increment);
1024             if (DEBUG_LOCK) {
1025                 if (increment > 0) {
1026                     System.err.println("INC-------- =" + increment +
1027                                        " lock[" +
1028                                        lockTableIndex + "] " +
1029                                        lockMemoryUsage.get());
1030                 } else {
1031                     System.err.println("-------DEC=" + increment +
1032                                        " lock[" + lockTableIndex + "] " +
1033                                        lockMemoryUsage.get());
1034                 }
1035             }
1036 
1037             if (totals.updateCacheUsage(increment)) {
1038                 envImpl.alertEvictor();
1039             }
1040         }
1041     }
1042 
makeErrorMessage(String memoryType, long total, long increment)1043     private String makeErrorMessage(String memoryType,
1044                                     long total,
1045                                     long increment) {
1046         return memoryType + "=" + total +
1047             " increment=" + increment + " " +
1048             LoggerUtils.getStackTrace(new Throwable());
1049     }
1050 
subtractCacheUsage()1051     void subtractCacheUsage() {
1052         totals.updateCacheUsage(0 - getLocalCacheUsage());
1053     }
1054 
getLocalCacheUsage()1055     private long getLocalCacheUsage() {
1056         return logBufferBudget +
1057                treeMemoryUsage.get() +
1058                adminMemoryUsage.get() +
1059                treeAdminMemoryUsage.get() +
1060                getLockMemoryUsage();
1061     }
1062 
getVariableCacheUsage()1063     long getVariableCacheUsage() {
1064         return treeMemoryUsage.get() +
1065             adminMemoryUsage.get() +
1066             treeAdminMemoryUsage.get() +
1067             getLockMemoryUsage();
1068     }
1069 
1070     /**
1071      * Public for unit testing.
1072      */
getLockMemoryUsage()1073     public long getLockMemoryUsage() {
1074         long accLockMemoryUsage =
1075             txnMemoryUsage.get() + lockMemoryUsage.get();
1076 
1077         return accLockMemoryUsage;
1078     }
1079 
1080     /*
1081      * The following 2 methods are shorthand for getTotals.getXxx().
1082      */
1083 
getCacheMemoryUsage()1084     public long getCacheMemoryUsage() {
1085         return totals.getCacheUsage();
1086     }
1087 
getMaxMemory()1088     public long getMaxMemory() {
1089         return totals.getMaxMemory();
1090     }
1091 
1092     /**
1093      * Used for unit testing.
1094      */
getTreeMemoryUsage()1095     public long getTreeMemoryUsage() {
1096         return treeMemoryUsage.get();
1097     }
1098 
1099     /**
1100      * Used for unit testing.
1101      */
getAdminMemoryUsage()1102     public long getAdminMemoryUsage() {
1103         return adminMemoryUsage.get();
1104     }
1105 
1106     /*
1107      * For unit testing
1108      */
getTreeAdminMemoryUsage()1109     public long getTreeAdminMemoryUsage() {
1110         return treeAdminMemoryUsage.get();
1111     }
1112 
getLogBufferBudget()1113     public long getLogBufferBudget() {
1114         return logBufferBudget;
1115     }
1116 
getTrackerBudget()1117     public long getTrackerBudget() {
1118         return trackerBudget;
1119     }
1120 
tupleOutputSize(TupleOutput o)1121     public static int tupleOutputSize(TupleOutput o) {
1122         return TUPLE_OUTPUT_OVERHEAD +
1123                byteArraySize(o.getBufferBytes().length);
1124     }
1125 
1126     /**
1127      * Returns the memory size occupied by a byte array of a given length.  All
1128      * arrays (regardless of element type) have the same overhead for a zero
1129      * length array.  On 32b Java, there are 4 bytes included in that fixed
1130      * overhead that can be used for the first N elements -- however many fit
1131      * in 4 bytes.  On 64b Java, there is no extra space included.  In all
1132      * cases, space is allocated in 8 byte chunks.
1133      */
byteArraySize(int arrayLen)1134     public static int byteArraySize(int arrayLen) {
1135 
1136         /*
1137          * ARRAY_OVERHEAD accounts for N bytes of data, which is 4 bytes on 32b
1138          * Java and 0 bytes on 64b Java.  Data larger than N bytes is allocated
1139          * in 8 byte increments.
1140          */
1141         int size = ARRAY_OVERHEAD;
1142         if (arrayLen > ARRAY_SIZE_INCLUDED) {
1143             size += ((arrayLen - ARRAY_SIZE_INCLUDED + 7) / 8) * 8;
1144         }
1145 
1146         return size;
1147     }
1148 
shortArraySize(int arrayLen)1149     public static int shortArraySize(int arrayLen) {
1150         return byteArraySize(arrayLen * 2);
1151     }
1152 
intArraySize(int arrayLen)1153     public static int intArraySize(int arrayLen) {
1154         return byteArraySize(arrayLen * 4);
1155     }
1156 
objectArraySize(int arrayLen)1157     public static int objectArraySize(int arrayLen) {
1158         return byteArraySize(arrayLen * OBJECT_ARRAY_ITEM_OVERHEAD);
1159     }
1160 
loadStats()1161     StatGroup loadStats() {
1162         StatGroup stats = new StatGroup(MB_GROUP_NAME, MB_GROUP_DESC);
1163         new LongStat(stats, MB_SHARED_CACHE_TOTAL_BYTES,
1164                      totals.isSharedCache() ? totals.getCacheUsage() : 0);
1165         new LongStat(stats, MB_TOTAL_BYTES, getLocalCacheUsage());
1166         new LongStat(stats, MB_DATA_BYTES,
1167                      treeMemoryUsage.get() + treeAdminMemoryUsage.get());
1168         new LongStat(stats, MB_DATA_ADMIN_BYTES, treeAdminMemoryUsage.get());
1169         new LongStat(stats, MB_ADMIN_BYTES, adminMemoryUsage.get());
1170         new LongStat(stats, MB_LOCK_BYTES, getLockMemoryUsage());
1171 
1172         return stats;
1173     }
1174 
1175     @Override
toString()1176     public String toString() {
1177         StringBuilder sb = new StringBuilder();
1178         sb.append("treeUsage = ").append(treeMemoryUsage.get());
1179         sb.append("treeAdminUsage = ").append(treeAdminMemoryUsage.get());
1180         sb.append("adminUsage = ").append(adminMemoryUsage.get());
1181         sb.append("txnUsage = ").append(txnMemoryUsage.get());
1182         sb.append("lockUsage = ").append(getLockMemoryUsage());
1183         return sb.toString();
1184     }
1185 
getTotals()1186     public Totals getTotals() {
1187         return totals;
1188     }
1189 
1190     /**
1191      * Common base class for shared and private totals.  This abstraction
1192      * allows most other classes to be unaware of whether we're using a
1193      * SharedEvictor or PrivateEvictor.
1194      */
1195     public abstract static class Totals {
1196 
1197         long maxMemory;
1198         private long criticalThreshold;
1199 
Totals()1200         private Totals() {
1201             maxMemory = 0;
1202         }
1203 
setMaxMemory(long maxMemory)1204         private final void setMaxMemory(long maxMemory) {
1205             this.maxMemory = maxMemory;
1206         }
1207 
getMaxMemory()1208         public final long getMaxMemory() {
1209             return maxMemory;
1210         }
1211 
setCriticalThreshold(long criticalThreshold)1212         private final void setCriticalThreshold(long criticalThreshold) {
1213             this.criticalThreshold = criticalThreshold;
1214         }
1215 
getCriticalThreshold()1216         public final long getCriticalThreshold() {
1217             return criticalThreshold;
1218         }
1219 
getCacheUsage()1220         public abstract long getCacheUsage();
updateCacheUsage(long increment)1221         abstract boolean updateCacheUsage(long increment);
isSharedCache()1222         abstract boolean isSharedCache();
1223     }
1224 
1225     /**
1226      * Totals for a single environment's non-shared cache.  Used when
1227      * EnvironmentConfig.setSharedCache(false) and a PrivateEvictor are used.
1228      */
1229     private static class PrivateTotals extends Totals {
1230 
1231         private final MemoryBudget parent;
1232 
PrivateTotals(MemoryBudget parent)1233         private PrivateTotals(MemoryBudget parent) {
1234             this.parent = parent;
1235         }
1236 
1237         @Override
getCacheUsage()1238         public final long getCacheUsage() {
1239             return parent.getLocalCacheUsage();
1240         }
1241 
1242         @Override
updateCacheUsage(long increment)1243         final boolean updateCacheUsage(long increment) {
1244             return (parent.getLocalCacheUsage() > maxMemory);
1245         }
1246 
1247         @Override
isSharedCache()1248         final boolean isSharedCache() {
1249             return false;
1250         }
1251     }
1252 
1253     /**
1254      * Totals for the multi-environment shared cache.  Used when
1255      * EnvironmentConfig.setSharedCache(false) and the SharedEvictor are used.
1256      */
1257     private static class SharedTotals extends Totals {
1258 
1259         private final AtomicLong usage;
1260 
SharedTotals()1261         private SharedTotals() {
1262             usage = new AtomicLong();
1263         }
1264 
1265         @Override
getCacheUsage()1266         public final long getCacheUsage() {
1267             return usage.get();
1268         }
1269 
1270         @Override
updateCacheUsage(long increment)1271         final boolean updateCacheUsage(long increment) {
1272             return (usage.addAndGet(increment) > maxMemory);
1273         }
1274 
1275         @Override
isSharedCache()1276         final boolean isSharedCache() {
1277             return true;
1278         }
1279     }
1280 }
1281