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 @SuppressWarnings("deprecation") 127 @Override 128 public void setSlice(IMonitor mon, IDataset data, SliceND slice) throws IOException { 129 if (slice.isExpanded()) { 130 Dataset od = d; 131 d = DatasetFactory.zeros(slice.getSourceShape(), od.getDType()); 132 d.setSlice(od, SliceND.createSlice(od, null, null)); 133 } 134 d.setSlice(data, slice); 135 } 136 }); 137 } 138 139 @Override 140 public int[] getChunking() { 141 return chunks; 142 } 143 144 @Override 145 public void setChunking(int... chunks) { 146 this.chunks = chunks == null ? null : chunks.clone(); 147 } 148 149 @Override 150 public LazyWriteableDataset clone() { 151 LazyWriteableDataset ret = new LazyWriteableDataset(new String(name), getDType(), getElementsPerItem(), 152 oShape, maxShape, chunks, saver); 153 ret.shape = shape; 154 ret.size = size; 155 ret.prepShape = prepShape; 156 ret.postShape = postShape; 157 ret.begSlice = begSlice; 158 ret.delSlice = delSlice; 159 ret.map = map; 160 ret.base = base; 161 ret.metadata = copyMetadata(); 162 ret.oMetadata = oMetadata; 163 ret.eventDelegate = eventDelegate; 164 return ret; 165 } 166 167 @Override 168 public LazyWriteableDataset getSliceView(int[] start, int[] stop, int[] step) { 169 return (LazyWriteableDataset) super.getSliceView(start, stop, step); 170 } 171 172 @Override 173 public LazyWriteableDataset getSliceView(Slice... slice) { 174 return (LazyWriteableDataset) super.getSliceView(slice); 175 } 176 177 @Override 178 public LazyWriteableDataset getSliceView(SliceND slice) { 179 return (LazyWriteableDataset) super.getSliceView(slice); 180 } 181 182 @Override 183 public LazyWriteableDataset getTransposedView(int... axes) { 184 return (LazyWriteableDataset) super.getTransposedView(axes); 185 } 186 187 @Override 188 public void setWritingAsync(boolean async) { 189 writeAsync = async; 190 } 191 192 /** 193 * Set a slice of the dataset 194 * 195 * @param data 196 * @param slice an n-D slice 197 * @throws DatasetException 198 */ 199 public void setSlice(IDataset data, SliceND slice) throws DatasetException { 200 setSlice(null, data, slice); 201 } 202 203 @Override 204 public void setSlice(IMonitor monitor, IDataset data, int[] start, int[] stop, int[] step) throws DatasetException { 205 internalSetSlice(monitor, writeAsync, data, new SliceND(shape, maxShape, start, stop, step)); 206 } 207 208 @Override 209 public void setSlice(IMonitor monitor, IDataset data, SliceND slice) throws DatasetException { 210 internalSetSlice(monitor, writeAsync, data, slice); 211 } 212 213 @Override 214 public void setSliceSync(IMonitor monitor, IDataset data, SliceND slice) throws DatasetException { 215 internalSetSlice(monitor, false, data, slice); 216 } 217 218 private void internalSetSlice(IMonitor monitor, final boolean async, IDataset data, SliceND slice) throws DatasetException { 219 int[] dshape = data instanceof Dataset ? ((Dataset) data).getShapeRef() : data.getShape(); 220 if (dshape.length == 0) { // fix zero-rank case 221 dshape = new int[] {1}; // FIXME remove 222 } 223 // if necessary, reshape the input data according to the shape of the slice 224 if (!Arrays.equals(slice.getShape(), dshape)) { 225 data = data.getSliceView(); 226 data.setShape(slice.getShape()); 227 } 228 229 SliceND nslice = calcTrueSlice(slice); 230 data = transformInput(data); 231 232 if (base != null) { 233 ((ILazyWriteableDataset) base).setSlice(monitor, data, nslice); 234 } else { 235 if (saver == null) { 236 throw new DatasetException("Cannot write to file as saver not defined!"); 237 } 238 239 try { 240 if (async && saver instanceof ILazyAsyncSaver) { 241 ((ILazyAsyncSaver)saver).setSliceAsync(monitor, data, nslice); 242 } else { 243 if (!saver.isFileWriteable()) { 244 throw new DatasetException("Cannot write to file as it is not writeable!"); 245 } 246 saver.setSlice(monitor, data, nslice); 247 } 248 } catch (IOException e) { 249 throw new DatasetException("Could not save dataset", e); 250 } 251 if (!refreshShape()) { // send event as data has changed 252 eventDelegate.fire(new DataEvent(name, shape)); 253 } 254 } 255 } 256 257 /** 258 * Set saver (and also loader) 259 * @param saver 260 */ 261 @Override 262 public void setSaver(ILazySaver saver) { 263 this.saver = saver; 264 this.loader = saver; 265 } 266 267 @Override 268 protected SliceND createSlice(int[] nstart, int[] nstop, int[] nstep) { 269 if (base == null) { 270 return new SliceND(oShape, maxShape, nstart, nstop, nstep); 271 } 272 return base.createSlice(nstart, nstop, nstep); 273 } 274 275 @Override 276 public Object getFillValue() { 277 return fillValue; 278 } 279 280 @Override 281 public void setFillValue(Object fill) { 282 fillValue = fill; 283 } 284}