📄 fileobjectmemory.java
字号:
/*
* Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.store.fs;
import java.io.EOFException;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import org.h2.compress.CompressLZF;
import org.h2.util.MathUtils;
/**
* This class is an abstraction of an in-memory random access file.
* Data compression using the LZF algorithm is supported as well.
*/
public class FileObjectMemory implements FileObject {
private static final int CACHE_SIZE = 8;
private static final int BLOCK_SIZE_SHIFT = 16;
private static final int BLOCK_SIZE = 1 << BLOCK_SIZE_SHIFT;
private static final int BLOCK_SIZE_MASK = BLOCK_SIZE - 1;
private String name;
private final boolean compress;
private long length;
private long pos;
private byte[][] data;
private long lastModified;
private static final CompressLZF LZF = new CompressLZF();
private static final byte[] BUFFER = new byte[BLOCK_SIZE * 2];
private static final byte[] COMPRESSED_BLOCK;
//#ifdef JDK14
static class Cache extends LinkedHashMap {
private static final long serialVersionUID = 5549197956072850355L;
private int size;
public Cache(int size) {
this.size = size;
}
protected boolean removeEldestEntry(Map.Entry eldest) {
if (size() < size) {
return false;
}
CompressItem c = (CompressItem) eldest.getKey();
compress(c.data, c.l);
return true;
}
}
static class CompressItem {
byte[][] data;
int l;
public int hashCode() {
return data.hashCode() ^ l;
}
public boolean equals(Object o) {
if (o instanceof CompressItem) {
CompressItem c = (CompressItem) o;
return c.data == data && c.l == l;
}
return false;
}
}
private static final Cache COMPRESS_LATER = new Cache(CACHE_SIZE);
//#endif
private static void compressLater(byte[][] data, int l) {
//#ifdef JDK14
CompressItem c = new CompressItem();
c.data = data;
c.l = l;
synchronized (LZF) {
COMPRESS_LATER.put(c, c);
}
//#endif
}
private static void expand(byte[][] data, int i) {
byte[] d = data[i];
if (d.length == BLOCK_SIZE) {
return;
}
byte[] out = new byte[BLOCK_SIZE];
synchronized (LZF) {
LZF.expand(d, 0, d.length, out, 0, BLOCK_SIZE);
}
data[i] = out;
}
private static void compress(byte[][] data, int i) {
byte[] d = data[i];
synchronized (LZF) {
int len = LZF.compress(d, BLOCK_SIZE, BUFFER, 0);
if (len <= BLOCK_SIZE) {
d = new byte[len];
System.arraycopy(BUFFER, 0, d, 0, len);
data[i] = d;
}
}
}
static {
byte[] n = new byte[BLOCK_SIZE];
int len = LZF.compress(n, BLOCK_SIZE, BUFFER, 0);
COMPRESSED_BLOCK = new byte[len];
System.arraycopy(BUFFER, 0, COMPRESSED_BLOCK, 0, len);
}
public FileObjectMemory(String name, boolean compress) {
this.name = name;
this.compress = compress;
data = new byte[0][];
touch();
}
private void touch() {
lastModified = System.currentTimeMillis();
}
public long length() {
return length;
}
public void setFileLength(long l) {
touch();
if (l < length) {
pos = Math.min(pos, l);
changeLength(l);
long end = MathUtils.roundUpLong(l, BLOCK_SIZE);
if (end != l) {
int lastBlock = (int) (l >>> BLOCK_SIZE_SHIFT);
expand(data, lastBlock);
byte[] d = data[lastBlock];
for (int i = (int) (l & BLOCK_SIZE_MASK); i < BLOCK_SIZE; i++) {
d[i] = 0;
}
if (compress) {
compressLater(data, lastBlock);
}
}
} else {
changeLength(l);
}
}
public void seek(long pos) {
this.pos = (int) pos;
}
private void changeLength(long len) {
length = len;
len = MathUtils.roundUpLong(len, BLOCK_SIZE);
int blocks = (int) (len >>> BLOCK_SIZE_SHIFT);
if (blocks != data.length) {
byte[][] n = new byte[blocks][];
System.arraycopy(data, 0, n, 0, Math.min(data.length, n.length));
for (int i = data.length; i < blocks; i++) {
n[i] = COMPRESSED_BLOCK;
}
data = n;
}
}
private void readWrite(byte[] b, int off, int len, boolean write) throws IOException {
long end = pos + len;
if (end > length) {
if (write) {
changeLength(end);
} else {
if (len == 0) {
return;
}
throw new EOFException("File: " + name);
}
}
while (len > 0) {
int l = (int) Math.min(len, BLOCK_SIZE - (pos & BLOCK_SIZE_MASK));
int id = (int) (pos >>> BLOCK_SIZE_SHIFT);
expand(data, id);
byte[] block = data[id];
int blockOffset = (int) (pos & BLOCK_SIZE_MASK);
if (write) {
System.arraycopy(b, off, block, blockOffset, l);
} else {
System.arraycopy(block, blockOffset, b, off, l);
}
if (compress) {
compressLater(data, id);
}
off += l;
pos += l;
len -= l;
}
}
public void write(byte[] b, int off, int len) throws IOException {
touch();
readWrite(b, off, len, true);
}
public void readFully(byte[] b, int off, int len) throws IOException {
readWrite(b, off, len, false);
}
public long getFilePointer() {
return pos;
}
public void close() {
pos = 0;
}
public void sync() throws IOException {
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public long getLastModified() {
return lastModified;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -