All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.dawnsci.hdf5.HDF5LazySaver Maven / Gradle / Ivy

/*-
 * Copyright 2015 Diamond Light Source Ltd.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 */

package org.eclipse.dawnsci.hdf5;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.Arrays;

import org.eclipse.dawnsci.analysis.api.io.ScanFileHolderException;
import org.eclipse.dawnsci.analysis.api.tree.Node;
import org.eclipse.dawnsci.analysis.api.tree.Tree;
import org.eclipse.dawnsci.nexus.NexusException;
import org.eclipse.january.IMonitor;
import org.eclipse.january.dataset.DatasetUtils;
import org.eclipse.january.dataset.IDataset;
import org.eclipse.january.dataset.ILazyWriteableDataset;
import org.eclipse.january.dataset.SliceND;
import org.eclipse.january.io.ILazyAsyncSaver;

/**
 * Lazy saver for HDF5 files
 */
public class HDF5LazySaver extends HDF5LazyLoader implements ILazyAsyncSaver, Serializable {

	private static final long serialVersionUID = -5244067010482825423L;

	boolean isWriteable;
	private String parentPath; // path of group containing dataset
	private int[] maxShape;
	private int[] chunks;
	private Object fill;
	private boolean create = false; // create on first slice setting
	private boolean init = false;   // has been initialized?

	private ILazyWriteableDataset writeableDataset;

	private String dataPath;

	/**
	 * 
	 * @param hostname
	 * @param filename
	 * @param node
	 * @param name
	 * @param trueShape
	 * @param isize
	 * @param dtype
	 * @param extendUnsigned
	 * @param maxShape
	 * @param chunks
	 * @param fill null, a String or single value array
	 */
	public HDF5LazySaver(String hostname, String filename, String node, String name, int[] trueShape, int isize,
			int dtype, boolean extendUnsigned, int[] maxShape, int[] chunks, Object fill) {
		super(hostname, filename, node, name, trueShape, isize, dtype, extendUnsigned);
		int i = node.lastIndexOf(Node.SEPARATOR);
		if (i > 0) {
			parentPath = node.substring(0, i);
		} else {
			parentPath = Tree.ROOT;
		}
		this.maxShape = maxShape == null ? trueShape.clone() : maxShape.clone();
		this.chunks = chunks == null ? null : chunks.clone();
		this.fill = fill;
		isWriteable = false;
		dataPath = HDF5Utils.absolutePathToData(parentPath, name);
	}

	/**
	 * Set flag to create the dataset on file when the first slice is set
	 * @param create this is false by default (i.e. no dataset is created)
	 */
	public void setCreateOnInitialization(boolean create) {
		if (init) {
			throw new UnsupportedOperationException("It is too late for this flag to have any effect as the first slice has already been set");
		}
		this.create = create;
	}

	/**
	 * Set flag to indicate the dataset has already been created on file
	 */
	public void setAlreadyCreated() {
		create = true;
		init = true;
	}

	@Override
	public boolean isFileWriteable() {
		if (!isWriteable && (!init || create || isFileReadable())) {
			if (file == null) {
				file = new File(filePath);
			}
			isWriteable = file.exists() ? file.canWrite() : file.getParentFile().canWrite();
		}

		return isWriteable;
	}

	@Override
	public void initialize() throws IOException {
		if (!init) {
			init = true;
			if (create) {
				try {
					HDF5Utils.createDataset(filePath, parentPath, name, trueShape, maxShape, chunks, dtype, fill, false);
				} catch (ScanFileHolderException e) {
					throw new IOException(e);
				}
			}
		}
	}

	@Override
	public void setSlice(IMonitor mon, IDataset data, SliceND slice) throws IOException {
		if (!init) {
			boolean zeroes = false;
			for (int i : trueShape) {
				if (i == 0) {
					zeroes = true;
					break;
				}
			}
			if (zeroes) {
				trueShape = slice.getSourceShape().clone();
			}
			initialize();
		}
		if (data.getRank() == 0) {
			data = data.getSliceView();
			data.setShape(slice.getShape());
		}

		// higher level API does not cope with differing data types
		data = DatasetUtils.cast(data, dtype);
		try {
			if (!create) { // ensure create on first use
				HDF5Utils.setDatasetSlice(filePath, parentPath, name, slice, data);
				create = true;
			} else {
				HDF5File fid = HDF5FileFactory.acquireFile(filePath, true);
				try {
					HDF5Utils.writeDatasetSlice(fid, dataPath, slice, data);
				} catch (NexusException e) {
					throw new ScanFileHolderException("Problem writing slice to dataset", e);
				} finally {
					fid.decrementCount();
				}
			}
			expandShape(slice);
			if (mon != null) {
				if (mon.isCancelled()) {
					return;
				}
				mon.worked(1);
			}
		} catch (ScanFileHolderException e) {
			throw new IOException(e);
		}
	}

	/**
	 * Set to asynchronously write if lazy writeable dataset is not null
	 * 

* The dataset must correspond to that held by this saver otherwise mismatches * can occur between the shape * @param dataset */ public void setAsyncWriteableDataset(ILazyWriteableDataset dataset) { if (!Arrays.equals(dataset.getChunking(), chunks)) { throw new IllegalArgumentException("Chunk size of given dataset must match saver's"); } if (!Arrays.equals(dataset.getMaxShape(), maxShape)) { throw new IllegalArgumentException("Max shape of given dataset must match saver's"); } Object ofill = dataset.getFillValue(); if (fill != ofill || (fill != null && !fill.equals(ofill))) { throw new IllegalArgumentException("Fill value of given dataset must match saver's"); } this.writeableDataset = dataset; } @Override public void setSliceAsync(IMonitor mon, IDataset data, SliceND slice) throws IOException { try { HDF5File fid = HDF5FileFactory.acquireFile(filePath, true); synchronized (fid) { fid.addWriteJob(writeableDataset, data, slice); fid.decrementCount(); } expandShape(slice); } catch (ScanFileHolderException e) { logger.error("Problem setting slice of dataset in file: {}", filePath, e); throw new IOException("Problem setting slice of dataset in file: " + filePath, e); } } protected boolean expandShape(SliceND slice) { int[] eShape = slice.getSourceShape(); if (eShape.length != trueShape.length) { throw new IllegalArgumentException("Slice shape must match this saver's shape"); } boolean expand = false; for (int i = 0; i < trueShape.length; i++) { int l = eShape[i]; if (l > trueShape[i]) { trueShape[i] = l; expand = true; } } return expand; } @Override public int[] refreshShape() { return trueShape.clone(); } @Override public String toString() { return dataPath; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy