Unverified 提交 06da38de authored 作者: Noel Grandin's avatar Noel Grandin 提交者: GitHub

Merge pull request #1025 from katzyn/BitSet

Remove BitField and replace its usages with BitSet
......@@ -5,6 +5,7 @@
*/
package org.h2.command.dml;
import java.util.BitSet;
import java.util.Random;
import java.util.concurrent.TimeUnit;
......@@ -13,7 +14,6 @@ import org.h2.expression.Expression;
import org.h2.table.Plan;
import org.h2.table.PlanItem;
import org.h2.table.TableFilter;
import org.h2.util.BitField;
import org.h2.util.Permutations;
/**
......@@ -26,7 +26,7 @@ class Optimizer {
private static final int MAX_BRUTE_FORCE = 2000;
private static final int MAX_GENETIC = 500;
private long startNs;
private BitField switched;
private BitSet switched;
// possible plans for filters, if using brute force:
// 1 filter 1 plan
......@@ -163,13 +163,13 @@ class Optimizer {
}
}
if (generateRandom) {
switched = new BitField();
switched = new BitSet();
System.arraycopy(filters, 0, best, 0, filters.length);
shuffleAll(best);
System.arraycopy(best, 0, list, 0, filters.length);
}
if (testPlan(list)) {
switched = new BitField();
switched = new BitSet();
System.arraycopy(list, 0, best, 0, filters.length);
}
}
......
......@@ -8,6 +8,7 @@ package org.h2.engine;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
......@@ -64,7 +65,6 @@ import org.h2.table.TableType;
import org.h2.table.TableView;
import org.h2.tools.DeleteDbFiles;
import org.h2.tools.Server;
import org.h2.util.BitField;
import org.h2.util.JdbcUtils;
import org.h2.util.MathUtils;
import org.h2.util.NetUtils;
......@@ -123,7 +123,7 @@ public class Database implements DataHandler {
private final Set<Session> userSessions =
Collections.synchronizedSet(new HashSet<Session>());
private final AtomicReference<Session> exclusiveSession = new AtomicReference<>();
private final BitField objectIds = new BitField();
private final BitSet objectIds = new BitSet();
private final Object lobSyncObject = new Object();
private Schema mainSchema;
......@@ -792,7 +792,7 @@ public class Database implements DataHandler {
}
// mark all ids used in the page store
if (pageStore != null) {
BitField f = pageStore.getObjectIds();
BitSet f = pageStore.getObjectIds();
for (int i = 0, len = f.length(); i < len; i++) {
if (f.get(i) && !objectIds.get(i)) {
trace.info("unused object id: " + i);
......
......@@ -22,6 +22,7 @@ import java.sql.SQLException;
import java.sql.SQLXML;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.BitSet;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
......@@ -29,7 +30,6 @@ import org.h2.api.ErrorCode;
import org.h2.expression.ParameterInterface;
import org.h2.message.DbException;
import org.h2.message.TraceObject;
import org.h2.util.BitField;
import org.h2.value.ValueNull;
/**
......@@ -41,7 +41,7 @@ import org.h2.value.ValueNull;
public class JdbcCallableStatement extends JdbcPreparedStatement implements
CallableStatement, JdbcCallableStatementBackwardsCompat {
private BitField outParameters;
private BitSet outParameters;
private int maxOutParameters;
private HashMap<String, Integer> namedParameters;
......@@ -1637,7 +1637,7 @@ public class JdbcCallableStatement extends JdbcPreparedStatement implements
maxOutParameters = Math.min(
getParameterMetaData().getParameterCount(),
getCheckedMetaData().getColumnCount());
outParameters = new BitField();
outParameters = new BitSet();
}
checkIndexBounds(parameterIndex);
ParameterInterface param = command.getParameters().get(--parameterIndex);
......
......@@ -9,6 +9,7 @@ import java.io.InputStream;
import java.lang.Thread.UncaughtExceptionHandler;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
......@@ -33,7 +34,6 @@ import org.h2.store.InDoubtTransaction;
import org.h2.store.fs.FileChannelInputStream;
import org.h2.store.fs.FileUtils;
import org.h2.table.TableBase;
import org.h2.util.BitField;
import org.h2.util.New;
/**
......@@ -263,7 +263,7 @@ public class MVTableEngine implements TableEngine {
*
* @param objectIds the ids of the objects to keep
*/
public void removeTemporaryMaps(BitField objectIds) {
public void removeTemporaryMaps(BitSet objectIds) {
for (String mapName : store.getMapNames()) {
if (mapName.startsWith("temp.")) {
MVMap<?, ?> map = store.openMap(mapName);
......
......@@ -5,8 +5,9 @@
*/
package org.h2.store;
import java.util.BitSet;
import org.h2.engine.Session;
import org.h2.util.BitField;
/**
* The list of free pages of a page store. The format of a free list trunk page
......@@ -22,18 +23,17 @@ public class PageFreeList extends Page {
private static final int DATA_START = 3;
private final PageStore store;
private final BitField used;
private final BitSet used;
private final int pageCount;
private boolean full;
private Data data;
private PageFreeList(PageStore store, int pageId) {
private PageFreeList(PageStore store, int pageId, int pageCount, BitSet used) {
// kept in cache, and array list in page store
setPos(pageId);
this.store = store;
pageCount = (store.getPageSize() - DATA_START) * 8;
used = new BitField(pageCount);
used.set(0);
this.pageCount = pageCount;
this.used = used;
}
/**
......@@ -45,9 +45,15 @@ public class PageFreeList extends Page {
* @return the page
*/
static PageFreeList read(PageStore store, Data data, int pageId) {
PageFreeList p = new PageFreeList(store, pageId);
data.reset();
data.readByte();
data.readShortInt();
int length = store.getPageSize() - DATA_START;
byte[] b = new byte[length];
data.read(b, 0, b.length);
PageFreeList p = new PageFreeList(store, pageId, length * 8, BitSet.valueOf(b));
p.data = data;
p.read();
p.full = false;
return p;
}
......@@ -59,7 +65,10 @@ public class PageFreeList extends Page {
* @return the page
*/
static PageFreeList create(PageStore store, int pageId) {
return new PageFreeList(store, pageId);
int pageCount = (store.getPageSize() - DATA_START) * 8;
BitSet used = new BitSet(pageCount);
used.set(0);
return new PageFreeList(store, pageId, pageCount, used);
}
/**
......@@ -69,7 +78,7 @@ public class PageFreeList extends Page {
* @param first the first page to look for
* @return the page, or -1 if all pages are used
*/
int allocate(BitField exclude, int first) {
int allocate(BitSet exclude, int first) {
if (full) {
return -1;
}
......@@ -152,27 +161,17 @@ public class PageFreeList extends Page {
store.update(this);
}
/**
* Read the page from the disk.
*/
private void read() {
data.reset();
data.readByte();
data.readShortInt();
for (int i = 0; i < pageCount; i += 8) {
int x = data.readByte() & 255;
used.setByte(i, x);
}
full = false;
}
@Override
public void write() {
data = store.createData();
data.writeByte((byte) Page.TYPE_FREE_LIST);
data.writeShortInt(0);
for (int i = 0; i < pageCount; i += 8) {
data.writeByte((byte) used.getByte(i));
int cnt = pageCount >>> 3;
byte[] b = used.toByteArray();
int l = Math.min(b.length, cnt);
data.write(b, 0, l);
for (int i = cnt - l; i > 0; i--) {
data.writeByte((byte) 0);
}
store.writePage(getPos(), data);
}
......
......@@ -8,9 +8,10 @@ package org.h2.store;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.util.BitSet;
import org.h2.message.DbException;
import org.h2.message.Trace;
import org.h2.util.BitField;
/**
* An input stream that reads from a page store.
......@@ -132,8 +133,8 @@ public class PageInputStream extends InputStream {
*
* @return the bit set
*/
BitField allocateAllPages() {
BitField pages = new BitField();
BitSet allocateAllPages() {
BitSet pages = new BitSet();
int key = logKey;
PageStreamTrunk.Iterator it = new PageStreamTrunk.Iterator(
store, firstTrunkPage);
......
......@@ -8,6 +8,7 @@ package org.h2.store;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashMap;
import org.h2.api.ErrorCode;
import org.h2.compress.CompressLZF;
......@@ -17,7 +18,6 @@ import org.h2.message.DbException;
import org.h2.message.Trace;
import org.h2.result.Row;
import org.h2.result.RowFactory;
import org.h2.util.BitField;
import org.h2.util.IntArray;
import org.h2.util.IntIntHashMap;
import org.h2.util.New;
......@@ -132,13 +132,13 @@ public class PageLog {
* If the bit is set, the given page was written to the current log section.
* The undo entry of these pages doesn't need to be written again.
*/
private BitField undo = new BitField();
private BitSet undo = new BitSet();
/**
* The undo entry of those pages was written in any log section.
* These pages may not be used in the transaction log.
*/
private final BitField undoAll = new BitField();
private final BitSet undoAll = new BitSet();
/**
* The map of section ids (key) and data page where the section starts
......@@ -156,7 +156,7 @@ public class PageLog {
* The map of pages used by the transaction log.
* Only used during recovery.
*/
private BitField usedLogPages;
private BitSet usedLogPages;
/**
* This flag is set while freeing up pages.
......@@ -422,7 +422,7 @@ public class PageLog {
} catch (IOException e) {
trace.debug("log recovery completed");
}
undo = new BitField();
undo = new BitSet();
if (stage == RECOVERY_STAGE_REDO) {
usedLogPages = null;
}
......@@ -691,7 +691,7 @@ public class PageLog {
Data buffer = getBuffer();
buffer.writeByte((byte) CHECKPOINT);
write(buffer);
undo = new BitField();
undo = new BitSet();
logSectionId++;
logPos = 0;
pageOut.flush();
......
......@@ -5,9 +5,10 @@
*/
package org.h2.store;
import java.util.BitSet;
import org.h2.message.DbException;
import org.h2.message.Trace;
import org.h2.util.BitField;
import org.h2.util.IntArray;
/**
......@@ -17,7 +18,7 @@ public class PageOutputStream {
private PageStore store;
private final Trace trace;
private final BitField exclude;
private final BitSet exclude;
private final boolean atEnd;
private final int minPageId;
......@@ -42,7 +43,7 @@ public class PageOutputStream {
* @param logKey the log key of the first trunk page
* @param atEnd whether only pages at the end of the file should be used
*/
public PageOutputStream(PageStore store, int trunkPage, BitField exclude,
public PageOutputStream(PageStore store, int trunkPage, BitSet exclude,
int logKey, boolean atEnd) {
this.trace = store.getTrace();
this.store = store;
......
......@@ -8,6 +8,7 @@ package org.h2.store;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
......@@ -42,7 +43,6 @@ import org.h2.table.IndexColumn;
import org.h2.table.RegularTable;
import org.h2.table.Table;
import org.h2.table.TableType;
import org.h2.util.BitField;
import org.h2.util.Cache;
import org.h2.util.CacheLRU;
import org.h2.util.CacheObject;
......@@ -180,7 +180,7 @@ public class PageStore implements CacheWriter {
/**
* Each free page is marked with a set bit.
*/
private final BitField freed = new BitField();
private final BitSet freed = new BitSet();
private final ArrayList<PageFreeList> freeLists = New.arrayList();
private boolean recordPageReads;
......@@ -1160,7 +1160,7 @@ public class PageStore implements CacheWriter {
* @param exclude the exclude list
* @param after all allocated pages are higher than this page
*/
void allocatePages(IntArray list, int pagesToAllocate, BitField exclude,
void allocatePages(IntArray list, int pagesToAllocate, BitSet exclude,
int after) {
list.ensureCapacity(list.size() + pagesToAllocate);
for (int i = 0; i < pagesToAllocate; i++) {
......@@ -1186,7 +1186,7 @@ public class PageStore implements CacheWriter {
return pos;
}
private int allocatePage(BitField exclude, int first) {
private int allocatePage(BitSet exclude, int first) {
int page;
for (int i = firstFreeListIndex;; i++) {
PageFreeList list = getFreeList(i);
......@@ -2020,8 +2020,8 @@ public class PageStore implements CacheWriter {
this.lockFile = lockFile;
}
public BitField getObjectIds() {
BitField f = new BitField();
public BitSet getObjectIds() {
BitSet f = new BitSet();
Cursor cursor = metaIndex.find(pageStoreSession, null, null);
while (cursor.next()) {
Row row = cursor.get();
......
......@@ -21,6 +21,7 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
......@@ -62,7 +63,6 @@ import org.h2.store.PageFreeList;
import org.h2.store.PageLog;
import org.h2.store.PageStore;
import org.h2.store.fs.FileUtils;
import org.h2.util.BitField;
import org.h2.util.IOUtils;
import org.h2.util.IntArray;
import org.h2.util.MathUtils;
......@@ -1248,15 +1248,10 @@ public class Recover extends Tool implements DataHandler {
private int dumpPageFreeList(PrintWriter writer, Data s, long pageId,
long pageCount) {
int pagesAddressed = PageFreeList.getPagesAddressed(pageSize);
BitField used = new BitField();
for (int i = 0; i < pagesAddressed; i += 8) {
int x = s.readByte() & 255;
for (int j = 0; j < 8; j++) {
if ((x & (1 << j)) != 0) {
used.set(i + j);
}
}
}
int len = pagesAddressed >> 3;
byte[] b = new byte[len];
s.read(b, 0, len);
BitSet used = BitSet.valueOf(b);
int free = 0;
for (long i = 0, j = pageId; i < pagesAddressed && j < pageCount; i++, j++) {
if (i == 0 || j % 100 == 0) {
......
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.util;
import java.util.Arrays;
/**
* A list of bits.
*/
public final class BitField {
private static final int ADDRESS_BITS = 6;
private static final int BITS = 64;
private static final int ADDRESS_MASK = BITS - 1;
private long[] data;
private int maxLength;
public BitField() {
this(64);
}
public BitField(int capacity) {
data = new long[capacity >>> 3];
}
/**
* Get the index of the next bit that is not set.
*
* @param fromIndex where to start searching
* @return the index of the next disabled bit
*/
public int nextClearBit(int fromIndex) {
int i = fromIndex >> ADDRESS_BITS;
int max = data.length;
for (; i < max; i++) {
if (data[i] == -1) {
continue;
}
int j = Math.max(fromIndex, i << ADDRESS_BITS);
for (int end = j + 64; j < end; j++) {
if (!get(j)) {
return j;
}
}
}
return max << ADDRESS_BITS;
}
/**
* Get the bit at the given index.
*
* @param i the index
* @return true if the bit is enabled
*/
public boolean get(int i) {
int addr = i >> ADDRESS_BITS;
if (addr >= data.length) {
return false;
}
return (data[addr] & getBitMask(i)) != 0;
}
/**
* Get the next 8 bits at the given index.
* The index must be a multiple of 8.
*
* @param i the index
* @return the next 8 bits
*/
public int getByte(int i) {
int addr = i >> ADDRESS_BITS;
if (addr >= data.length) {
return 0;
}
return (int) (data[addr] >>> (i & (7 << 3)) & 255);
}
/**
* Combine the next 8 bits at the given index with OR.
* The index must be a multiple of 8.
*
* @param i the index
* @param x the next 8 bits (0 - 255)
*/
public void setByte(int i, int x) {
int addr = i >> ADDRESS_BITS;
checkCapacity(addr);
data[addr] |= ((long) x) << (i & (7 << 3));
if (maxLength < i && x != 0) {
maxLength = i + 7;
}
}
/**
* Set bit at the given index to 'true'.
*
* @param i the index
*/
public void set(int i) {
int addr = i >> ADDRESS_BITS;
checkCapacity(addr);
data[addr] |= getBitMask(i);
if (maxLength < i) {
maxLength = i;
}
}
/**
* Set bit at the given index to 'false'.
*
* @param i the index
*/
public void clear(int i) {
int addr = i >> ADDRESS_BITS;
if (addr >= data.length) {
return;
}
data[addr] &= ~getBitMask(i);
}
private static long getBitMask(int i) {
return 1L << (i & ADDRESS_MASK);
}
private void checkCapacity(int size) {
if (size >= data.length) {
expandCapacity(size);
}
}
private void expandCapacity(int size) {
while (size >= data.length) {
int newSize = data.length == 0 ? 1 : data.length * 2;
data = Arrays.copyOf(data, newSize);
}
}
/**
* Enable or disable a number of bits.
*
* @param fromIndex the index of the first bit to enable or disable
* @param toIndex one plus the index of the last bit to enable or disable
* @param value the new value
*/
public void set(int fromIndex, int toIndex, boolean value) {
// go backwards so that OutOfMemory happens
// before some bytes are modified
for (int i = toIndex - 1; i >= fromIndex; i--) {
set(i, value);
}
if (value) {
if (toIndex > maxLength) {
maxLength = toIndex;
}
} else {
if (toIndex >= maxLength) {
maxLength = fromIndex;
}
}
}
private void set(int i, boolean value) {
if (value) {
set(i);
} else {
clear(i);
}
}
/**
* Get the index of the highest set bit plus one, or 0 if no bits are set.
*
* @return the length of the bit field
*/
public int length() {
int m = maxLength >> ADDRESS_BITS;
while (m > 0 && data[m] == 0) {
m--;
}
maxLength = (m << ADDRESS_BITS) +
(64 - Long.numberOfLeadingZeros(data[m]));
return maxLength;
}
}
......@@ -173,7 +173,6 @@ import org.h2.test.synth.thread.TestMulti;
import org.h2.test.unit.TestAnsCompression;
import org.h2.test.unit.TestAutoReconnect;
import org.h2.test.unit.TestBinaryArithmeticStream;
import org.h2.test.unit.TestBitField;
import org.h2.test.unit.TestBitStream;
import org.h2.test.unit.TestBnf;
import org.h2.test.unit.TestCache;
......@@ -903,7 +902,6 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
addTest(new TestAnsCompression());
addTest(new TestAutoReconnect());
addTest(new TestBinaryArithmeticStream());
addTest(new TestBitField());
addTest(new TestBitStream());
addTest(new TestBnf());
addTest(new TestCache());
......
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.test.unit;
import java.util.BitSet;
import java.util.Random;
import org.h2.test.TestBase;
import org.h2.util.BitField;
/**
* A unit test for bit fields.
*/
public class TestBitField extends TestBase {
/**
* Run just this test.
*
* @param a ignored
*/
public static void main(String... a) throws Exception {
TestBase.createCaller().init().test();
}
@Override
public void test() {
testNextClearBit();
testByteOperations();
testRandom();
testGetSet();
testRandomSetRange();
}
private void testNextClearBit() {
BitSet set = new BitSet();
BitField field = new BitField();
set.set(0, 640);
field.set(0, 640, true);
assertEquals(set.nextClearBit(0), field.nextClearBit(0));
Random random = new Random(1);
field = new BitField();
field.set(0, 500, true);
for (int i = 0; i < 100000; i++) {
int a = random.nextInt(120);
int b = a + 1 + random.nextInt(200);
field.clear(a);
field.clear(b);
assertEquals(b, field.nextClearBit(a + 1));
field.set(a);
field.set(b);
}
}
private void testByteOperations() {
BitField used = new BitField();
testSetFast(used, false);
testSetFast(used, true);
}
private void testSetFast(BitField used, boolean init) {
int len = 10000;
Random random = new Random(1);
for (int i = 0, x = 0; i < len / 8; i++) {
int mask = random.nextInt() & 255;
if (init) {
assertEquals(mask, used.getByte(x));
x += 8;
// for (int j = 0; j < 8; j++, x++) {
// if (used.get(x) != ((mask & (1 << j)) != 0)) {
// throw Message.getInternalError(
// "Redo failure, block: " + x +
// " expected in-use bit: " + used.get(x));
// }
// }
} else {
used.setByte(x, mask);
x += 8;
// for (int j = 0; j < 8; j++, x++) {
// if ((mask & (1 << j)) != 0) {
// used.set(x);
// }
// }
}
}
}
private void testRandom() {
BitField bits = new BitField();
BitSet set = new BitSet();
int max = 300;
int count = 100000;
Random random = new Random(1);
for (int i = 0; i < count; i++) {
int idx = random.nextInt(max);
if (random.nextBoolean()) {
if (random.nextBoolean()) {
bits.set(idx);
set.set(idx);
} else {
bits.clear(idx);
set.clear(idx);
}
} else {
assertEquals(set.get(idx), bits.get(idx));
assertEquals(set.nextClearBit(idx), bits.nextClearBit(idx));
assertEquals(set.length(), bits.length());
}
}
}
private void testGetSet() {
BitField bits = new BitField();
for (int i = 0; i < 10000; i++) {
bits.set(i);
if (!bits.get(i)) {
fail("not set: " + i);
}
if (bits.get(i + 1)) {
fail("set: " + i);
}
}
for (int i = 0; i < 10000; i++) {
if (!bits.get(i)) {
fail("not set: " + i);
}
}
for (int i = 0; i < 1000; i++) {
int k = bits.nextClearBit(0);
if (k != 10000) {
fail("" + k);
}
}
}
private void testRandomSetRange() {
BitField bits = new BitField();
BitSet set = new BitSet();
Random random = new Random(1);
int maxOffset = 500;
int maxLen = 500;
int total = maxOffset + maxLen;
int count = 10000;
for (int i = 0; i < count; i++) {
int offset = random.nextInt(maxOffset);
int len = random.nextInt(maxLen);
boolean val = random.nextBoolean();
set.set(offset, offset + len, val);
bits.set(offset, offset + len, val);
for (int j = 0; j < total; j++) {
assertEquals(set.get(j), bits.get(j));
}
}
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论