001/*- 002 * Copyright 2015, 2016 Diamond Light Source Ltd. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 */ 009 010package org.eclipse.january.dataset; 011 012import java.io.IOException; 013import java.util.Arrays; 014 015import org.eclipse.january.DatasetException; 016import org.eclipse.january.IMonitor; 017import org.eclipse.january.io.ILazyAsyncSaver; 018import org.eclipse.january.io.ILazySaver; 019 020/** 021 * Subclass of lazy dataset that allows setting slices 022 */ 023public class LazyWriteableDataset extends LazyDynamicDataset implements ILazyWriteableDataset { 024 private static final long serialVersionUID = -679846418938412535L; 025 private int[] chunks; 026 private ILazySaver saver; 027 private Object fillValue; 028 private boolean writeAsync; 029 030 /** 031 * Create a lazy dataset 032 * @param name 033 * @param dtype dataset type 034 * @param elements 035 * @param shape 036 * @param maxShape 037 * @param chunks 038 * @param saver 039 */ 040 public LazyWriteableDataset(String name, int dtype, int elements, int[] shape, int[] maxShape, int[] chunks, ILazySaver saver) { 041 super(name, dtype, elements, shape, maxShape, saver); 042 this.chunks = chunks == null ? null : chunks.clone(); 043 this.saver = saver; 044 045 size = ShapeUtils.calcLongSize(this.shape); 046 } 047 048 /** 049 * Create a lazy dataset 050 * @param name 051 * @param dtype dataset type 052 * @param shape 053 * @param maxShape 054 * @param chunks 055 * @param saver 056 */ 057 public LazyWriteableDataset(String name, int dtype, int[] shape, int[] maxShape, int[] chunks, ILazySaver saver) { 058 this(name, dtype, 1, shape, maxShape, chunks, saver); 059 } 060 061 /** 062 * Create a lazy dataset 063 * @param name 064 * @param clazz dataset element class 065 * @param elements 066 * @param shape 067 * @param maxShape 068 * @param chunks 069 * @param saver 070 */ 071 public LazyWriteableDataset(String name, Class<?> clazz, int elements, int[] shape, int[] maxShape, int[] chunks, ILazySaver saver) { 072 this(name, DTypeUtils.getDTypeFromClass(clazz), elements, shape, maxShape, chunks, saver); 073 } 074 075 /** 076 * Create a lazy dataset 077 * @param name 078 * @param clazz dataset element class 079 * @param shape 080 * @param maxShape 081 * @param chunks 082 * @param saver 083 */ 084 public LazyWriteableDataset(String name, Class<?> clazz, int[] shape, int[] maxShape, int[] chunks, ILazySaver saver) { 085 this(name, DTypeUtils.getDTypeFromClass(clazz), 1, shape, maxShape, chunks, saver); 086 } 087 088 /** 089 * Create a lazy writeable dataset based on in-memory data (handy for testing) 090 * @param dataset 091 */ 092 public static LazyWriteableDataset createLazyDataset(final Dataset dataset) { 093 return createLazyDataset(dataset, null); 094 } 095 096 /** 097 * Create a lazy writeable dataset based on in-memory data (handy for testing) 098 * @param dataset 099 */ 100 public static LazyWriteableDataset createLazyDataset(final Dataset dataset, final int[] maxShape) { 101 return new LazyWriteableDataset(dataset.getName(), dataset.getDType(), dataset.getElementsPerItem(), dataset.getShape(), 102 maxShape, null, 103 new ILazySaver() { 104 private static final long serialVersionUID = ILazySaver.serialVersionUID; 105 106 Dataset d = dataset; 107 @Override 108 public boolean isFileReadable() { 109 return true; 110 } 111 112 @Override 113 public boolean isFileWriteable() { 114 return true; 115 } 116 117 @Override 118 public void initialize() throws IOException { 119 } 120 121 @Override 122 public Dataset getDataset(IMonitor mon, SliceND slice) throws IOException { 123 return d.getSlice(mon, slice); 124 } 125 126 @Override 127 public void setSlice(IMonitor mon, IDataset data, SliceND slice) throws IOException { 128 if (slice.isExpanded()) { 129 Dataset od = d; 130 d = DatasetFactory.zeros(od.getClass(), slice.getSourceShape()); 131 d.setSlice(od, SliceND.createSlice(od, null, null)); 132 } 133 d.setSlice(data, slice); 134 } 135 }); 136 } 137 138 @Override 139 public int[] getChunking() { 140 return chunks; 141 } 142 143 @Override 144 public void setChunking(int... chunks) { 145 this.chunks = chunks == null ? null : chunks.clone(); 146 } 147 148 @Override 149 public LazyWriteableDataset clone() { 150 LazyWriteableDataset ret = new LazyWriteableDataset(new String(name), getDType(), getElementsPerItem(), 151 oShape, maxShape, chunks, saver); 152 ret.shape = shape; 153 ret.size = size; 154 ret.prepShape = prepShape; 155 ret.postShape = postShape; 156 ret.begSlice = begSlice; 157 ret.delSlice = delSlice; 158 ret.map = map; 159 ret.base = base; 160 ret.metadata = copyMetadata(); 161 ret.oMetadata = oMetadata; 162 ret.eventDelegate = eventDelegate; 163 return ret; 164 } 165 166 @Override 167 public LazyWriteableDataset getSliceView(int[] start, int[] stop, int[] step) { 168 return (LazyWriteableDataset) super.getSliceView(start, stop, step); 169 } 170 171 @Override 172 public LazyWriteableDataset getSliceView(Slice... slice) { 173 return (LazyWriteableDataset) super.getSliceView(slice); 174 } 175 176 @Override 177 public LazyWriteableDataset getSliceView(SliceND slice) { 178 return (LazyWriteableDataset) super.getSliceView(slice); 179 } 180 181 @Override 182 public LazyWriteableDataset getTransposedView(int... axes) { 183 return (LazyWriteableDataset) super.getTransposedView(axes); 184 } 185 186 @Override 187 public void setWritingAsync(boolean async) { 188 writeAsync = async; 189 } 190 191 /** 192 * Set a slice of the dataset 193 * 194 * @param data 195 * @param slice an n-D slice 196 * @throws DatasetException 197 */ 198 public void setSlice(IDataset data, SliceND slice) throws DatasetException { 199 setSlice(null, data, slice); 200 } 201 202 @Override 203 public void setSlice(IMonitor monitor, IDataset data, int[] start, int[] stop, int[] step) throws DatasetException { 204 internalSetSlice(monitor, writeAsync, data, new SliceND(shape, maxShape, start, stop, step)); 205 } 206 207 @Override 208 public void setSlice(IMonitor monitor, IDataset data, SliceND slice) throws DatasetException { 209 internalSetSlice(monitor, writeAsync, data, slice); 210 } 211 212 @Override 213 public void setSliceSync(IMonitor monitor, IDataset data, SliceND slice) throws DatasetException { 214 internalSetSlice(monitor, false, data, slice); 215 } 216 217 private void internalSetSlice(IMonitor monitor, final boolean async, IDataset data, SliceND slice) throws DatasetException { 218 int[] dshape = data instanceof Dataset ? ((Dataset) data).getShapeRef() : data.getShape(); 219 if (dshape.length == 0) { // fix zero-rank case 220 dshape = new int[] {1}; // FIXME remove 221 } 222 // if necessary, reshape the input data according to the shape of the slice 223 if (!Arrays.equals(slice.getShape(), dshape)) { 224 data = data.getSliceView(); 225 data.setShape(slice.getShape()); 226 } 227 228 SliceND nslice = calcTrueSlice(slice); 229 data = transformInput(data); 230 231 if (base != null) { 232 ((ILazyWriteableDataset) base).setSlice(monitor, data, nslice); 233 } else { 234 if (saver == null) { 235 throw new DatasetException("Cannot write to file as saver not defined!"); 236 } 237 238 try { 239 if (async && saver instanceof ILazyAsyncSaver) { 240 ((ILazyAsyncSaver)saver).setSliceAsync(monitor, data, nslice); 241 } else { 242 if (!saver.isFileWriteable()) { 243 throw new DatasetException("Cannot write to file as it is not writeable!"); 244 } 245 saver.setSlice(monitor, data, nslice); 246 } 247 } catch (IOException e) { 248 throw new DatasetException("Could not save dataset", e); 249 } 250 if (!refreshShape()) { // send event as data has changed 251 eventDelegate.fire(new DataEvent(name, shape)); 252 } 253 } 254 } 255 256 /** 257 * Set saver (and also loader) 258 * @param saver 259 */ 260 @Override 261 public void setSaver(ILazySaver saver) { 262 this.saver = saver; 263 this.loader = saver; 264 } 265 266 @Override 267 protected SliceND createSlice(int[] nstart, int[] nstop, int[] nstep) { 268 if (base == null) { 269 return new SliceND(oShape, maxShape, nstart, nstop, nstep); 270 } 271 return base.createSlice(nstart, nstop, nstep); 272 } 273 274 @Override 275 public Object getFillValue() { 276 return fillValue; 277 } 278 279 @Override 280 public void setFillValue(Object fill) { 281 fillValue = fill; 282 } 283}