TrueZIP 7.6 released

TrueZIP 7.6 has been released. This is a feature release. As usual, binary backwards compatibility of the client APIs with TrueZIP 7.0 has been retained, so please don’t hesitate to upgrade your dependencies. If you have been coding a TrueZIP Driver however, you need to recompile because this version incorporates considerable changes to the Kernel API which were required to achieve some important improvements.

What’s new?

Most relevant:

  1. The new TrueZIP Extension PaceManager restricts the number of mounted archive files in order to save some heap space.
  2. Support for TAR.XZ files has been added in the TrueZIP Driver TAR. The code is based on XZ for Java 1.1.
  3. Improved I/O exception handling so that more accurate stack traces are provided for easier analysis of the root cause.
  4. Improved concurrency of the TrueZIP Kernel so that multithreaded applications run with less contention between different threads.

For a more detailed list, please refer to the Release Notes at the bottom of this article.

Introducing TrueZIP Extension PaceManager

The TrueZIP Extension PaceManager is especially useful if your application is accessing lots of archive files: Without this plugin the TrueZIP Kernel mounts each archive file upon first access. This may consume a lot of heap space over time. The traditional way to deal with this issue is to add explicit calls to TVFS.umount() or TVFS.sync(). However, it can be tricky to estimate when its best to call these methods and what particular synchronization options to use. Often times the only result is a serious degradation of performance.

If you add the JAR artifact of this plugin to the run time class path however, the TrueZIP Kernel (more particular, the PaceManager in this plugin) maintains a cache of most recently used (mounted) archive files and a property to limit the number of mounted archive files. Whenever the maximum number of mounted archive files is reached and another archive file is accessed, the least recently used archive file gets evicted from the cache and unmounted (unless its a parent file system of one of the mounted archive files in the cache).

TrueZIP Extension PaceManager provides a JMX interface for monitoring and management: The singleton Pacemanager MXBean is registered with the ObjectName de.schlichtherle.truezip.extension.pace:type=PaceManager and quite natural its management interface is de.schlichtherle.truezip.extension.pace.PaceManager.

Changing The Maximum Number Of Most Recently Used Archive Files

To interface with the PaceManager programmatically, add a compile time dependency to this extension in your Maven POM:

<dependency>
  <groupId>de.schlichtherle.truezip</groupId>
  <artifactId>truezip-extension-pace</artifactId>
  <version>7.6</version>
</dependency>

Now you can obtain a reference to the singleton PaceManager quite comfortably in order to change the maximum number of mounted archive files:

PaceManager manager = PaceManagerFactory.newMXBeanProxy();
// Let's change the default value, which is 2.
manager.setMaximumFileSystemsMounted(5);

Note that newMXBeanProxy() returns a new proxy to the singleton PaceManager, even if it hasn’t been registered in the TrueZIP Kernel yet. Furthermore, the default value of the property MaximumFileSystemsMounted is two, which is just enough to copy an archive entry from one archive file to another, so it’s a good idea to change it.

PaceManager in Action

To see the TrueZIP Extension PaceManager in action, let’s use the TrueZIP Archetype File or TrueZIP Archetype Path to generate a new Maven project for the TrueZIP File* API. Next, let’s add the dependency on the TrueZIP Extension PaceManager to the Maven POM of the generated project as explained before and modify the sync() method of the Application class as follows:

@Override
protected void sync() throws FsSyncException {
    System.out.println("Waiting until interrupt...");
    try {
        Thread.sleep(Long.MAX_VALUE);
    } catch (InterruptedException ex) {
    }
    super.sync();
}

The purpose of this change is to make any application wait indefinitely before shutdown so that we’ve got a chance to watch the PaceManager in action. Now simply run the main class Tree and cancel the password dialog for the TZP file. Next, start up JVisualVM and connect to the target JVM with the class Tree. Finally, switch to the tab MBeans and the GUI should look similar to this:

Let’s discuss the Attribute tuple (2, 6, 2, 1, 1) in sequence:

  1. FileSystemsMounted:  The number of mounted file systems. The value of this property never exceeds MaximumFileSystemsMounted.
  2. FileSystemsTotal:  The total number of file systems.
  3. MaximumFileSystemsMounted:  The maximum number of mounted file systems. This is an editable property. Changing it will show effect upon the next access to any file system.
  4. TopLevelArchiveFileSystemsMounted:  The number of mounted top level archive file systems. The value of this property never exceeds FileSystemsMounted.
  5. TopLevelArchiveFileSystemsTotal:  The total number of top level archive file systems. The value of this property never exceeds FileSystemsTotal.

Next, let’s interact with the PaceManager. Change to the tab Operations and click on the button sync. The result should look like this:

To see the effect you need to switch back to the tab Attributes and click on the button Refresh:

The tuple has changed from (2, 6, 2, 1, 1) to (1, 6, 2, 1, 1), so the number of mounted file systems has been reduced from two to one. It hasn’t been reset to zero because the top level archive file test.jar still holds some nested archive files in its selective entry cache. The selective entry cache isn’t cleared by the MBean operation in order to prevent some potentially dangerous side effects in multithreaded applications.

To reduce the total number of file systems we need to instruct the JVM to do some garbage collection. You can do this by changing to the tab Monitor and clicking on the button Perform GC. Changing back to the tab MBeans and clicking on the button Refresh again should result in this:

The tuple has changed again from (1, 6, 2, 1, 1) to (1, 2, 2, 1, 1), so the total number of file systems has been reduced from six to two. It hasn’t been reset to zero because the archive file test.jar is still mounted and it references the current directory as its parent file system.

Release Notes

Last, but not least, following are the Release Notes for TrueZIP 7.6 as compiled by the project’s issue tracker at http://java.net/jira/browse/TRUEZIP.

Bug

  • [TRUEZIP-262] - ZipOutputShop.EntryOutputStream and TarOutputShop.EntryOutputStream will write to the underlying container even if they have been closed
  • [TRUEZIP-264] - Covariant archive entries may not be readable
  • [TRUEZIP-268] - Using FsSyncOption.CLEAR_CACHE induces extended dead locks in other threads
  • [TRUEZIP-269] - Using FsSyncOption.CLEAR_CACHE induces busy loops in other threads
  • [TRUEZIP-271] - Memory leak in TFileSystemProvider.filesystems
  • [TRUEZIP-278] - FsEntry.toString() throws IllegalArgumentException if getTypes() returns an empty set.
  • [TRUEZIP-279] - ResourceController$ResourceOutputStream.close() et al should stop accounting for the resource unless a control flow exception gets thrown
  • [TRUEZIP-281] - DateTimeConverter.ZIP fails to recognize change of daylight savings in long running applications

Improvement

  • [TRUEZIP-265] - Upgrade to commons-compress 1.4.1
  • [TRUEZIP-266] - The sample code for key management should customize the ZipDriver class, not the JarDriver class
  • [TRUEZIP-267] - Improve concurrency of the default archive manager
  • [TRUEZIP-270] - TrueZIP Extension JMX should sync() without CLEAR_CACHE
  • [TRUEZIP-272] - Make archive controller chain eligible for GC after sync() if the selective entry cache is empty.
  • [TRUEZIP-280] - Upgrade to Apache HttpClient 4.2.1
  • [TRUEZIP-282] - Raise logging level for calling close() on stale streams or channels in finalizer-threads to INFO

New Feature

  • [TRUEZIP-175] - Add TarXZDriver for TAR.XZ files
  • [TRUEZIP-273] - Welcome TrueZIP Extension PaceManager!

Task

  • [TRUEZIP-263] - Improve documentation