/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.github.geophile.erdo.segmentfilemanager;
import com.github.geophile.erdo.Configuration;
import com.github.geophile.erdo.util.FileUtil;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ReferenceCountedSegmentFileManager extends SegmentFileManagerWrapper
{
// AbstractSegmentFileManager interface
@Override
public synchronized void create(File file, long treeId, long segmentId) throws IOException
{
LOG.log(Level.FINE, "Creating {0} for use by {1}", new Object[]{file, treeId});
FileUtil.createFile(file);
List<Long> users = fileUsers.get(segmentId);
assert users == null : file;
users = new ArrayList<>();
fileUsers.put(segmentId, users);
users.add(treeId);
}
@Override
public synchronized boolean delete(File file, long treeId, long segmentId)
{
boolean deleted;
List<Long> users = fileUsers.get(segmentId);
if (users != null) {
LOG.log(Level.FINE, "Unregistering {0} used by {1}", new Object[]{file, treeId});
// Cast to Object because List.remove(int x) removes the element at position x.
// This call should normally return true. But there is a small window between
// creating the file and registering it (in createSegmentFile, in this class). If
// an InterruptedException occurs between those actions then we're probably here
// while cleaning up, and users.remove could return false.
users.remove((Object) treeId);
if (users.isEmpty()) {
LOG.log(Level.FINE, "Really deleting {0}", file);
fileUsers.remove(segmentId);
filesystem.delete(file, treeId, segmentId);
deleted = true;
} else {
deleted = false;
}
} else {
// must be deleting an obsolete file during recovery.
// TODO: Don't assume recovery, but there's currently no way to check whether we are.
filesystem.delete(file, treeId, segmentId);
deleted = true;
}
return deleted;
}
@Override
public synchronized void register(File file, long treeId, long segmentId)
{
if (LOG.isLoggable(Level.FINE)) {
LOG.log(Level.FINE, "Registering {0} for use by {1}", new Object[]{file, treeId});
}
List<Long> users = fileUsers.get(segmentId);
if (users == null) {
users = new ArrayList<>();
fileUsers.put(segmentId, users);
}
assert !users.contains(treeId) : treeId;
users.add(treeId);
}
public void resetForTesting()
{
fileUsers.clear();
}
// ReferenceCountedSegmentFileManager interface
public ReferenceCountedSegmentFileManager(Configuration configuration, AbstractSegmentFileManager filesystem)
{
super(configuration, filesystem);
}
// Class state
private static final Logger LOG = Logger.getLogger(ReferenceCountedSegmentFileManager.class.getName());
// Object state
private final Map<Long, List<Long>> fileUsers = new HashMap<>();
}