blob: 9b247075d1da43c7d46d37c72c11c174099b3d2b [file] [log] [blame]
/*
* Copyright (c) 2016 Audi AG
* 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.mdm.mdfsorter;
import java.nio.ByteBuffer;
import java.util.AbstractMap;
import org.eclipse.mdm.mdfsorter.mdf4.MDF4ProcessWriter;
/**
* Cache for outgoing Data. This class stores data to be written, until a usuful
* amout is collected. If this size is reached, the write out will be performed.
*
* Cache size should be at least as large as the process
* writers<code>MAX_OUTPUTBLOCKSIZE</code> value, because otherwise large blocks
* will be splitted into smaller pieces, slowing down the write operation.
*/
public class WriteDataCache {
private static final int WRITE_CACHE_SIZE = MDF4ProcessWriter.MAX_OUTPUTBLOCKSIZE / 2;
/**
* The buffer the data is send to, once the cache is full
*/
DataBlockBuffer buf;
byte[] cache;
int cachewriteposition = 0;
public WriteDataCache(DataBlockBuffer buf) {
this.buf = buf;
}
/**
* Puts length bytes from the given ByteBuffer into the cache.
*
* @param data
* The ByteBuffer.
* @param length
* The number of Bytes from the Buffers current position to be
* written.
* @param reused
* True, if the current buffer contains other data, that will be
* overwritten or its position can be changed until output.
* Therefore its content needs to be copied. False if the
* Buffer.array() method can be used, for faster access to the
* data bytes. Therefore the size of the ByteBuffer and length
* must be equal.
*/
public void put(ByteBuffer data, int length, boolean reused) {
if (reused) {
if (length > WRITE_CACHE_SIZE) {
byte[] dt = new byte[length];
data.get(dt, 0, length);
put(dt);
} else {
// copy to cache immediately
// use the cache
// first write part that still fits into cache.
if (cache == null) {
cache = new byte[WRITE_CACHE_SIZE];
}
int spaceremaining = WRITE_CACHE_SIZE - cachewriteposition;
int bytesfirstsection = spaceremaining < length ? spaceremaining : length;
// maybe data needs to be split up
data.get(cache, cachewriteposition, bytesfirstsection);
cachewriteposition += bytesfirstsection;
CheckAndWriteout();
// write second part if needed
if (bytesfirstsection < length) {
int bytessecond = length - bytesfirstsection;
data.get(cache, cachewriteposition, bytessecond);
cachewriteposition += bytessecond;
}
}
} else {
put(data.array());
}
}
/**
* Puts the array data in the WriteCache.
*
* @param data
* The data, which should be put in the Cache.
*/
public void put(byte[] data) {
// Cache is useless;
int length = data.length;
if (length > WRITE_CACHE_SIZE) {
flush(); // flush data from the cache
buf.putData(new AbstractMap.SimpleEntry<byte[], Integer>(data, -1));
} else {
// use the cache
// first write part that still fits into cache.
if (cache == null) {
cache = new byte[WRITE_CACHE_SIZE];
}
int spaceremaining = WRITE_CACHE_SIZE - cachewriteposition;
int bytesfirstsection = spaceremaining < length ? spaceremaining : length;
// maybe data needs to be split up
System.arraycopy(data, 0, cache, cachewriteposition, bytesfirstsection);
cachewriteposition += bytesfirstsection;
CheckAndWriteout();
// write second part if needed
if (bytesfirstsection < length) {
int bytessecond = length - bytesfirstsection;
System.arraycopy(data, bytesfirstsection, cache, cachewriteposition, bytessecond);
cachewriteposition += bytessecond;
}
}
}
/**
* Force data in the Cache to be written out.
*/
public void flush() {
// Cache has been flushed?
if (cache != null) {
buf.putData(new AbstractMap.SimpleEntry<byte[], Integer>(cache, cachewriteposition));
cachewriteposition = 0;
cache = null;
}
}
public void CheckAndWriteout() {
if (cachewriteposition == WRITE_CACHE_SIZE) {
// write all data out.
buf.putData(new AbstractMap.SimpleEntry<byte[], Integer>(cache, -1));
cache = new byte[WRITE_CACHE_SIZE];
cachewriteposition = 0;
}
}
}