Merge lp:~pbeaman/akiban-persistit/buffer-pool-warmup-sorted into lp:akiban-persistit
- buffer-pool-warmup-sorted
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~pbeaman/akiban-persistit/buffer-pool-warmup-sorted |
Merge into: | lp:akiban-persistit |
Prerequisite: | lp:~pbeaman/akiban-persistit/eclipse-canonical-format |
Diff against target: |
1315 lines (+654/-247) 15 files modified
doc/Configuration.rst (+13/-1) src/main/java/com/persistit/BufferPool.java (+144/-109) src/main/java/com/persistit/CheckpointManager.java (+2/-1) src/main/java/com/persistit/Configuration.java (+72/-72) src/main/java/com/persistit/JournalManager.java (+45/-22) src/main/java/com/persistit/MediatedFileChannel.java (+1/-1) src/main/java/com/persistit/Persistit.java (+22/-9) src/main/java/com/persistit/logging/LogBase.java (+9/-0) src/test/java/com/persistit/IOFailureTest.java (+1/-1) src/test/java/com/persistit/StressRunner.java (+2/-0) src/test/java/com/persistit/TrackingFileChannel.java (+175/-0) src/test/java/com/persistit/WarmupTest.java (+84/-29) src/test/java/com/persistit/stress/PreloadMixtureTxn1.java (+82/-0) src/test/java/com/persistit/unit/PersistitUnitTestCase.java (+2/-1) src/test/java/com/persistit/unit/UnitTestProperties.java (+0/-1) |
To merge this branch: | bzr merge lp:~pbeaman/akiban-persistit/buffer-pool-warmup-sorted |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Akiban Technologies | Pending | ||
Review via email: mp+121091@code.launchpad.net |
This proposal has been superseded by a proposal from 2012-08-24.
Commit message
Description of the change
This proposal is a re-work of the original buffer pool warm-up code. Instead of creating a text file, this version stores the inventory in the system volume. It also loads pages in file-address order to reduce I/O time. There is a new stress test that pushes this into a medium-sized buffer pool (25K pages) but we still need to test it with a 1M page pool in TPCC or some other big test.
There are two config options, one to turn on inventory recording and the other to enable pre-loading pages. They are separate so that a server can start up without waiting for the pre-load but still be set to perform the inventory function.
Other changes include Configuration, Configuration.rst (documentation), etc.
- 383. By Peter Beaman
-
Merge from release-notes-3.16
- 384. By Peter Beaman
-
Fix failures in WarmupTest
- 385. By Peter Beaman
-
Fix WarmupTest (again)
Unmerged revisions
Preview Diff
1 | === modified file 'doc/Configuration.rst' |
2 | --- doc/Configuration.rst 2012-06-11 21:25:37 +0000 |
3 | +++ doc/Configuration.rst 2012-08-23 21:28:19 +0000 |
4 | @@ -221,7 +221,7 @@ |
5 | ``serialOverride``, ``constructorOverride``: (``com.persistit.Configuration#setSerialOverride`` ``com.persistit.Configuration#setConstructorOverride``) |
6 | Control aspects of object serialization. See :ref:`Serialization`. |
7 | |
8 | - ``showgui``: (``com.persistit.Configuration#setShowGUI``), True of False. |
9 | + ``showgui``: (``com.persistit.Configuration#setShowGUI``), True or False (default). |
10 | If true, Persistit attempts to create and display an instance of the AdminUI utility panel within the current JVM. |
11 | Alternatively, AdminUI uses RMI and can be launched and run remotely if ``rmiport`` or ``rmihost`` has been |
12 | specified. |
13 | @@ -231,6 +231,18 @@ |
14 | install a logging adapter to reroute messages through Log4J, SLF4J or other logger. The ``logfile`` property is used |
15 | only when no adapter has been installed. |
16 | |
17 | + ``bufferinventory``: (``com.persistit.Configuration#setBufferInventoryEnabled``), True or False (default). |
18 | + If true, Persistit periodically records an inventory of all the buffes in the buffers pools to the System Volume. The inventory |
19 | + enables Persistit to preload the buffer pools then next time it starts up with approximately the same pages that were present |
20 | + before shutdown. To enable buffer preloading, the bufferpreload property must also be true. |
21 | + |
22 | + ``bufferpreload``: (``com.persistit.Configuration#setBufferPreloadEnabled``), True or False (default). |
23 | + If true, and if a buffer pool inventory was previously recorded, Persistit attempts to "warm up" the buffer pool |
24 | + by preloading pages that were present in the buffer pool when Persistit last shut down. This may allow a freshly started |
25 | + Persistit instance to begin service a workload similar to what it had previously been processing without incurring the |
26 | + cost of many random disk reads to load pages. |
27 | + |
28 | + |
29 | For all integer-valued properties, the suffix “K” may be used to represent kilo, “M” for mega, “G” for giga and “T” for tera. For example, “2M” represents the value 2,097,152. |
30 | |
31 | A Configuration Example |
32 | |
33 | === modified file 'src/main/java/com/persistit/BufferPool.java' |
34 | --- src/main/java/com/persistit/BufferPool.java 2012-08-23 21:28:19 +0000 |
35 | +++ src/main/java/com/persistit/BufferPool.java 2012-08-23 21:28:19 +0000 |
36 | @@ -15,16 +15,14 @@ |
37 | |
38 | package com.persistit; |
39 | |
40 | -import java.io.BufferedReader; |
41 | -import java.io.BufferedWriter; |
42 | import java.io.DataOutputStream; |
43 | -import java.io.File; |
44 | -import java.io.FileReader; |
45 | -import java.io.FileWriter; |
46 | import java.io.IOException; |
47 | import java.nio.ByteBuffer; |
48 | +import java.util.ArrayList; |
49 | import java.util.Arrays; |
50 | +import java.util.Collections; |
51 | import java.util.HashSet; |
52 | +import java.util.List; |
53 | import java.util.Set; |
54 | import java.util.concurrent.atomic.AtomicBoolean; |
55 | import java.util.concurrent.atomic.AtomicInteger; |
56 | @@ -32,6 +30,7 @@ |
57 | import java.util.concurrent.atomic.AtomicLongArray; |
58 | import java.util.concurrent.locks.ReentrantLock; |
59 | |
60 | +import com.persistit.JournalManager.PageNode; |
61 | import com.persistit.exception.InUseException; |
62 | import com.persistit.exception.InvalidPageAddressException; |
63 | import com.persistit.exception.InvalidPageStructureException; |
64 | @@ -92,6 +91,17 @@ |
65 | */ |
66 | private final static int WRITE_AGE_THRESHOLD_RATIO = 4; |
67 | |
68 | + private final static String INVENTORY_TREE_NAME = "_buffers"; |
69 | + /** |
70 | + * Maximum number of buffer inventory versions to retain |
71 | + */ |
72 | + private final static int INVENTORY_VERSIONS = 3; |
73 | + |
74 | + /** |
75 | + * Preload log multiple |
76 | + */ |
77 | + private final static int INVENTORY_PRELOAD_LOG_MESSAGE_MULTIPLE = 10000; |
78 | + |
79 | /** |
80 | * The Persistit instance that references this BufferPool. |
81 | */ |
82 | @@ -203,23 +213,11 @@ |
83 | private volatile int _pageWriterTrancheSize = PAGE_WRITER_TRANCHE_SIZE; |
84 | |
85 | /** |
86 | - * Polling interval for PageCacher |
87 | - */ |
88 | - private volatile long _cacherPollInterval; |
89 | - |
90 | - /** |
91 | * The PAGE_WRITER IOTaskRunnable |
92 | */ |
93 | private PageWriter _writer; |
94 | |
95 | /** |
96 | - * The PAGE_CACHER IOTaskRunnable |
97 | - */ |
98 | - private PageCacher _cacher; |
99 | - |
100 | - private String _defaultLogPath; |
101 | - |
102 | - /** |
103 | * Construct a BufferPool with the specified count of <code>Buffer</code>s |
104 | * of the specified size. |
105 | * |
106 | @@ -289,37 +287,6 @@ |
107 | throw e; |
108 | } |
109 | _writer = new PageWriter(); |
110 | - _cacher = new PageCacher(); |
111 | - } |
112 | - |
113 | - void warmupBufferPool(final String pathName, final String fname) throws PersistitException { |
114 | - final File file = new File(pathName, fname + ".log"); |
115 | - _defaultLogPath = file.getAbsolutePath(); |
116 | - |
117 | - try { |
118 | - if (!file.exists()) { |
119 | - file.createNewFile(); |
120 | - } |
121 | - |
122 | - final BufferedReader reader = new BufferedReader(new FileReader(file)); |
123 | - String currLine; |
124 | - while ((currLine = reader.readLine()) != null) { |
125 | - final String[] info = currLine.split(" "); |
126 | - if (info.length == 2) { |
127 | - final Volume vol = _persistit.getVolume(info[1]); |
128 | - if (vol != null) { |
129 | - final long page = Long.parseLong(info[0]); |
130 | - final Buffer buff = get(vol, page, false, true); |
131 | - buff.release(); |
132 | - } |
133 | - } |
134 | - } |
135 | - reader.close(); |
136 | - _cacherPollInterval = _persistit.getConfiguration().getBufferInventoryPollingInterval(); |
137 | - _cacher.start(); |
138 | - } catch (final IOException e) { |
139 | - throw new PersistitException(e); |
140 | - } |
141 | } |
142 | |
143 | void startThreads() throws PersistitException { |
144 | @@ -329,9 +296,7 @@ |
145 | void close() { |
146 | _closed.set(true); |
147 | _persistit.waitForIOTaskStop(_writer); |
148 | - _persistit.waitForIOTaskStop(_cacher); |
149 | _writer = null; |
150 | - _cacher = null; |
151 | } |
152 | |
153 | /** |
154 | @@ -340,7 +305,6 @@ |
155 | */ |
156 | void crash() { |
157 | IOTaskRunnable.crash(_writer); |
158 | - IOTaskRunnable.crash(_cacher); |
159 | } |
160 | |
161 | void flush(final long timestamp) throws PersistitInterruptedException { |
162 | @@ -433,35 +397,6 @@ |
163 | } |
164 | } |
165 | |
166 | - private void populateWarmupFile() throws PersistitException { |
167 | - final File file = new File(_defaultLogPath); |
168 | - |
169 | - try { |
170 | - final BufferedWriter writer = new BufferedWriter(new FileWriter(file)); |
171 | - for (int i = 0; i < _buffers.length; ++i) { |
172 | - final Buffer b = _buffers[i]; |
173 | - if (b != null && b.isValid() && !b.isDirty()) { |
174 | - final long page = b.getPageAddress(); |
175 | - final Volume volume = b.getVolume(); |
176 | - final long page2 = b.getPageAddress(); |
177 | - final Volume volume2 = b.getVolume(); |
178 | - |
179 | - // Check if buffer has changed while reading |
180 | - if (page == page2 && volume == volume2 && volume != null) { |
181 | - final String addr = Long.toString(page); |
182 | - final String vol = volume.getName(); |
183 | - writer.append(addr + " " + vol); |
184 | - writer.newLine(); |
185 | - writer.flush(); |
186 | - } |
187 | - } |
188 | - } |
189 | - writer.close(); |
190 | - } catch (final IOException e) { |
191 | - throw new PersistitException(e); |
192 | - } |
193 | - } |
194 | - |
195 | private boolean selected(final Buffer buffer, final int includeMask, final int excludeMask) { |
196 | return ((includeMask == 0) || (buffer.getStatus() & includeMask) != 0) |
197 | && (buffer.getStatus() & excludeMask) == 0; |
198 | @@ -1403,35 +1338,6 @@ |
199 | } |
200 | } |
201 | |
202 | - /** |
203 | - * Implementation of PAGE_CACHER thread |
204 | - */ |
205 | - class PageCacher extends IOTaskRunnable { |
206 | - |
207 | - PageCacher() { |
208 | - super(BufferPool.this._persistit); |
209 | - } |
210 | - |
211 | - void start() { |
212 | - start("PAGE_CACHER:" + _bufferSize, _cacherPollInterval); |
213 | - } |
214 | - |
215 | - @Override |
216 | - public void runTask() throws Exception { |
217 | - populateWarmupFile(); |
218 | - } |
219 | - |
220 | - @Override |
221 | - protected boolean shouldStop() { |
222 | - return _closed.get() && !isFlushing(); |
223 | - } |
224 | - |
225 | - @Override |
226 | - protected long pollInterval() { |
227 | - return isFlushing() ? 0 : _cacherPollInterval; |
228 | - } |
229 | - } |
230 | - |
231 | @Override |
232 | public String toString() { |
233 | return "BufferPool[" + _bufferCount + "@" + _bufferSize + (_closed.get() ? ":closed" : "") + "]"; |
234 | @@ -1486,4 +1392,133 @@ |
235 | } |
236 | stream.flush(); |
237 | } |
238 | + |
239 | + void recordBufferInventory(final long timestamp) throws PersistitException { |
240 | + final Exchange exchange = getBufferInventoryExchange(); |
241 | + /* |
242 | + * Advisory only - transaction integrity not needed |
243 | + */ |
244 | + exchange.ignoreTransactions(); |
245 | + try { |
246 | + int total = 0; |
247 | + exchange.clear().append(_bufferSize).append(timestamp).append(Key.BEFORE); |
248 | + final Value value = exchange.getValue(); |
249 | + final int clockValueBefore = _clock.get(); |
250 | + for (int index = 0; index < _buffers.length; index++) { |
251 | + final Buffer buffer = _buffers[index]; |
252 | + long page1 = -1, page2 = -1; |
253 | + Volume volume1 = null, volume2 = null; |
254 | + if (buffer != null && buffer.isValid()) { |
255 | + while (true) { |
256 | + page1 = buffer.getPageAddress(); |
257 | + volume1 = buffer.getVolume(); |
258 | + page2 = buffer.getPageAddress(); |
259 | + volume2 = buffer.getVolume(); |
260 | + if (page1 == page2 && volume1 == volume2) { |
261 | + break; |
262 | + } |
263 | + Util.spinSleep(); |
264 | + } |
265 | + if (volume1 != null && !volume1.isTemporary()) { |
266 | + value.clear().setStreamMode(true); |
267 | + value.put(volume1.getHandle()); |
268 | + value.put(page1); |
269 | + exchange.to(index).store(); |
270 | + total++; |
271 | + } |
272 | + } |
273 | + } |
274 | + final int clockValueAfter = _clock.get(); |
275 | + exchange.cut(); |
276 | + value.clear().setStreamMode(true); |
277 | + value.put(_bufferCount); |
278 | + value.put(total); |
279 | + value.put(clockValueBefore); |
280 | + value.put(clockValueAfter); |
281 | + value.put(System.currentTimeMillis()); |
282 | + exchange.store(); |
283 | + int count = 0; |
284 | + while (exchange.previous()) { |
285 | + if (++count > INVENTORY_VERSIONS) { |
286 | + exchange.remove(Key.GTEQ); |
287 | + } |
288 | + } |
289 | + } catch (final PersistitException e) { |
290 | + _persistit.getLogBase().bufferInventoryException.log(e); |
291 | + } |
292 | + } |
293 | + |
294 | + void preloadBufferInventory() { |
295 | + int count = 0; |
296 | + int total = 0; |
297 | + try { |
298 | + final JournalManager jman = _persistit.getJournalManager(); |
299 | + final Exchange exchange = getBufferInventoryExchange(); |
300 | + final Value value = exchange.getValue(); |
301 | + final List<PageNode> pageNodes = new ArrayList<PageNode>(); |
302 | + boolean foundInventory = false; |
303 | + exchange.clear().append(_bufferSize).append(Key.AFTER); |
304 | + while (exchange.previous()) { |
305 | + if (exchange.getValue().isDefined()) { |
306 | + foundInventory = true; |
307 | + break; |
308 | + } |
309 | + } |
310 | + if (!foundInventory) { |
311 | + return; |
312 | + } |
313 | + value.setStreamMode(true); |
314 | + /* int bufferCount = */value.getInt(); |
315 | + total = value.getInt(); |
316 | + /* int clockValueBefore = */value.getInt(); |
317 | + /* int clockValueAfter = */value.getInt(); |
318 | + final long systemTime = value.getLong(); |
319 | + |
320 | + _persistit.getLogBase().bufferInventoryLoad.log(systemTime); |
321 | + |
322 | + exchange.append(Key.BEFORE); |
323 | + |
324 | + while (exchange.next()) { |
325 | + value.setStreamMode(true); |
326 | + final int volumeHandle = value.getInt(); |
327 | + final long pageAddress = value.getLong(); |
328 | + final PageNode pn = new PageNode(volumeHandle, pageAddress); |
329 | + pageNodes.add(pn); |
330 | + } |
331 | + |
332 | + Collections.sort(pageNodes, PageNode.READ_COMPARATOR); |
333 | + for (final PageNode pn : pageNodes) { |
334 | + final Volume vol = jman.volumeForHandle(pn.getVolumeHandle()); |
335 | + if (vol == null) { |
336 | + continue; |
337 | + } |
338 | + try { |
339 | + final Buffer buff = get(vol, pn.getPageAddress(), false, true); |
340 | + buff.release(); |
341 | + count++; |
342 | + if ((count % INVENTORY_PRELOAD_LOG_MESSAGE_MULTIPLE) == 0) { |
343 | + _persistit.getLogBase().bufferInventoryProgress.log(count, total); |
344 | + } |
345 | + if (count >= _bufferCount) { |
346 | + // |
347 | + // If the buffer pool is now smaller, no need to load |
348 | + // more pages |
349 | + // |
350 | + break; |
351 | + } |
352 | + } catch (final PersistitException e) { |
353 | + // ignore it |
354 | + } |
355 | + } |
356 | + } catch (final PersistitException e) { |
357 | + _persistit.getLogBase().bufferInventoryException.log(e); |
358 | + } finally { |
359 | + _persistit.getLogBase().bufferInventoryProgress.log(count, total); |
360 | + } |
361 | + } |
362 | + |
363 | + private Exchange getBufferInventoryExchange() throws PersistitException { |
364 | + final Volume sysvol = _persistit.getSystemVolume(); |
365 | + return _persistit.getExchange(sysvol, INVENTORY_TREE_NAME, true); |
366 | + } |
367 | } |
368 | |
369 | === modified file 'src/main/java/com/persistit/CheckpointManager.java' |
370 | --- src/main/java/com/persistit/CheckpointManager.java 2012-08-23 21:28:19 +0000 |
371 | +++ src/main/java/com/persistit/CheckpointManager.java 2012-08-23 21:28:19 +0000 |
372 | @@ -201,6 +201,7 @@ |
373 | void pollCreateCheckpoint() throws PersistitException { |
374 | final long now = System.nanoTime(); |
375 | if (_lastCheckpointNanos + _checkpointIntervalNanos < now) { |
376 | + _persistit.recordBufferPoolInventory(); |
377 | createCheckpoint(); |
378 | } |
379 | } |
380 | @@ -252,12 +253,12 @@ |
381 | _currentCheckpoint = new Checkpoint(txn.getStartTimestamp(), System.currentTimeMillis()); |
382 | _outstandingCheckpoints.add(_currentCheckpoint); |
383 | _persistit.getLogBase().checkpointProposed.log(_currentCheckpoint); |
384 | - return _currentCheckpoint; |
385 | } catch (final InterruptedException ie) { |
386 | throw new PersistitInterruptedException(ie); |
387 | } finally { |
388 | txn.end(); |
389 | } |
390 | + return _currentCheckpoint; |
391 | } finally { |
392 | _persistit.setSessionId(saveSessionId); |
393 | } |
394 | |
395 | === modified file 'src/main/java/com/persistit/Configuration.java' |
396 | --- src/main/java/com/persistit/Configuration.java 2012-08-23 21:28:19 +0000 |
397 | +++ src/main/java/com/persistit/Configuration.java 2012-08-23 21:28:19 +0000 |
398 | @@ -263,7 +263,7 @@ |
399 | /** |
400 | * Property name for the "append only" property. |
401 | */ |
402 | - public final static String APPEND_ONLY_PROPERTY = "appendonly"; |
403 | + public final static String APPEND_ONLY_PROPERTY_NAME = "appendonly"; |
404 | |
405 | /** |
406 | * Property name for the "ignore missing volumes" property. |
407 | @@ -276,12 +276,15 @@ |
408 | public final static String SPLIT_POLICY_PROPERTY_NAME = "splitpolicy"; |
409 | |
410 | /** |
411 | - * Property name to specify the"buffer inventory" property name. |
412 | + * Property name to specify whether buffer preloading is enabled. |
413 | + */ |
414 | + public final static String BUFFER_PRELOAD_PROPERTY_NAME = "bufferpreload"; |
415 | + |
416 | + /** |
417 | + * Property name to specify whether buffer inventory is enabled. |
418 | */ |
419 | public final static String BUFFER_INVENTORY_PROPERTY_NAME = "bufferinventory"; |
420 | |
421 | - public final static String BUFFER_POLLING_INTERVAL_PROPERTY = "bufferpollinginterval"; |
422 | - |
423 | /** |
424 | * Property name to specify the default {@link JoinPolicy}. |
425 | */ |
426 | @@ -634,9 +637,8 @@ |
427 | private int rmiServerPort; |
428 | private boolean jmx = true; |
429 | private boolean appendOnly; |
430 | - private String bufferInventoryPathName; |
431 | - private long bufferInventoryPollInterval = 3000000; // default five minute |
432 | - // polling |
433 | + private boolean bufferInventoryEnabled; |
434 | + private boolean bufferPreloadEnabled; |
435 | private boolean ignoreMissingVolumes; |
436 | private String tmpVolDir; |
437 | private int tmpVolPageSize; |
438 | @@ -715,9 +717,7 @@ |
439 | } |
440 | |
441 | void loadProperties() throws InvalidVolumeSpecificationException { |
442 | - setBufferInventoryPathName(getProperty(BUFFER_INVENTORY_PROPERTY_NAME)); |
443 | - setBufferInventoryPollingInterval(getLongProperty(BUFFER_POLLING_INTERVAL_PROPERTY, bufferInventoryPollInterval)); |
444 | - setAppendOnly(getBooleanProperty(APPEND_ONLY_PROPERTY, false)); |
445 | + setAppendOnly(getBooleanProperty(APPEND_ONLY_PROPERTY_NAME, false)); |
446 | setCommitPolicy(getProperty(COMMIT_POLICY_PROPERTY_NAME)); |
447 | setConstructorOverride(getBooleanProperty(CONSTRUCTOR_OVERRIDE_PROPERTY_NAME, false)); |
448 | setIgnoreMissingVolumes(getBooleanProperty(IGNORE_MISSING_VOLUMES_PROPERTY, false)); |
449 | @@ -737,6 +737,8 @@ |
450 | setShowGUI(getBooleanProperty(SHOW_GUI_PROPERTY_NAME, false)); |
451 | setSplitPolicy(getProperty(SPLIT_POLICY_PROPERTY_NAME)); |
452 | setSysVolume(getProperty(SYSTEM_VOLUME_PROPERTY_NAME, DEFAULT_SYSTEM_VOLUME_NAME)); |
453 | + setBufferInventoryEnabled(getBooleanProperty(BUFFER_INVENTORY_PROPERTY_NAME, false)); |
454 | + setBufferPreloadEnabled(getBooleanProperty(BUFFER_PRELOAD_PROPERTY_NAME, false)); |
455 | |
456 | loadPropertiesBufferSpecifications(); |
457 | loadPropertiesVolumeSpecifications(); |
458 | @@ -1548,8 +1550,7 @@ |
459 | /** |
460 | * <p> |
461 | * Set a pattern that identifies classes to be serialized using standard |
462 | - * Java serialization rather than Persistit's default serialization. TODO |
463 | - * Link to Serialization section of user_guide.html. |
464 | + * Java serialization rather than Persistit's default serialization. |
465 | * </p> |
466 | * <p> |
467 | * Default value is <code>null</code><br /> |
468 | @@ -1559,6 +1560,8 @@ |
469 | * @param serialOverride |
470 | * the serial override pattern to set |
471 | * @see DefaultCoderManager |
472 | + * @see <a |
473 | + * href="http://www.akiban.com/ak-docs/admin/persistit/Serialization.html">Serialization</a> |
474 | */ |
475 | public void setSerialOverride(final String serialOverride) { |
476 | this.serialOverride = serialOverride; |
477 | @@ -1579,8 +1582,7 @@ |
478 | * a public no-argument constructor. If so, then that constructor is used |
479 | * when deserializing in the {@link DefaultObjectCoder}; if not then |
480 | * Persistit uses private methods within the JDK to emulate standard Java |
481 | - * serialization logic. TODO Link to Serialization section of |
482 | - * user_guide.html. |
483 | + * serialization logic. |
484 | * </p> |
485 | * <p> |
486 | * Default value is <code>false</code><br /> |
487 | @@ -1589,6 +1591,8 @@ |
488 | * |
489 | * @param constructorOverride |
490 | * the constructorOverride to set |
491 | + * @see <a |
492 | + * href="http://www.akiban.com/ak-docs/admin/persistit/Serialization.html">Serialization</a> |
493 | */ |
494 | public void setConstructorOverride(final boolean constructorOverride) { |
495 | this.constructorOverride = constructorOverride; |
496 | @@ -1791,7 +1795,7 @@ |
497 | /** |
498 | * Return the value defined by {@link #setAppendOnly} |
499 | * |
500 | - * @return the whether to start Persistit in append-only mode |
501 | + * @return <true>true</code> if append-only mode is enabled at startup |
502 | */ |
503 | public boolean isAppendOnly() { |
504 | return appendOnly; |
505 | @@ -1807,77 +1811,73 @@ |
506 | * </p> |
507 | * <p> |
508 | * Default value is <code>false</code><br /> |
509 | - * Property name is {@value #APPEND_ONLY_PROPERTY} |
510 | + * Property name is {@value #APPEND_ONLY_PROPERTY_NAME} |
511 | * </p> |
512 | * |
513 | * @param appendOnly |
514 | - * <code>true</code> to start Persistit in append-only only |
515 | + * <code>true</code> to start Persistit in append-only mode |
516 | */ |
517 | public void setAppendOnly(final boolean appendOnly) { |
518 | this.appendOnly = appendOnly; |
519 | } |
520 | |
521 | /** |
522 | - * Return the path name defined by {@link #getBufferInventoryPathName} |
523 | - * |
524 | - * @return the path where file to warm-up Persistit with sample buffer data |
525 | - * is stored |
526 | - */ |
527 | - public String getBufferInventoryPathName() { |
528 | - return bufferInventoryPathName; |
529 | - } |
530 | - |
531 | - /** |
532 | - * <p> |
533 | - * Control where Persistit stores its buffer inventory. In this mode |
534 | - * Persistit restarts with information from the last run. This method |
535 | - * initializes the warm-up file at the specified location, if none is |
536 | - * specified the buffer pool is not warmed up on start-up. |
537 | - * </p> |
538 | - * <p> |
539 | - * Default value is <code>null</code><br /> |
540 | - * Property name is {@value #BUFFER_INVENTORY_PROPERTY_NAME} |
541 | - * </p> |
542 | - * |
543 | - * @param pathName |
544 | - * the name of the path to the warm-up file |
545 | - */ |
546 | - public void setBufferInventoryPathName(final String pathName) { |
547 | - bufferInventoryPathName = pathName; |
548 | - |
549 | - } |
550 | - |
551 | - /** |
552 | - * Return polling interval defined by |
553 | - * {@link #getBufferInventoryPollingInterval} |
554 | - * |
555 | - * @return the number of seconds wait between warm-up polls |
556 | - */ |
557 | - public long getBufferInventoryPollingInterval() { |
558 | - return bufferInventoryPollInterval; |
559 | - } |
560 | - |
561 | - /** |
562 | - * <p> |
563 | - * Control the number of seconds between each poll for the cache warm-up |
564 | - * option in Persistit. |
565 | - * </p> |
566 | - * <p> |
567 | - * Default value is <code>3000</code><br /> |
568 | - * Property name is {@value #BUFFER_POLLING_INTERVAL_PROPERTY} |
569 | - * </p> |
570 | - * |
571 | - * @param seconds |
572 | - * the number of seconds between polls |
573 | - */ |
574 | - public void setBufferInventoryPollingInterval(final long seconds) { |
575 | - bufferInventoryPollInterval = Util.rangeCheck(seconds, 60L, Long.MAX_VALUE) * 1000L; |
576 | + * Return the value defined by {@link #setBufferInventoryEnabled} |
577 | + * |
578 | + * @return <code>true</code> if periodic buffer pool inventory recording is |
579 | + * enabled |
580 | + */ |
581 | + public boolean isBufferInventoryEnabled() { |
582 | + return bufferInventoryEnabled; |
583 | + } |
584 | + |
585 | + /** |
586 | + * <p> |
587 | + * Control whether Persistit periodically records an inventory of its buffer |
588 | + * pools to enable buffer pool preloading on a subsequent startup. |
589 | + * </p> |
590 | + * <p> |
591 | + * Default value is <code>false</code><br /> |
592 | + * Property name is {@value #BUFFER_INVENTORY_PROPERTY_NAME} |
593 | + * |
594 | + * @param bufferInventoryEnabled |
595 | + * <code>true</code> to enable periodic buffer inventory behavior |
596 | + */ |
597 | + public void setBufferInventoryEnabled(final boolean bufferInventoryEnabled) { |
598 | + this.bufferInventoryEnabled = bufferInventoryEnabled; |
599 | + } |
600 | + |
601 | + /** |
602 | + * Return the value defined by {@link #setBufferPreloadEnabled} |
603 | + * |
604 | + * @return <code>true</code> if the option to preload buffer pools is |
605 | + * enabled |
606 | + */ |
607 | + public boolean isBufferPreloadEnabled() { |
608 | + return bufferPreloadEnabled; |
609 | + } |
610 | + |
611 | + /** |
612 | + * <p> |
613 | + * Control whether Persistit attempts to preload (warm up) the buffer pools |
614 | + * by preloading pages recorded in a previously generated inventory. |
615 | + * </p> |
616 | + * <p> |
617 | + * Default value is <code>false</code><br /> |
618 | + * Property name is {@value #BUFFER_INVENTORY_PROPERTY_NAME} |
619 | + * |
620 | + * @param bufferPreloadEnabled |
621 | + * <code>true</code> to enable buffer pool preloading during |
622 | + * startup |
623 | + */ |
624 | + public void setBufferPreloadEnabled(final boolean bufferPreloadEnabled) { |
625 | + this.bufferPreloadEnabled = bufferPreloadEnabled; |
626 | } |
627 | |
628 | /** |
629 | * Return the value defined by {@link #setIgnoreMissingVolumes(boolean)} |
630 | * |
631 | - * @return the whether to start Persistit in ignore-missing-volumes mode |
632 | + * @return <code>true</code>to enable ignore-missing-volumes mode |
633 | */ |
634 | public boolean isIgnoreMissingVolumes() { |
635 | return ignoreMissingVolumes; |
636 | |
637 | === modified file 'src/main/java/com/persistit/JournalManager.java' |
638 | --- src/main/java/com/persistit/JournalManager.java 2012-08-23 21:28:19 +0000 |
639 | +++ src/main/java/com/persistit/JournalManager.java 2012-08-23 21:28:19 +0000 |
640 | @@ -690,6 +690,29 @@ |
641 | final ByteBuffer bb = buffer.getByteBuffer(); |
642 | |
643 | final Volume volume = buffer.getVolume(); |
644 | + final PageNode pn = lookupUpPageNode(pageAddress, volume); |
645 | + if (pn == null) { |
646 | + return false; |
647 | + } |
648 | + bb.position(0); |
649 | + final long recordPageAddress = readPageBufferFromJournal(pn, bb); |
650 | + _persistit.getIOMeter().chargeReadPageFromJournal(volume, pageAddress, bufferSize, pn.getJournalAddress(), |
651 | + buffer.getIndex()); |
652 | + |
653 | + if (pageAddress != recordPageAddress) { |
654 | + throw new CorruptJournalException("Record at " + pn + " is not volume/page " + buffer.toString()); |
655 | + } |
656 | + |
657 | + if (bb.limit() != bufferSize) { |
658 | + throw new CorruptJournalException("Record at " + pn + " is wrong size: expected/actual=" + bufferSize + "/" |
659 | + + bb.limit()); |
660 | + } |
661 | + _readPageCount++; |
662 | + buffer.getVolume().getStatistics().bumpReadCounter(); |
663 | + return true; |
664 | + } |
665 | + |
666 | + PageNode lookupUpPageNode(final long pageAddress, final Volume volume) { |
667 | PageNode pnLookup = null; |
668 | synchronized (this) { |
669 | final Integer volumeHandle = _volumeToHandleMap.get(volume); |
670 | @@ -699,7 +722,7 @@ |
671 | } |
672 | |
673 | if (pnLookup == null) { |
674 | - return false; |
675 | + return null; |
676 | } |
677 | |
678 | final PageNode pn = new PageNode(pnLookup.getVolumeHandle(), pnLookup.getPageAddress(), |
679 | @@ -714,25 +737,9 @@ |
680 | * new checkpoints and that keeps the copier from deleting it. |
681 | */ |
682 | if (pnLookup.isInvalid()) { |
683 | - return false; |
684 | - } |
685 | - |
686 | - bb.position(0); |
687 | - final long recordPageAddress = readPageBufferFromJournal(pn, bb); |
688 | - _persistit.getIOMeter().chargeReadPageFromJournal(volume, pageAddress, bufferSize, pn.getJournalAddress(), |
689 | - buffer.getIndex()); |
690 | - |
691 | - if (pageAddress != recordPageAddress) { |
692 | - throw new CorruptJournalException("Record at " + pn + " is not volume/page " + buffer.toString()); |
693 | - } |
694 | - |
695 | - if (bb.limit() != bufferSize) { |
696 | - throw new CorruptJournalException("Record at " + pn + " is wrong size: expected/actual=" + bufferSize + "/" |
697 | - + bb.limit()); |
698 | - } |
699 | - _readPageCount++; |
700 | - buffer.getVolume().getStatistics().bumpReadCounter(); |
701 | - return true; |
702 | + return null; |
703 | + } |
704 | + return pn; |
705 | } |
706 | |
707 | private long readPageBufferFromJournal(final PageNode pn, final ByteBuffer bb) throws PersistitIOException, |
708 | @@ -1829,6 +1836,10 @@ |
709 | |
710 | PageNode _previous; |
711 | |
712 | + PageNode(final int volumeHandle, final long pageAddress) { |
713 | + this(volumeHandle, pageAddress, Long.MIN_VALUE, -1); |
714 | + } |
715 | + |
716 | PageNode(final int volumeHandle, final long pageAddress, final long journalAddress, final long timestamp) { |
717 | this._volumeHandle = volumeHandle; |
718 | this._pageAddress = pageAddress; |
719 | @@ -1950,8 +1961,20 @@ |
720 | |
721 | @Override |
722 | public int compare(final PageNode a, final PageNode b) { |
723 | - return a.getJournalAddress() > b.getJournalAddress() ? 1 : a.getJournalAddress() < b |
724 | - .getJournalAddress() ? -1 : 0; |
725 | + if (!a.isInvalid() && !b.isInvalid()) { |
726 | + return a.getJournalAddress() > b.getJournalAddress() ? 1 : a.getJournalAddress() < b |
727 | + .getJournalAddress() ? -1 : 0; |
728 | + } |
729 | + if (a.isInvalid() && !b.isInvalid()) { |
730 | + return -1; |
731 | + } |
732 | + if (!a.isInvalid() && b.isInvalid()) { |
733 | + return 1; |
734 | + } |
735 | + if (a._volumeHandle != b._volumeHandle) { |
736 | + return a._volumeHandle - b._volumeHandle; |
737 | + } |
738 | + return a._pageAddress > b._pageAddress ? 1 : a._pageAddress < b._pageAddress ? -1 : 0; |
739 | } |
740 | }; |
741 | |
742 | |
743 | === modified file 'src/main/java/com/persistit/MediatedFileChannel.java' |
744 | --- src/main/java/com/persistit/MediatedFileChannel.java 2012-08-23 21:28:19 +0000 |
745 | +++ src/main/java/com/persistit/MediatedFileChannel.java 2012-08-23 21:28:19 +0000 |
746 | @@ -342,7 +342,7 @@ |
747 | * |
748 | * @param channel |
749 | */ |
750 | - void setErrorInjectingChannelForTests(final FileChannel channel) { |
751 | + void injectChannelForTests(final FileChannel channel) { |
752 | ((TestChannelInjector) channel).setChannel(_channel); |
753 | _channel = channel; |
754 | } |
755 | |
756 | === modified file 'src/main/java/com/persistit/Persistit.java' |
757 | --- src/main/java/com/persistit/Persistit.java 2012-08-23 21:28:19 +0000 |
758 | +++ src/main/java/com/persistit/Persistit.java 2012-08-23 21:28:19 +0000 |
759 | @@ -403,6 +403,7 @@ |
760 | |
761 | private final AtomicBoolean _suspendShutdown = new AtomicBoolean(false); |
762 | private final AtomicBoolean _suspendUpdates = new AtomicBoolean(false); |
763 | + private final AtomicBoolean _enableBufferInventory = new AtomicBoolean(false); |
764 | |
765 | private UtilControl _localGUI; |
766 | |
767 | @@ -588,9 +589,7 @@ |
768 | initializeVolumes(); |
769 | startJournal(); |
770 | startBufferPools(); |
771 | - if (_configuration.getBufferInventoryPathName() != null) { |
772 | - warmupBufferPools(); |
773 | - } |
774 | + preloadBufferPools(); |
775 | finishRecovery(); |
776 | startCheckpointManager(); |
777 | startTransactionIndexPollTask(); |
778 | @@ -699,6 +698,7 @@ |
779 | _defaultSplitPolicy = _configuration.getSplitPolicy(); |
780 | _defaultJoinPolicy = _configuration.getJoinPolicy(); |
781 | _defaultCommitPolicy = _configuration.getCommitPolicy(); |
782 | + _enableBufferInventory.set(_configuration.isBufferInventoryEnabled()); |
783 | } |
784 | |
785 | void startCheckpointManager() { |
786 | @@ -719,10 +719,24 @@ |
787 | } |
788 | } |
789 | |
790 | - void warmupBufferPools() throws PersistitException { |
791 | - final String pathName = _configuration.getBufferInventoryPathName(); |
792 | - for (final BufferPool pool : _bufferPoolTable.values()) { |
793 | - pool.warmupBufferPool(pathName, pool.toString()); |
794 | + void recordBufferPoolInventory() { |
795 | + final long timestamp = _timestampAllocator.getCurrentTimestamp(); |
796 | + if (_enableBufferInventory.get()) { |
797 | + for (final BufferPool pool : _bufferPoolTable.values()) { |
798 | + try { |
799 | + pool.recordBufferInventory(timestamp); |
800 | + } catch (PersistitException e) { |
801 | + getLogBase().bufferInventoryException.log(e); |
802 | + } |
803 | + } |
804 | + } |
805 | + } |
806 | + |
807 | + void preloadBufferPools() throws PersistitException { |
808 | + if (_configuration.isBufferPreloadEnabled()) { |
809 | + for (final BufferPool pool : _bufferPoolTable.values()) { |
810 | + pool.preloadBufferInventory(); |
811 | + } |
812 | } |
813 | } |
814 | |
815 | @@ -974,8 +988,6 @@ |
816 | * |
817 | * @throws IllegalStateException |
818 | */ |
819 | - |
820 | - // TODO - why not one pool. |
821 | public void releaseExchange(final Exchange exchange, final boolean secure) { |
822 | if (exchange == null) { |
823 | return; |
824 | @@ -1638,6 +1650,7 @@ |
825 | } |
826 | } |
827 | } |
828 | + recordBufferPoolInventory(); |
829 | |
830 | /* |
831 | * The copier is responsible for background pruning of aborted |
832 | |
833 | === modified file 'src/main/java/com/persistit/logging/LogBase.java' |
834 | --- src/main/java/com/persistit/logging/LogBase.java 2012-08-23 21:28:19 +0000 |
835 | +++ src/main/java/com/persistit/logging/LogBase.java 2012-08-23 21:28:19 +0000 |
836 | @@ -244,6 +244,15 @@ |
837 | @Message("ERROR|Too many journal files %,d") |
838 | public final LogItem tooManyJournalFilesError = PersistitLogMessage.empty(); |
839 | |
840 | + @Message("INFO|Preloading buffer pool inventory recorded at %tc") |
841 | + public final LogItem bufferInventoryLoad = PersistitLogMessage.empty(); |
842 | + |
843 | + @Message("INFO|Preloaded %,d of %,d buffers") |
844 | + public final LogItem bufferInventoryProgress = PersistitLogMessage.empty(); |
845 | + |
846 | + @Message("WARNING|Exception while writing buffer pool inventory %s") |
847 | + public final LogItem bufferInventoryException = PersistitLogMessage.empty(); |
848 | + |
849 | public static String recurring(final String message, final int count, final long duration) { |
850 | return String.format(RECURRING, message, count, duration); |
851 | } |
852 | |
853 | === modified file 'src/test/java/com/persistit/IOFailureTest.java' |
854 | --- src/test/java/com/persistit/IOFailureTest.java 2012-08-23 21:28:19 +0000 |
855 | +++ src/test/java/com/persistit/IOFailureTest.java 2012-08-23 21:28:19 +0000 |
856 | @@ -57,7 +57,7 @@ |
857 | |
858 | private ErrorInjectingFileChannel errorInjectingChannel(final FileChannel channel) { |
859 | final ErrorInjectingFileChannel eimfc = new ErrorInjectingFileChannel(); |
860 | - ((MediatedFileChannel) channel).setErrorInjectingChannelForTests(eimfc); |
861 | + ((MediatedFileChannel) channel).injectChannelForTests(eimfc); |
862 | return eimfc; |
863 | } |
864 | |
865 | |
866 | === modified file 'src/test/java/com/persistit/StressRunner.java' |
867 | --- src/test/java/com/persistit/StressRunner.java 2012-08-23 21:28:19 +0000 |
868 | +++ src/test/java/com/persistit/StressRunner.java 2012-08-23 21:28:19 +0000 |
869 | @@ -31,6 +31,7 @@ |
870 | import com.persistit.stress.MixtureTxn1; |
871 | import com.persistit.stress.MixtureTxn2; |
872 | import com.persistit.stress.PersistitMap1; |
873 | +import com.persistit.stress.PreloadMixtureTxn1; |
874 | import com.persistit.stress.StartStop; |
875 | import com.persistit.stress.Stress10Suite; |
876 | import com.persistit.stress.Stress12txnSuite; |
877 | @@ -79,6 +80,7 @@ |
878 | _classes.add(Stress12txnSuite.class); |
879 | _classes.add(Stress4Suite.class); |
880 | _classes.add(Stress8txnSuite.class); |
881 | + _classes.add(PreloadMixtureTxn1.class); |
882 | } |
883 | |
884 | private final static String DURATION_PARAM = "duration="; |
885 | |
886 | === added file 'src/test/java/com/persistit/TrackingFileChannel.java' |
887 | --- src/test/java/com/persistit/TrackingFileChannel.java 1970-01-01 00:00:00 +0000 |
888 | +++ src/test/java/com/persistit/TrackingFileChannel.java 2012-08-23 21:28:19 +0000 |
889 | @@ -0,0 +1,175 @@ |
890 | +/** |
891 | + * Copyright © 2012 Akiban Technologies, Inc. All rights reserved. |
892 | + * |
893 | + * This program and the accompanying materials are made available |
894 | + * under the terms of the Eclipse Public License v1.0 which |
895 | + * accompanies this distribution, and is available at |
896 | + * http://www.eclipse.org/legal/epl-v10.html |
897 | + * |
898 | + * This program may also be available under different license terms. |
899 | + * For more information, see www.akiban.com or contact licensing@akiban.com. |
900 | + * |
901 | + * Contributors: |
902 | + * Akiban Technologies, Inc. |
903 | + */ |
904 | + |
905 | +package com.persistit; |
906 | + |
907 | +import static org.junit.Assert.assertEquals; |
908 | +import static org.junit.Assert.assertTrue; |
909 | +import static org.junit.Assert.fail; |
910 | +import java.io.IOException; |
911 | +import java.nio.ByteBuffer; |
912 | +import java.nio.MappedByteBuffer; |
913 | +import java.nio.channels.FileChannel; |
914 | +import java.nio.channels.FileLock; |
915 | +import java.nio.channels.ReadableByteChannel; |
916 | +import java.nio.channels.WritableByteChannel; |
917 | +import java.util.ArrayList; |
918 | +import java.util.List; |
919 | + |
920 | +import com.persistit.MediatedFileChannel.TestChannelInjector; |
921 | + |
922 | +/** |
923 | + * <p> |
924 | + * A {@link FileChannel} implementation that simulates IOExceptions under |
925 | + * control of a unit test program. This class implements only those methods used |
926 | + * by Persistit; many methods of FileChannel throw |
927 | + * {@link UnsupportedOperationException}. |
928 | + * </p> |
929 | + * |
930 | + * @author peter |
931 | + * |
932 | + */ |
933 | +class TrackingFileChannel extends FileChannel implements TestChannelInjector { |
934 | + |
935 | + volatile FileChannel _channel; |
936 | + |
937 | + final List<Long> _writePositions = new ArrayList<Long>(); |
938 | + |
939 | + final List<Long> _readPositions = new ArrayList<Long>(); |
940 | + |
941 | + @Override |
942 | + public void setChannel(final FileChannel channel) { |
943 | + _channel = channel; |
944 | + } |
945 | + |
946 | + @Override |
947 | + protected void implCloseChannel() throws IOException { |
948 | + _channel.close(); |
949 | + } |
950 | + |
951 | + @Override |
952 | + public void force(final boolean metaData) throws IOException { |
953 | + _channel.force(metaData); |
954 | + } |
955 | + |
956 | + @Override |
957 | + public int read(final ByteBuffer byteBuffer, final long position) throws IOException { |
958 | + _readPositions.add(position); |
959 | + return _channel.read(byteBuffer, position); |
960 | + } |
961 | + |
962 | + @Override |
963 | + public long size() throws IOException { |
964 | + return _channel.size(); |
965 | + } |
966 | + |
967 | + @Override |
968 | + public FileChannel truncate(final long size) throws IOException { |
969 | + return _channel.truncate(size); |
970 | + } |
971 | + |
972 | + @Override |
973 | + public synchronized FileLock tryLock(final long position, final long size, final boolean shared) throws IOException { |
974 | + return _channel.tryLock(position, size, shared); |
975 | + } |
976 | + |
977 | + @Override |
978 | + public int write(final ByteBuffer byteBuffer, final long position) throws IOException { |
979 | + _writePositions.add(position); |
980 | + final int written = _channel.write(byteBuffer, position); |
981 | + return written; |
982 | + } |
983 | + |
984 | + /* |
985 | + * -------------------------------- |
986 | + * |
987 | + * Persistit does not use these methods and so they are Unsupported. Note |
988 | + * that it would be difficult to support the relative read/write methods |
989 | + * because the channel size is unavailable after it is closed. Therefore a |
990 | + * client of this class must maintain its own position counter and cannot |
991 | + * use the relative-addressing calls. |
992 | + * |
993 | + * -------------------------------- |
994 | + */ |
995 | + @Override |
996 | + public FileLock lock(final long position, final long size, final boolean shared) throws IOException { |
997 | + throw new UnsupportedOperationException(); |
998 | + } |
999 | + |
1000 | + @Override |
1001 | + public MappedByteBuffer map(final MapMode arg0, final long arg1, final long arg2) throws IOException { |
1002 | + throw new UnsupportedOperationException(); |
1003 | + } |
1004 | + |
1005 | + @Override |
1006 | + public long position() throws IOException { |
1007 | + throw new UnsupportedOperationException(); |
1008 | + } |
1009 | + |
1010 | + @Override |
1011 | + public FileChannel position(final long arg0) throws IOException { |
1012 | + throw new UnsupportedOperationException(); |
1013 | + } |
1014 | + |
1015 | + @Override |
1016 | + public int read(final ByteBuffer byteBuffer) throws IOException { |
1017 | + throw new UnsupportedOperationException(); |
1018 | + } |
1019 | + |
1020 | + @Override |
1021 | + public long read(final ByteBuffer[] arg0, final int arg1, final int arg2) throws IOException { |
1022 | + throw new UnsupportedOperationException(); |
1023 | + } |
1024 | + |
1025 | + @Override |
1026 | + public long transferFrom(final ReadableByteChannel arg0, final long arg1, final long arg2) throws IOException { |
1027 | + throw new UnsupportedOperationException(); |
1028 | + } |
1029 | + |
1030 | + @Override |
1031 | + public long transferTo(final long arg0, final long arg1, final WritableByteChannel arg2) throws IOException { |
1032 | + throw new UnsupportedOperationException(); |
1033 | + } |
1034 | + |
1035 | + @Override |
1036 | + public int write(final ByteBuffer byteBuffer) throws IOException { |
1037 | + throw new UnsupportedOperationException(); |
1038 | + } |
1039 | + |
1040 | + @Override |
1041 | + public long write(final ByteBuffer[] arg0, final int arg1, final int arg2) throws IOException { |
1042 | + throw new UnsupportedOperationException(); |
1043 | + } |
1044 | + |
1045 | + public List<Long> getWritePositionList() { |
1046 | + return _writePositions; |
1047 | + } |
1048 | + |
1049 | + public List<Long> getReadPositionList() { |
1050 | + return _readPositions; |
1051 | + } |
1052 | + |
1053 | + public void assertSequential(boolean read, boolean forward) { |
1054 | + final List<Long> list = read ? _readPositions : _writePositions; |
1055 | + long previous = forward ? -1 : Long.MAX_VALUE; |
1056 | + for (final Long position : list) { |
1057 | + if (forward) { |
1058 | + assertTrue("Position should be larger", position > previous); |
1059 | + } else { |
1060 | + assertTrue("Position should be smaller", position < previous); |
1061 | + } |
1062 | + } |
1063 | + } |
1064 | +} |
1065 | |
1066 | === modified file 'src/test/java/com/persistit/WarmupTest.java' |
1067 | --- src/test/java/com/persistit/WarmupTest.java 2012-08-23 21:28:19 +0000 |
1068 | +++ src/test/java/com/persistit/WarmupTest.java 2012-08-23 21:28:19 +0000 |
1069 | @@ -16,6 +16,7 @@ |
1070 | package com.persistit; |
1071 | |
1072 | import static org.junit.Assert.assertEquals; |
1073 | +import static org.junit.Assert.assertTrue; |
1074 | |
1075 | import java.util.Properties; |
1076 | |
1077 | @@ -25,43 +26,97 @@ |
1078 | |
1079 | public class WarmupTest extends PersistitUnitTestCase { |
1080 | |
1081 | + @Override |
1082 | + protected Properties getProperties(final boolean cleanup) { |
1083 | + final Properties p = super.getProperties(cleanup); |
1084 | + p.setProperty("bufferinventory", "true"); |
1085 | + p.setProperty("bufferpreload", "true"); |
1086 | + return p; |
1087 | + } |
1088 | + |
1089 | @Test |
1090 | public void testWarmup() throws Exception { |
1091 | Exchange ex = _persistit.getExchange("persistit", "WarmupTest", true); |
1092 | + final BufferPool pool = ex.getBufferPool(); |
1093 | for (int i = 1; i <= 1000; i++) { |
1094 | ex.getValue().put(RED_FOX); |
1095 | ex.clear().append(i).store(); |
1096 | } |
1097 | |
1098 | - // Assumption: only one buffer pool is created |
1099 | - int poolCount = 0; |
1100 | - String pathName = ""; |
1101 | final Buffer[] buff = new Buffer[100]; |
1102 | - for (final BufferPool p : _persistit.getBufferPoolHashMap().values()) { |
1103 | - poolCount = p.getBufferCount(); |
1104 | - pathName = p.toString(); |
1105 | - for (int i = 0; i < poolCount; ++i) { |
1106 | - buff[i] = p.getBufferCopy(i); |
1107 | - } |
1108 | - } |
1109 | - |
1110 | - final Properties properties = _persistit.getProperties(); |
1111 | - ex = null; |
1112 | - _persistit.close(); |
1113 | - |
1114 | - _persistit = new Persistit(); |
1115 | - _persistit.initialize(properties); |
1116 | - |
1117 | - int poolCount1 = 0; |
1118 | - for (final BufferPool p : _persistit.getBufferPoolHashMap().values()) { |
1119 | - poolCount1 = p.getBufferCount(); |
1120 | - for (int i = 0; i < poolCount1; ++i) { |
1121 | - final Buffer bufferCopy = p.getBufferCopy(i); |
1122 | - assertEquals(bufferCopy.getPageAddress(), buff[i].getPageAddress()); |
1123 | - assertEquals(bufferCopy.getPageType(), buff[i].getPageType()); |
1124 | - assertEquals(bufferCopy.getBufferSize(), buff[i].getBufferSize()); |
1125 | - } |
1126 | - } |
1127 | - assertEquals(poolCount, poolCount1); |
1128 | + for (int i = 0; i < pool.getBufferCount(); ++i) { |
1129 | + buff[i] = pool.getBufferCopy(i); |
1130 | + } |
1131 | + |
1132 | + final Configuration config = _persistit.getConfiguration(); |
1133 | + ex = null; |
1134 | + _persistit.close(); |
1135 | + |
1136 | + _persistit = new Persistit(); |
1137 | + _persistit.initialize(config); |
1138 | + |
1139 | + for (int i = 0; i < pool.getBufferCount(); ++i) { |
1140 | + final Buffer bufferCopy = pool.getBufferCopy(i); |
1141 | + assertEquals(bufferCopy.getPageAddress(), buff[i].getPageAddress()); |
1142 | + assertEquals(bufferCopy.getPageType(), buff[i].getPageType()); |
1143 | + assertEquals(bufferCopy.getBufferSize(), buff[i].getBufferSize()); |
1144 | + } |
1145 | + } |
1146 | + |
1147 | + @Test |
1148 | + public void readOrderIsSequential() throws Exception { |
1149 | + |
1150 | + Exchange ex = _persistit.getExchange("persistit", "WarmupTest", true); |
1151 | + BufferPool pool = ex.getBufferPool(); |
1152 | + |
1153 | + final int full = pool.getBufferCount() * (pool.getBufferSize() / RED_FOX.length()); |
1154 | + /* |
1155 | + * Overflow the buffer pool |
1156 | + */ |
1157 | + for (int i = 1; i <= full * 3; i++) { |
1158 | + ex.getValue().put(RED_FOX); |
1159 | + ex.clear().append(i).store(); |
1160 | + } |
1161 | + /* |
1162 | + * Pull some low-address pages in to scramble the pool |
1163 | + */ |
1164 | + for (int i = full * 2; i >= 0; i -= 1000) { |
1165 | + ex.clear().append(i).fetch(); |
1166 | + } |
1167 | + /* |
1168 | + * Verify that buffers in pool now have somewhat scrambled page |
1169 | + * addresses |
1170 | + */ |
1171 | + int breaks = 0; |
1172 | + long previous = -1; |
1173 | + |
1174 | + for (int i = 0; i < pool.getBufferCount(); i++) { |
1175 | + final Buffer b = pool.getBufferCopy(i); |
1176 | + assertTrue("Every buffer should be valid at this point", b.isValid()); |
1177 | + if (b.getPageAddress() < previous) { |
1178 | + breaks++; |
1179 | + } |
1180 | + previous = b.getPageAddress(); |
1181 | + } |
1182 | + |
1183 | + assertTrue("Buffer pool should have scrambled page address", breaks > 0); |
1184 | + |
1185 | + final Configuration config = _persistit.getConfiguration(); |
1186 | + ex = null; |
1187 | + pool = null; |
1188 | + _persistit.close(); |
1189 | + |
1190 | + _persistit = new Persistit(); |
1191 | + config.setBufferPreloadEnabled(false); |
1192 | + _persistit.initialize(config); |
1193 | + |
1194 | + final Volume volume = _persistit.getVolume("persistit"); |
1195 | + final MediatedFileChannel mfc = (MediatedFileChannel) volume.getStorage().getChannel(); |
1196 | + final TrackingFileChannel tfc = new TrackingFileChannel(); |
1197 | + mfc.injectChannelForTests(tfc); |
1198 | + pool = volume.getStructure().getPool(); |
1199 | + pool.preloadBufferInventory(); |
1200 | + assertTrue("Preload should have loaded pages from journal file", tfc.getReadPositionList().size() > 0); |
1201 | + tfc.assertSequential(true, true); |
1202 | } |
1203 | } |
1204 | |
1205 | === added file 'src/test/java/com/persistit/stress/PreloadMixtureTxn1.java' |
1206 | --- src/test/java/com/persistit/stress/PreloadMixtureTxn1.java 1970-01-01 00:00:00 +0000 |
1207 | +++ src/test/java/com/persistit/stress/PreloadMixtureTxn1.java 2012-08-23 21:28:19 +0000 |
1208 | @@ -0,0 +1,82 @@ |
1209 | +/** |
1210 | + * Copyright © 2012 Akiban Technologies, Inc. All rights reserved. |
1211 | + * |
1212 | + * This program and the accompanying materials are made available |
1213 | + * under the terms of the Eclipse Public License v1.0 which |
1214 | + * accompanies this distribution, and is available at |
1215 | + * http://www.eclipse.org/legal/epl-v10.html |
1216 | + * |
1217 | + * This program may also be available under different license terms. |
1218 | + * For more information, see www.akiban.com or contact licensing@akiban.com. |
1219 | + * |
1220 | + * Contributors: |
1221 | + * Akiban Technologies, Inc. |
1222 | + */ |
1223 | + |
1224 | +package com.persistit.stress; |
1225 | + |
1226 | +import com.persistit.Configuration; |
1227 | +import com.persistit.Persistit; |
1228 | +import com.persistit.Transaction.CommitPolicy; |
1229 | +import com.persistit.stress.unit.Stress1; |
1230 | +import com.persistit.stress.unit.Stress2txn; |
1231 | +import com.persistit.stress.unit.Stress3; |
1232 | +import com.persistit.stress.unit.Stress3txn; |
1233 | +import com.persistit.stress.unit.Stress5; |
1234 | +import com.persistit.stress.unit.Stress6; |
1235 | +import com.persistit.stress.unit.Stress8txn; |
1236 | + |
1237 | +public class PreloadMixtureTxn1 extends AbstractSuite { |
1238 | + private final static int CYCLES = 4; |
1239 | + |
1240 | + static String name() { |
1241 | + return PreloadMixtureTxn1.class.getSimpleName(); |
1242 | + } |
1243 | + |
1244 | + public static void main(final String[] args) throws Exception { |
1245 | + new PreloadMixtureTxn1(args).runTest(); |
1246 | + } |
1247 | + |
1248 | + public PreloadMixtureTxn1(final String[] args) { |
1249 | + super(name(), args); |
1250 | + setDuration(getDuration() / CYCLES); |
1251 | + } |
1252 | + |
1253 | + @Override |
1254 | + public void runTest() throws Exception { |
1255 | + |
1256 | + deleteFiles(substitute("$datapath$/persistit*")); |
1257 | + |
1258 | + for (int iteration = 0; iteration < CYCLES; iteration++) { |
1259 | + clear(); |
1260 | + add(new Stress1("repeat=10 count=25000")); |
1261 | + add(new Stress1("repeat=10 count=25000")); |
1262 | + add(new Stress2txn("repeat=10 count=2500 size=4000 seed=118")); |
1263 | + add(new Stress2txn("repeat=2 count=25000 seed=119")); |
1264 | + add(new Stress3("repeat=5 count=25000 seed=119")); |
1265 | + add(new Stress3txn("repeat=5 count=25000 seed=120")); |
1266 | + add(new Stress3txn("repeat=5 count=25000")); |
1267 | + add(new Stress5("repeat=5 count=25000")); |
1268 | + add(new Stress6("repeat=5 count=1000 size=250")); |
1269 | + add(new Stress6("repeat=10 count=1000 size=250")); |
1270 | + add(new Stress8txn("repeat=2 count=1000 size=1000 seed=1")); |
1271 | + add(new Stress8txn("repeat=2 count=1000 size=1000 seed=2")); |
1272 | + add(new Stress8txn("repeat=2 count=1000 size=1000 seed=3")); |
1273 | + add(new Stress8txn("repeat=2 count=1000 size=1000 seed=4")); |
1274 | + |
1275 | + final Configuration configuration = makeConfiguration(16384, "25000", CommitPolicy.SOFT); |
1276 | + configuration.setLogFile(configuration.getLogFile() + "_" + iteration); |
1277 | + configuration.setBufferInventoryEnabled(true); |
1278 | + configuration.setBufferPreloadEnabled(true); |
1279 | + |
1280 | + final Persistit persistit = new Persistit(); |
1281 | + persistit.initialize(configuration); |
1282 | + |
1283 | + try { |
1284 | + execute(persistit); |
1285 | + } finally { |
1286 | + persistit.close(); |
1287 | + } |
1288 | + } |
1289 | + } |
1290 | +} |
1291 | |
1292 | === modified file 'src/test/java/com/persistit/unit/PersistitUnitTestCase.java' |
1293 | --- src/test/java/com/persistit/unit/PersistitUnitTestCase.java 2012-08-23 21:28:19 +0000 |
1294 | +++ src/test/java/com/persistit/unit/PersistitUnitTestCase.java 2012-08-23 21:28:19 +0000 |
1295 | @@ -47,7 +47,8 @@ |
1296 | protected Persistit _persistit = new Persistit(); |
1297 | |
1298 | protected Properties getProperties(final boolean cleanup) { |
1299 | - return UnitTestProperties.getProperties(cleanup); |
1300 | + final Properties p = UnitTestProperties.getProperties(cleanup); |
1301 | + return p; |
1302 | } |
1303 | |
1304 | @Before |
1305 | |
1306 | === modified file 'src/test/java/com/persistit/unit/UnitTestProperties.java' |
1307 | --- src/test/java/com/persistit/unit/UnitTestProperties.java 2012-08-07 21:11:28 +0000 |
1308 | +++ src/test/java/com/persistit/unit/UnitTestProperties.java 2012-08-23 21:28:19 +0000 |
1309 | @@ -43,7 +43,6 @@ |
1310 | p.setProperty("tmpvoldir", "${datapath}"); |
1311 | p.setProperty("rmiport", System.getProperty("rmiport", "8081")); |
1312 | p.setProperty("jmx", "true"); |
1313 | - p.setProperty("bufferinventory", "/tmp/persistit_test_data"); |
1314 | return p; |
1315 | } |
1316 |