Skip to content

Commit

Permalink
Merge pull request #489 from knime-ip/fix-cached-cell
Browse files Browse the repository at this point in the history
 KNIPGuavaCacheService: Switch to String based cache
  • Loading branch information
Gabriel Einsdorf authored Nov 20, 2017
2 parents f5492e2 + 39b7286 commit bc7e9fa
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 100 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,13 @@
import org.knime.core.data.filestore.FileStoreCell;
import org.knime.knip.base.KNIMEKNIPPlugin;
import org.knime.knip.base.data.CachedObjectAccess;
import org.knime.knip.base.data.CachedObjectAccess.StreamSkipper;
import org.knime.knip.base.data.FileStoreCellMetadata;
import org.knime.knip.base.data.IntervalValue;
import org.knime.knip.base.renderer.ThumbnailRenderer;
import org.knime.knip.core.KNIPGateway;
import org.knime.knip.core.awt.AWTImageTools;
import org.knime.knip.core.awt.Real2GreyColorRenderer;
import org.knime.knip.core.data.img.DefaultImgMetadata;
import org.knime.knip.core.io.externalization.BufferedDataInputStream;
import org.knime.knip.core.io.externalization.ExternalizerManager;
import org.knime.knip.core.util.MinimaUtils;
import org.scijava.Named;
Expand Down Expand Up @@ -107,6 +105,8 @@
public class ImgPlusCell<T extends RealType<T>> extends FileStoreCell
implements ImgPlusValue<T>, StringValue, IntervalValue {

private static final String IMG_PLUS_CELL_KEY = "IP";

/**
* Type
*
Expand All @@ -122,7 +122,7 @@ public class ImgPlusCell<T extends RealType<T>> extends FileStoreCell
/**
* UID
*/
private static final long serialVersionUID = 1L;
private static final long serialVersionUID = 2L;

private FileStoreCellMetadata m_fileMetadata;

Expand Down Expand Up @@ -158,19 +158,19 @@ protected ImgPlusCell(final Img<T> img, final ImgPlusMetadata metadata, final Fi
tmpImg = ((WrappedImg<T>)tmpImg).getImg();
}

m_imgAccess = new CachedObjectAccess<Img<T>>(fileStore, tmpImg);
m_imgAccess = new CachedObjectAccess<>(fileStore, tmpImg);

final long[] dimensions = new long[img.numDimensions()];
img.dimensions(dimensions);

m_metadataAccess = new CachedObjectAccess<ImgPlusCellMetadata>(fileStore,
m_metadataAccess = new CachedObjectAccess<>(fileStore,
new ImgPlusCellMetadata(
MetadataUtil.copyImgPlusMetadata(metadata, new DefaultImgMetadata(dimensions.length)),
img.size(), getMinFromImg(img), dimensions, img.firstElement().getClass(), null));

m_fileMetadata = new FileStoreCellMetadata(-1, false, null);

CACHE.put(this, this);
CACHE.put(this.stringHashCode(), this);
}

/**
Expand Down Expand Up @@ -241,7 +241,14 @@ private BufferedImage createThumbnail(final double factor) {
*/
@Override
protected boolean equalsDataCell(final DataCell dc) {
return dc.hashCode() == hashCode();
if (dc instanceof ImgPlusCell) {
ImgPlusCell dc2 = (ImgPlusCell)dc;
if (dc2.getFileStore().getFile().equals(this.getFileStore().getFile())
&& dc2.m_fileMetadata.getOffset() == this.m_fileMetadata.getOffset()) {
return true;
}
}
return false;
}

/**
Expand Down Expand Up @@ -308,7 +315,7 @@ public synchronized ImgPlus<T> getImgPlus() {
@Override
public synchronized ImgPlus<T> getImgPlusCopy() {
final ImgPlus<T> source = getImgPlus();
final ImgPlus<T> dest = new ImgPlus<T>(source.copy());
final ImgPlus<T> dest = new ImgPlus<>(source.copy());

MetadataUtil.copyImgPlusMetadata(source, dest);

Expand Down Expand Up @@ -461,7 +468,7 @@ public synchronized Image getThumbnail(final RenderingHints renderingHints) {
tmp = new ImgPlusCellMetadata(tmp.getMetadata(), tmp.getSize(), tmp.getMinimum(),
tmp.getDimensions(), tmp.getPixelType(), createThumbnail(height / fullHeight)));
// update cached object
CACHE.put(this, this);
CACHE.put(this.stringHashCode(), this);
}
return tmp.getThumbnail();
}
Expand All @@ -482,7 +489,11 @@ private int getThumbnailWidth(final int height) {
*/
@Override
public int hashCode() {
return (int)(getFileStore().getFile().hashCode() + (31 * m_fileMetadata.getOffset()));
return stringHashCode().hashCode();
}

private String stringHashCode() {
return IMG_PLUS_CELL_KEY + getFileStore().getFile().getName() + m_fileMetadata.getOffset();
}

/**
Expand Down Expand Up @@ -517,28 +528,20 @@ protected synchronized void load(final DataInput input) throws IOException {
protected void postConstruct() {

@SuppressWarnings("unchecked")
final ImgPlusCell<T> tmp = (ImgPlusCell<T>)CACHE.get(this);
final ImgPlusCell<T> tmp = (ImgPlusCell<T>)CACHE.get(this.stringHashCode());

if (tmp == null) {
m_metadataAccess =
new CachedObjectAccess<ImgPlusCellMetadata>(getFileStore(), null, m_fileMetadata.getOffset(), null);

m_imgAccess = new CachedObjectAccess<Img<T>>(getFileStore(), null, m_fileMetadata.getOffset(),
new StreamSkipper() {
/**
* {@inheritDoc}
*/
@Override
public void skip(final BufferedDataInputStream in) {
try {
m_metadataAccess.setObject(ExternalizerManager.read(in));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
});

CACHE.put(this, this);
m_metadataAccess = new CachedObjectAccess<>(getFileStore(), null, m_fileMetadata.getOffset(), null);

m_imgAccess = new CachedObjectAccess<>(getFileStore(), null, m_fileMetadata.getOffset(), in -> {
try {
m_metadataAccess.setObject(ExternalizerManager.read(in));
} catch (Exception e) {
throw new RuntimeException(e);
}
});

CACHE.put(this.stringHashCode(), this);
} else {
m_metadataAccess = tmp.m_metadataAccess;
m_imgAccess = tmp.m_imgAccess;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@
import org.knime.core.data.filestore.FileStoreCell;
import org.knime.knip.base.KNIMEKNIPPlugin;
import org.knime.knip.base.data.CachedObjectAccess;
import org.knime.knip.base.data.CachedObjectAccess.StreamSkipper;
import org.knime.knip.base.data.FileStoreCellMetadata;
import org.knime.knip.base.data.IntervalValue;
import org.knime.knip.base.renderer.ThumbnailRenderer;
Expand All @@ -75,7 +74,6 @@
import org.knime.knip.core.awt.labelingcolortable.RandomMissingColorHandler;
import org.knime.knip.core.data.LabelingView;
import org.knime.knip.core.data.img.LabelingMetadata;
import org.knime.knip.core.io.externalization.BufferedDataInputStream;
import org.knime.knip.core.io.externalization.ExternalizerManager;
import org.scijava.Named;
import org.scijava.cache.CacheService;
Expand All @@ -102,6 +100,8 @@
*/
public class LabelingCell<L> extends FileStoreCell implements LabelingValue<L>, StringValue, IntervalValue {

private static final String LABELING_CELL_KEY = "LC";

/**
* ObjectRepository
*/
Expand All @@ -110,7 +110,7 @@ public class LabelingCell<L> extends FileStoreCell implements LabelingValue<L>,
/**
* UID
*/
private static final long serialVersionUID = 1L;
private static final long serialVersionUID = 2L;

/**
* Convenience access method for DataType.getType(ImageCell.class).
Expand Down Expand Up @@ -154,12 +154,12 @@ protected LabelingCell(final RandomAccessibleInterval<LabelingType<L>> labeling,
super(fileStore);
final long[] dimensions = new long[labeling.numDimensions()];
labeling.dimensions(dimensions);
m_metadataAccess = new CachedObjectAccess<LabelingCellMetadata>(fileStore,
m_metadataAccess = new CachedObjectAccess<>(fileStore,
new LabelingCellMetadata(metadata, Views.iterable(labeling).size(), dimensions, null));
m_labelingAccess = new CachedObjectAccess<>(fileStore, new LabelingView<L>(labeling));
m_labelingAccess = new CachedObjectAccess<>(fileStore, new LabelingView<>(labeling));
m_fileMetadata = new FileStoreCellMetadata(-1, false, null);

CACHE.put(this, this);
CACHE.put(this.stringHashCode(), this);

}

Expand All @@ -173,7 +173,7 @@ private BufferedImage createThumbnail(final double factor) {
}

// set the labeling mapping
final ColorLabelingRenderer<L> rend = new ColorLabelingRenderer<L>();
final ColorLabelingRenderer<L> rend = new ColorLabelingRenderer<>();
rend.setLabelMapping(lab2d.randomAccess().get().getMapping());
int i = 0;
final long[] max = new long[lab2d.numDimensions()];
Expand Down Expand Up @@ -202,7 +202,14 @@ private BufferedImage createThumbnail(final double factor) {
*/
@Override
protected boolean equalsDataCell(final DataCell dc) {
return dc.hashCode() == hashCode();
if (dc instanceof LabelingCell) {
LabelingCell dc2 = (LabelingCell)dc;
if (dc2.getFileStore().getFile().equals(this.getFileStore().getFile())
&& dc2.m_fileMetadata.getOffset() == this.m_fileMetadata.getOffset()) {
return true;
}
}
return false;
}

/**
Expand Down Expand Up @@ -356,17 +363,21 @@ public synchronized Image getThumbnail(final RenderingHints renderingHints) {
fullHeight = tmp.getDimensions()[1];
}
if ((tmp.getThumbnail() == null) || (tmp.getThumbnail().getHeight() != height)) {
m_metadataAccess = new CachedObjectAccess<LabelingCellMetadata>(getFileStore(),
m_metadataAccess = new CachedObjectAccess<>(getFileStore(),
tmp = new LabelingCellMetadata(tmp.getLabelingMetadata(), tmp.getSize(), tmp.getDimensions(),
createThumbnail(height / fullHeight)));
// update cached object
CACHE.put(this, this);
CACHE.put(this.stringHashCode(), this);
}
return tmp.getThumbnail();
}

}

private String stringHashCode() {
return LABELING_CELL_KEY + getFileStore().getFile().getName() + m_fileMetadata.getOffset();
}

private int getThumbnailWidth(final int height) {
final LabelingCellMetadata tmp = m_metadataAccess.get();
if (tmp.getDimensions().length == 1) {
Expand All @@ -381,7 +392,7 @@ private int getThumbnailWidth(final int height) {
*/
@Override
public int hashCode() {
return (int)(getFileStore().getFile().hashCode() + (31 * m_fileMetadata.getOffset()));
return stringHashCode().hashCode();
}

/**
Expand Down Expand Up @@ -415,27 +426,20 @@ protected synchronized void load(final DataInput input) throws IOException {
protected void postConstruct() {

@SuppressWarnings("unchecked")
final LabelingCell<L> tmp = (LabelingCell<L>)CACHE.get(this);
final LabelingCell<L> tmp = (LabelingCell<L>)CACHE.get(this.stringHashCode());

if (tmp == null) {
// Creates empty CachedObjectAccesses which know how to reconstruct the managed objects.
m_metadataAccess = new CachedObjectAccess<>(getFileStore(), null, m_fileMetadata.getOffset(), null);
m_labelingAccess =
new CachedObjectAccess<>(getFileStore(), null, m_fileMetadata.getOffset(), new StreamSkipper() {
/**
* {@inheritDoc}
*/
@Override
public void skip(final BufferedDataInputStream in) {
try {
m_metadataAccess.setObject(ExternalizerManager.read(in));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
});

CACHE.put(this, this);
m_labelingAccess = new CachedObjectAccess<>(getFileStore(), null, m_fileMetadata.getOffset(), in -> {
try {
m_metadataAccess.setObject(ExternalizerManager.read(in));
} catch (Exception e) {
throw new RuntimeException(e);
}
});

CACHE.put(this.stringHashCode(), this);
} else {
m_labelingAccess = tmp.m_labelingAccess;
m_metadataAccess = tmp.m_metadataAccess;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,50 +66,44 @@
/**
* {@link CacheService} implementation wrapping a guava {@link Cache}.
*/
@Plugin(type = Service.class, priority = Priority.HIGH_PRIORITY)
@Plugin(type = Service.class, priority = Priority.HIGH)
public class KNIPGuavaCacheService extends AbstractService implements CacheService {

@Parameter
private MemoryService ms;

private Cache<Integer, Object> cache;
private Cache<String, Object> cache;

private final Semaphore gate = new Semaphore(1);

@Override
public void initialize() {
//FIXME: Make parameters accessible via image processing config at some point
cache = CacheBuilder.newBuilder().maximumSize(1000).weakValues()
.build();

ms.register(new MemoryAlertable() {

@Override
public void memoryLow() {
if (gate.tryAcquire()) {
cache.invalidateAll();
cache.cleanUp();
gate.release();
}
cache = CacheBuilder.newBuilder().maximumSize(1000).weakValues().build();

ms.register(() -> {
if (gate.tryAcquire()) {
cache.invalidateAll();
cache.cleanUp();
gate.release();
}
});
}

@Override
public void put(final Object key, final Object value) {
cache.put(key.hashCode(), value);
cache.put(key.toString(), value);
}

@Override
public Object get(final Object key) {
return cache.getIfPresent(key.hashCode());
return cache.getIfPresent(key.toString());
}

@SuppressWarnings("unchecked")
@Override
public <V> V get(final Object key, final Callable<V> valueLoader) throws ExecutionException {
return (V)cache.get(key.hashCode(), valueLoader);
return (V)cache.get(key.toString(), valueLoader);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ public class AWTImageProvider extends HiddenViewerComponent {

private static final NodeLogger LOGGER = NodeLogger.getLogger(AWTImageProvider.class);

private static final String AWT_IMAGE_PROVIDE_KEY = "AP";

/**
* Converts DoubleType to FloatType and preserves other types. This can be used to ensure that images (after calling
* the method) are FloatType or smaller and thus can be normalized. However type safety is broken!
Expand Down Expand Up @@ -158,13 +160,13 @@ private void renderAndCacheImg() {
Image awtImage = null;
if (m_isCachingActive) {

final int hash = (31 + m_renderUnit.generateHashCode());
awtImage = (Image)KNIPGateway.cache().get(hash);
final String hashKey = AWT_IMAGE_PROVIDE_KEY + m_renderUnit.generateHashCode();
awtImage = (Image)KNIPGateway.cache().get(hashKey);

if (awtImage == null) {
awtImage = m_renderUnit.createImage();

KNIPGateway.cache().put(hash, awtImage);
KNIPGateway.cache().put(hashKey, awtImage);
LOGGER.info("Caching Image ...");
} else {
LOGGER.info("Image from Cache ...");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@
*/
public class KNIPCachedOpEnvironment extends CustomOpEnvironment {

@Parameter
private CacheService cs;
private Collection<Class<?>> ignored;

public KNIPCachedOpEnvironment(final OpEnvironment parent, final Collection<? extends OpInfo> prioritizedInfos,
Expand Down
Loading

0 comments on commit bc7e9fa

Please sign in to comment.