utils/src/main/java/com/streamsets/datacollector/io/DataStore.java
public void release() {
    CounterLock lock;
    synchronized (DataStore.class) {
      lock = FILE_LOCKS.get(file);

      if(lock == null) {
        LOG.error("Trying to release unlocked file {}", file);
        return;
      }

      lock.dec();

      if(lock.counter == 0) {
        FILE_LOCKS.remove(file);
      }
    }

    LOG.trace("Releasing the lock {} for '{}'", lock, file);
    lock.unlock();
    LOG.trace("Released the lock {} for '{}'", lock, file);
  }
public void release() {
    CounterLock lock;
    synchronized (DataStore.class) {
      lock = FILE_LOCKS.get(file);

      if(lock == null) {
        LOG.error("Trying to release unlocked file {}", file);
        return;
      }

      lock.dec();

      if(lock.counter == 0) {
        FILE_LOCKS.remove(file);
      }
    }

    LOG.trace("Releasing the lock {} for '{}'", lock, file);
    lock.unlock();
    LOG.trace("Released the lock {} for '{}'", lock, file);
  }
This method must be used after completing the write to output stream which was obtained by calling the
{@link #getOutputStream()} method.

If the write operation was successful, then this method must be called after calling the
{@link #commit(java.io.OutputStream)} method. Otherwise it must be called after calling the {@link #close()} on the
output stream.

Example usage:

DataStore dataStore = new DataStore(...);
try (OutputStream os = dataStore.getOutputStream()) {
os.write(..);
dataStore.commit(os);
} catch (IOException e) {
...
} finally {
dataStore.release();
}