提交 932f95ac authored 作者: Thomas Mueller's avatar Thomas Mueller

Make changes to page references atomic

上级 79798338
...@@ -154,12 +154,14 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -154,12 +154,14 @@ public class MVMap<K, V> extends AbstractMap<K, V>
Object k = p.getKey(at); Object k = p.getKey(at);
Page split = p.split(at); Page split = p.split(at);
Object[] keys = { k }; Object[] keys = { k };
long[] children = { p.getPos(), split.getPos() }; Page.PageReference[] children = {
Page[] childrenPages = { p, split }; new Page.PageReference(p, p.getPos()),
new Page.PageReference(split, split.getPos()),
};
long[] counts = { p.getTotalCount(), split.getTotalCount() }; long[] counts = { p.getTotalCount(), split.getTotalCount() };
p = Page.create(this, writeVersion, p = Page.create(this, writeVersion,
1, keys, null, 1, keys, null,
2, children, childrenPages, counts, 2, children, counts,
totalCount, 0, 0); totalCount, 0, 0);
return p; return p;
} }
......
...@@ -57,7 +57,7 @@ public class MVMapConcurrent<K, V> extends MVMap<K, V> { ...@@ -57,7 +57,7 @@ public class MVMapConcurrent<K, V> extends MVMap<K, V> {
afterWrite(); afterWrite();
} }
} }
@Override @Override
protected void waitUntilWritten(long version) { protected void waitUntilWritten(long version) {
// no need to wait // no need to wait
......
...@@ -112,6 +112,9 @@ MVStore: ...@@ -112,6 +112,9 @@ MVStore:
a map lookup when reading old data; also, this a map lookup when reading old data; also, this
old data map needs to be cleaned up somehow; old data map needs to be cleaned up somehow;
maybe using an additional timeout maybe using an additional timeout
- rollback of removeMap should restore the data -
which has big consequences, as the metadata map
would probably need references to the root nodes of all maps
*/ */
...@@ -823,11 +826,10 @@ public class MVStore { ...@@ -823,11 +826,10 @@ public class MVStore {
/** /**
* Whether the chunk at the given position is live. * Whether the chunk at the given position is live.
* *
* @param pos the position of the page * @param the chunk id
* @return true if it is live * @return true if it is live
*/ */
boolean isChunkLive(long pos) { boolean isChunkLive(int chunkId) {
int chunkId = DataUtils.getPageChunkId(pos);
String s = meta.get(Chunk.getMetaKey(chunkId)); String s = meta.get(Chunk.getMetaKey(chunkId));
return s != null; return s != null;
} }
...@@ -2262,9 +2264,10 @@ public class MVStore { ...@@ -2262,9 +2264,10 @@ public class MVStore {
} }
/** /**
* Remove a map. * Remove a map. Please note rolling back this operation does not restore
* * the data; if you need this ability, use Map.clear().
* @param map the map *
* @param map the map to remove
*/ */
public synchronized void removeMap(MVMap<?, ?> map) { public synchronized void removeMap(MVMap<?, ?> map) {
checkOpen(); checkOpen();
...@@ -2397,7 +2400,7 @@ public class MVStore { ...@@ -2397,7 +2400,7 @@ public class MVStore {
return; return;
} }
autoCommitDelay = millis; autoCommitDelay = millis;
if (fileStore == null) { if (fileStore == null || fileStore.isReadOnly()) {
return; return;
} }
stopBackgroundThread(); stopBackgroundThread();
......
...@@ -83,11 +83,11 @@ public class Page { ...@@ -83,11 +83,11 @@ public class Page {
private Object[] values; private Object[] values;
/** /**
* The child page positions. * The child page references.
* <p> * <p>
* The array might be larger than needed, to avoid frequent re-sizing. * The array might be larger than needed, to avoid frequent re-sizing.
*/ */
private long[] children; private PageReference[] children;
/** /**
* The descendant count for each child page. * The descendant count for each child page.
...@@ -96,13 +96,6 @@ public class Page { ...@@ -96,13 +96,6 @@ public class Page {
*/ */
private long[] counts; private long[] counts;
/**
* The child pages.
* <p>
* The array might be larger than needed, to avoid frequent re-sizing.
*/
private Page[] childrenPages;
/** /**
* Whether the page is an in-memory (not stored, or not yet stored) page, * Whether the page is an in-memory (not stored, or not yet stored) page,
* and it is removed. This is to keep track of pages that concurrently * and it is removed. This is to keep track of pages that concurrently
...@@ -126,7 +119,7 @@ public class Page { ...@@ -126,7 +119,7 @@ public class Page {
static Page createEmpty(MVMap<?, ?> map, long version) { static Page createEmpty(MVMap<?, ?> map, long version) {
return create(map, version, return create(map, version,
0, EMPTY_OBJECT_ARRAY, EMPTY_OBJECT_ARRAY, 0, EMPTY_OBJECT_ARRAY, EMPTY_OBJECT_ARRAY,
0, null, null, null, 0, null, null,
0, 0, DataUtils.PAGE_MEMORY); 0, 0, DataUtils.PAGE_MEMORY);
} }
...@@ -140,7 +133,6 @@ public class Page { ...@@ -140,7 +133,6 @@ public class Page {
* @param values the values * @param values the values
* @param childCount the number of children * @param childCount the number of children
* @param children the child page positions * @param children the child page positions
* @param childrenPages the children pages
* @param counts the children counts * @param counts the children counts
* @param totalCount the total number of keys * @param totalCount the total number of keys
* @param sharedFlags which arrays are shared * @param sharedFlags which arrays are shared
...@@ -148,8 +140,8 @@ public class Page { ...@@ -148,8 +140,8 @@ public class Page {
* @return the page * @return the page
*/ */
public static Page create(MVMap<?, ?> map, long version, int keyCount, public static Page create(MVMap<?, ?> map, long version, int keyCount,
Object[] keys, Object[] values, int childCount, long[] children, Object[] keys, Object[] values, int childCount, PageReference[] children,
Page[] childrenPages, long[] counts, long totalCount, long[] counts, long totalCount,
int sharedFlags, int memory) { int sharedFlags, int memory) {
Page p = new Page(map, version); Page p = new Page(map, version);
// the position is 0 // the position is 0
...@@ -158,7 +150,6 @@ public class Page { ...@@ -158,7 +150,6 @@ public class Page {
p.values = values; p.values = values;
p.childCount = childCount; p.childCount = childCount;
p.children = children; p.children = children;
p.childrenPages = childrenPages;
p.counts = counts; p.counts = counts;
p.totalCount = totalCount; p.totalCount = totalCount;
p.sharedFlags = sharedFlags; p.sharedFlags = sharedFlags;
...@@ -191,8 +182,7 @@ public class Page { ...@@ -191,8 +182,7 @@ public class Page {
p.values = source.values; p.values = source.values;
} else { } else {
p.childCount = source.childCount; p.childCount = source.childCount;
p.children = new long[source.children.length]; p.children = source.children;
p.childrenPages = new Page[source.childrenPages.length];
p.counts = source.counts; p.counts = source.counts;
} }
p.totalCount = source.totalCount; p.totalCount = source.totalCount;
...@@ -258,8 +248,8 @@ public class Page { ...@@ -258,8 +248,8 @@ public class Page {
* @return the child page * @return the child page
*/ */
public Page getChildPage(int index) { public Page getChildPage(int index) {
Page p = childrenPages[index]; PageReference ref = children[index];
return p != null ? p : map.readPage(children[index]); return ref.page != null ? ref.page : map.readPage(ref.pos);
} }
/** /**
...@@ -269,7 +259,7 @@ public class Page { ...@@ -269,7 +259,7 @@ public class Page {
* @return the position * @return the position
*/ */
public long getChildPagePos(int index) { public long getChildPagePos(int index) {
return children[index]; return children[index].pos;
} }
/** /**
...@@ -279,12 +269,12 @@ public class Page { ...@@ -279,12 +269,12 @@ public class Page {
* @return the page, or null if the chunk is not live * @return the page, or null if the chunk is not live
*/ */
public Page getLiveChildPage(int index) { public Page getLiveChildPage(int index) {
Page p = childrenPages[index]; PageReference ref = children[index];
if (p != null) { if (ref.page != null) {
return p; return ref.page;
} }
long pos = children[index]; int chunkId = DataUtils.getPageChunkId(ref.pos);
if (!map.store.isChunkLive(pos)) { if (!map.store.isChunkLive(chunkId)) {
return null; return null;
} }
return getChildPage(index); return getChildPage(index);
...@@ -342,7 +332,7 @@ public class Page { ...@@ -342,7 +332,7 @@ public class Page {
buff.append(" "); buff.append(" ");
} }
if (children != null) { if (children != null) {
buff.append("[" + Long.toHexString(children[i]) + "] "); buff.append("[" + Long.toHexString(children[i].pos) + "] ");
} }
if (i < keyCount) { if (i < keyCount) {
buff.append(keys[i]); buff.append(keys[i]);
...@@ -364,7 +354,7 @@ public class Page { ...@@ -364,7 +354,7 @@ public class Page {
public Page copy(long version) { public Page copy(long version) {
Page newPage = create(map, version, Page newPage = create(map, version,
keyCount, keys, values, keyCount, keys, values,
childCount, children, childrenPages, counts, totalCount, childCount, children, counts, totalCount,
SHARED_KEYS | SHARED_VALUES | SHARED_CHILDREN | SHARED_COUNTS, SHARED_KEYS | SHARED_VALUES | SHARED_CHILDREN | SHARED_COUNTS,
getMemory()); getMemory());
// mark the old as deleted // mark the old as deleted
...@@ -453,7 +443,7 @@ public class Page { ...@@ -453,7 +443,7 @@ public class Page {
totalCount = a; totalCount = a;
Page newPage = create(map, version, Page newPage = create(map, version,
b, bKeys, bValues, b, bKeys, bValues,
0, null, null, null, 0, null, null,
bKeys.length, 0, 0); bKeys.length, 0, 0);
recalculateMemory(); recalculateMemory();
newPage.recalculateMemory(); newPage.recalculateMemory();
...@@ -470,18 +460,12 @@ public class Page { ...@@ -470,18 +460,12 @@ public class Page {
keys = aKeys; keys = aKeys;
keyCount = a; keyCount = a;
long[] aChildren = new long[a + 1]; PageReference[] aChildren = new PageReference[a + 1];
long[] bChildren = new long[b]; PageReference[] bChildren = new PageReference[b];
System.arraycopy(children, 0, aChildren, 0, a + 1); System.arraycopy(children, 0, aChildren, 0, a + 1);
System.arraycopy(children, a + 1, bChildren, 0, b); System.arraycopy(children, a + 1, bChildren, 0, b);
children = aChildren; children = aChildren;
Page[] aChildrenPages = new Page[a + 1];
Page[] bChildrenPages = new Page[b];
System.arraycopy(childrenPages, 0, aChildrenPages, 0, a + 1);
System.arraycopy(childrenPages, a + 1, bChildrenPages, 0, b);
childrenPages = aChildrenPages;
long[] aCounts = new long[a + 1]; long[] aCounts = new long[a + 1];
long[] bCounts = new long[b]; long[] bCounts = new long[b];
System.arraycopy(counts, 0, aCounts, 0, a + 1); System.arraycopy(counts, 0, aCounts, 0, a + 1);
...@@ -501,7 +485,7 @@ public class Page { ...@@ -501,7 +485,7 @@ public class Page {
} }
Page newPage = create(map, version, Page newPage = create(map, version,
b - 1, bKeys, null, b - 1, bKeys, null,
b, bChildren, bChildrenPages, bCounts, b, bChildren, bCounts,
t, 0, 0); t, 0, 0);
recalculateMemory(); recalculateMemory();
newPage.recalculateMemory(); newPage.recalculateMemory();
...@@ -549,15 +533,13 @@ public class Page { ...@@ -549,15 +533,13 @@ public class Page {
* @param c the new child page * @param c the new child page
*/ */
public void setChild(int index, Page c) { public void setChild(int index, Page c) {
if (c != childrenPages[index] || c.getPos() != children[index]) { if (c != children[index].page || c.getPos() != children[index].pos) {
if ((sharedFlags & SHARED_CHILDREN) != 0) { if ((sharedFlags & SHARED_CHILDREN) != 0) {
children = Arrays.copyOf(children, children.length); children = Arrays.copyOf(children, children.length);
childrenPages = Arrays.copyOf(childrenPages,
childrenPages.length);
sharedFlags &= ~SHARED_CHILDREN; sharedFlags &= ~SHARED_CHILDREN;
} }
children[index] = c.getPos(); PageReference ref = new PageReference(c, c.pos);
childrenPages[index] = c; children[index] = ref;
} }
} }
...@@ -636,11 +618,11 @@ public class Page { ...@@ -636,11 +618,11 @@ public class Page {
void removeAllRecursive() { void removeAllRecursive() {
if (children != null) { if (children != null) {
for (int i = 0, size = childCount; i < size; i++) { for (int i = 0, size = childCount; i < size; i++) {
Page p = childrenPages[i]; PageReference ref = children[i];
if (p != null) { if (ref.page != null) {
p.removeAllRecursive(); ref.page.removeAllRecursive();
} else { } else {
long c = children[i]; long c = children[i].pos;
int type = DataUtils.getPageType(c); int type = DataUtils.getPageType(c);
if (type == DataUtils.PAGE_TYPE_LEAF) { if (type == DataUtils.PAGE_TYPE_LEAF) {
int mem = DataUtils.getPageMaxLength(c); int mem = DataUtils.getPageMaxLength(c);
...@@ -703,17 +685,11 @@ public class Page { ...@@ -703,17 +685,11 @@ public class Page {
keyCount++; keyCount++;
long[] newChildren = new long[childCount + 1]; PageReference[] newChildren = new PageReference[childCount + 1];
DataUtils.copyWithGap(children, newChildren, childCount, index); DataUtils.copyWithGap(children, newChildren, childCount, index);
newChildren[index] = childPage.getPos(); newChildren[index] = new PageReference(childPage, childPage.getPos());
children = newChildren; children = newChildren;
Page[] newChildrenPages = new Page[childCount + 1];
DataUtils.copyWithGap(childrenPages, newChildrenPages, childCount,
index);
newChildrenPages[index] = childPage;
childrenPages = newChildrenPages;
long[] newCounts = new long[childCount + 1]; long[] newCounts = new long[childCount + 1];
DataUtils.copyWithGap(counts, newCounts, childCount, index); DataUtils.copyWithGap(counts, newCounts, childCount, index);
newCounts[index] = childPage.totalCount; newCounts[index] = childPage.totalCount;
...@@ -773,15 +749,10 @@ public class Page { ...@@ -773,15 +749,10 @@ public class Page {
addMemory(-DataUtils.PAGE_MEMORY_CHILD); addMemory(-DataUtils.PAGE_MEMORY_CHILD);
long countOffset = counts[index]; long countOffset = counts[index];
long[] newChildren = new long[childCount - 1]; PageReference[] newChildren = new PageReference[childCount - 1];
DataUtils.copyExcept(children, newChildren, childCount, index); DataUtils.copyExcept(children, newChildren, childCount, index);
children = newChildren; children = newChildren;
Page[] newChildrenPages = new Page[childCount - 1];
DataUtils.copyExcept(childrenPages, newChildrenPages,
childCount, index);
childrenPages = newChildrenPages;
long[] newCounts = new long[childCount - 1]; long[] newCounts = new long[childCount - 1];
DataUtils.copyExcept(counts, newCounts, childCount, index); DataUtils.copyExcept(counts, newCounts, childCount, index);
counts = newCounts; counts = newCounts;
...@@ -835,11 +806,10 @@ public class Page { ...@@ -835,11 +806,10 @@ public class Page {
boolean node = (type & 1) == DataUtils.PAGE_TYPE_NODE; boolean node = (type & 1) == DataUtils.PAGE_TYPE_NODE;
if (node) { if (node) {
childCount = len + 1; childCount = len + 1;
children = new long[len + 1]; children = new PageReference[len + 1];
for (int i = 0; i <= len; i++) { for (int i = 0; i <= len; i++) {
children[i] = buff.getLong(); children[i] = new PageReference(null, buff.getLong());
} }
childrenPages = new Page[len + 1];
counts = new long[len + 1]; counts = new long[len + 1];
long total = 0; long total = 0;
for (int i = 0; i <= len; i++) { for (int i = 0; i <= len; i++) {
...@@ -961,7 +931,7 @@ public class Page { ...@@ -961,7 +931,7 @@ public class Page {
private void writeChildren(WriteBuffer buff) { private void writeChildren(WriteBuffer buff) {
int len = keyCount; int len = keyCount;
for (int i = 0; i <= len; i++) { for (int i = 0; i <= len; i++) {
buff.putLong(children[i]); buff.putLong(children[i].pos);
} }
} }
...@@ -981,10 +951,10 @@ public class Page { ...@@ -981,10 +951,10 @@ public class Page {
if (!isLeaf()) { if (!isLeaf()) {
int len = childCount; int len = childCount;
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
Page p = childrenPages[i]; Page p = children[i].page;
if (p != null) { if (p != null) {
p.writeUnsavedRecursive(chunk, buff); p.writeUnsavedRecursive(chunk, buff);
children[i] = p.getPos(); children[i] = new PageReference(p, p.getPos());
} }
} }
int old = buff.position(); int old = buff.position();
...@@ -1001,14 +971,14 @@ public class Page { ...@@ -1001,14 +971,14 @@ public class Page {
if (!isLeaf()) { if (!isLeaf()) {
int len = childCount; int len = childCount;
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
Page p = childrenPages[i]; PageReference ref = children[i];
if (p != null) { if (ref.page != null) {
if (p.getPos() == 0) { if (ref.page.getPos() == 0) {
throw DataUtils.newIllegalStateException( throw DataUtils.newIllegalStateException(
DataUtils.ERROR_INTERNAL, "Page not written"); DataUtils.ERROR_INTERNAL, "Page not written");
} }
p.writeEnd(); ref.page.writeEnd();
childrenPages[i] = null; children[i] = new PageReference(null, ref.pos);
} }
} }
} }
...@@ -1089,4 +1059,26 @@ public class Page { ...@@ -1089,4 +1059,26 @@ public class Page {
map.removePage(p, memory); map.removePage(p, memory);
} }
/**
* A pointer to a page, either in-memory or using a page position.
*/
public static class PageReference {
/**
* The position, if known, or 0.
*/
final long pos;
/**
* The page, if in memory, or null.
*/
final Page page;
public PageReference(Page page, long pos) {
this.page = page;
this.pos = pos;
}
}
} }
...@@ -248,13 +248,16 @@ public class MVRTreeMap<V> extends MVMap<SpatialKey, V> { ...@@ -248,13 +248,16 @@ public class MVRTreeMap<V> extends MVMap<SpatialKey, V> {
Object k1 = getBounds(p); Object k1 = getBounds(p);
Object k2 = getBounds(split); Object k2 = getBounds(split);
Object[] keys = { k1, k2 }; Object[] keys = { k1, k2 };
long[] children = { p.getPos(), split.getPos(), 0 }; Page.PageReference[] children = {
Page[] childrenPages = { p, split, null }; new Page.PageReference(p, p.getPos()),
new Page.PageReference(split, split.getPos()),
new Page.PageReference(null, 0)
};
long[] counts = { p.getTotalCount(), long[] counts = { p.getTotalCount(),
split.getTotalCount(), 0 }; split.getTotalCount(), 0 };
p = Page.create(this, v, p = Page.create(this, v,
2, keys, null, 2, keys, null,
3, children, childrenPages, counts, 3, children, counts,
totalCount, 0, 0); totalCount, 0, 0);
// now p is a node; continues // now p is a node; continues
} }
...@@ -449,12 +452,22 @@ public class MVRTreeMap<V> extends MVMap<SpatialKey, V> { ...@@ -449,12 +452,22 @@ public class MVRTreeMap<V> extends MVMap<SpatialKey, V> {
} }
private Page newPage(boolean leaf, long writeVersion) { private Page newPage(boolean leaf, long writeVersion) {
Object[] values = leaf ? new Object[4] : null; Object[] values;
long[] c = leaf ? null : new long[1]; Page.PageReference[] refs;
Page[] cp = leaf ? null : new Page[1]; long[] c;
if (leaf) {
values = new Object[4];
refs = null;
c = null;
} else {
values = null;
refs = new Page.PageReference[] {
new Page.PageReference(null, 0)};
c = new long[1];
}
return Page.create(this, writeVersion, return Page.create(this, writeVersion,
0, new Object[4], values, 0, new Object[4], values,
leaf ? 0 : 1, c, cp, c, 0, 0, 0); leaf ? 0 : 1, refs, c, 0, 0, 0);
} }
private static void move(Page source, Page target, int sourceIndex) { private static void move(Page source, Page target, int sourceIndex) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论