提交 a5f4c837 authored 作者: Thomas Mueller's avatar Thomas Mueller

MVStore: concurrency problems have been fixed.

上级 aee9a9cd
...@@ -194,7 +194,8 @@ public class SpatialTreeIndex extends BaseIndex implements SpatialIndex { ...@@ -194,7 +194,8 @@ public class SpatialTreeIndex extends BaseIndex implements SpatialIndex {
@Override @Override
public void remove(Session session) { public void remove(Session session) {
if (!treeMap.isClosed()) { if (!treeMap.isClosed()) {
treeMap.removeMap(); MVStore store = session.getDatabase().getMvStore().getStore();
store.removeMap(treeMap);
} }
} }
......
...@@ -505,24 +505,6 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -505,24 +505,6 @@ public class MVMap<K, V> extends AbstractMap<K, V>
} }
} }
/**
* Remove all entries, and close the map.
*/
public void removeMap() {
int todoMoveToMVStore;
if (this == store.getMetaMap()) {
return;
}
beforeWrite();
try {
root.removeAllRecursive();
store.removeMap(id);
close();
} finally {
afterWrite();
}
}
/** /**
* Close the map. Accessing the data is still possible (to allow concurrent * Close the map. Accessing the data is still possible (to allow concurrent
* reads), but it is marked as closed. * reads), but it is marked as closed.
...@@ -1115,21 +1097,6 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -1115,21 +1097,6 @@ public class MVMap<K, V> extends AbstractMap<K, V>
return buff.toString(); return buff.toString();
} }
/**
* Rename the map.
*
* @param newMapName the name name
*/
public void renameMap(String newMapName) {
int todoMoveToMVStore;
beforeWrite();
try {
store.renameMap(this, newMapName);
} finally {
afterWrite();
}
}
void setWriteVersion(long writeVersion) { void setWriteVersion(long writeVersion) {
this.writeVersion = writeVersion; this.writeVersion = writeVersion;
} }
......
...@@ -15,6 +15,7 @@ import java.util.Comparator; ...@@ -15,6 +15,7 @@ import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
...@@ -484,20 +485,6 @@ public class MVStore { ...@@ -484,20 +485,6 @@ public class MVStore {
} }
} }
/**
* Remove a map.
*
* @param id the map id
*/
void removeMap(int id) {
String name = getMapName(id);
markMetaChanged();
meta.remove("map." + id);
meta.remove("name." + name);
meta.remove("root." + id);
maps.remove(id);
}
/** /**
* Check whether a given map exists. * Check whether a given map exists.
* *
...@@ -1058,19 +1045,23 @@ public class MVStore { ...@@ -1058,19 +1045,23 @@ public class MVStore {
Set<Chunk> removedChunks = New.hashSet(); Set<Chunk> removedChunks = New.hashSet();
while (true) { while (true) {
ArrayList<Chunk> modified = New.arrayList(); ArrayList<Chunk> modified = New.arrayList();
ArrayList<Long> keys = new ArrayList<Long>(freedPageSpace.keySet()); Iterator<Entry<Long, HashMap<Integer, Chunk>>> it;
for (Iterator<Long> it = keys.iterator(); it.hasNext();) { it = freedPageSpace.entrySet().iterator();
long v = it.next(); while (it.hasNext()) {
Entry<Long, HashMap<Integer, Chunk>> e = it.next();
long v = e.getKey();
if (v > storeVersion) { if (v > storeVersion) {
continue; continue;
} }
Map<Integer, Chunk> freed = freedPageSpace.get(v); Map<Integer, Chunk> freed = e.getValue();
for (Chunk f : freed.values()) { for (Chunk f : freed.values()) {
Chunk c = chunks.get(f.id); Chunk c = chunks.get(f.id);
if (c == null) { if (c == null) {
// already removed // already removed
continue; continue;
} }
// no need to synchronize, as old entries
// are not concurrently modified
c.maxLengthLive += f.maxLengthLive; c.maxLengthLive += f.maxLengthLive;
c.pageCountLive += f.pageCountLive; c.pageCountLive += f.pageCountLive;
if (c.pageCountLive < 0) { if (c.pageCountLive < 0) {
...@@ -1090,7 +1081,7 @@ public class MVStore { ...@@ -1090,7 +1081,7 @@ public class MVStore {
} }
modified.add(c); modified.add(c);
} }
freedPageSpace.remove(v); it.remove();
} }
for (Chunk c : modified) { for (Chunk c : modified) {
if (c.maxLengthLive == 0) { if (c.maxLengthLive == 0) {
...@@ -1511,6 +1502,7 @@ public class MVStore { ...@@ -1511,6 +1502,7 @@ public class MVStore {
freed = f2; freed = f2;
} }
} }
// synchronize, because pages could be freed concurrently
synchronized (freed) { synchronized (freed) {
Chunk f = freed.get(chunkId); Chunk f = freed.get(chunkId);
if (f == null) { if (f == null) {
...@@ -1759,14 +1751,12 @@ public class MVStore { ...@@ -1759,14 +1751,12 @@ public class MVStore {
for (MVMap<?, ?> m : maps.values()) { for (MVMap<?, ?> m : maps.values()) {
m.rollbackTo(version); m.rollbackTo(version);
} }
synchronized (freedPageSpace) {
for (long v = currentVersion; v >= version; v--) { for (long v = currentVersion; v >= version; v--) {
if (freedPageSpace.size() == 0) { if (freedPageSpace.size() == 0) {
break; break;
} }
freedPageSpace.remove(v); freedPageSpace.remove(v);
} }
}
meta.rollbackTo(version); meta.rollbackTo(version);
metaChanged = false; metaChanged = false;
boolean loadFromFile = false; boolean loadFromFile = false;
...@@ -1899,7 +1889,7 @@ public class MVStore { ...@@ -1899,7 +1889,7 @@ public class MVStore {
* @param map the map * @param map the map
* @param newName the new name * @param newName the new name
*/ */
void renameMap(MVMap<?, ?> map, String newName) { public void renameMap(MVMap<?, ?> map, String newName) {
checkOpen(); checkOpen();
DataUtils.checkArgument(map != meta, DataUtils.checkArgument(map != meta,
"Renaming the meta map is not allowed"); "Renaming the meta map is not allowed");
...@@ -1917,6 +1907,25 @@ public class MVStore { ...@@ -1917,6 +1907,25 @@ public class MVStore {
meta.put("name." + newName, Integer.toString(id)); meta.put("name." + newName, Integer.toString(id));
} }
/**
* Remove a map.
*
* @param map the map
*/
public void removeMap(MVMap<?, ?> map) {
checkOpen();
DataUtils.checkArgument(map != meta,
"Removing the meta map is not allowed");
map.clear();
int id = map.getId();
String name = getMapName(id);
markMetaChanged();
meta.remove("map." + id);
meta.remove("name." + name);
meta.remove("root." + id);
maps.remove(id);
}
/** /**
* Get the name of the given map. * Get the name of the given map.
* *
......
...@@ -9,6 +9,7 @@ package org.h2.mvstore.db; ...@@ -9,6 +9,7 @@ package org.h2.mvstore.db;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.engine.Database; import org.h2.engine.Database;
...@@ -17,7 +18,6 @@ import org.h2.index.BaseIndex; ...@@ -17,7 +18,6 @@ import org.h2.index.BaseIndex;
import org.h2.index.Cursor; import org.h2.index.Cursor;
import org.h2.index.IndexType; import org.h2.index.IndexType;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.mvstore.MVMap;
import org.h2.mvstore.db.TransactionStore.Transaction; import org.h2.mvstore.db.TransactionStore.Transaction;
import org.h2.mvstore.db.TransactionStore.TransactionMap; import org.h2.mvstore.db.TransactionStore.TransactionMap;
import org.h2.result.Row; import org.h2.result.Row;
...@@ -55,10 +55,8 @@ public class MVPrimaryIndex extends BaseIndex { ...@@ -55,10 +55,8 @@ public class MVPrimaryIndex extends BaseIndex {
ValueDataType valueType = new ValueDataType( ValueDataType valueType = new ValueDataType(
db.getCompareMode(), db, sortTypes); db.getCompareMode(), db, sortTypes);
mapName = "table." + getId(); mapName = "table." + getId();
MVMap.Builder<Value, Value> mapBuilder = new MVMap.Builder<Value, Value>(). dataMap = mvTable.getTransaction(null).openMap(
keyType(keyType). mapName, keyType, valueType);
valueType(valueType);
dataMap = mvTable.getTransaction(null).openMap(mapName, mapBuilder);
Value k = dataMap.lastKey(); Value k = dataMap.lastKey();
lastKey = k == null ? 0 : k.getLong(); lastKey = k == null ? 0 : k.getLong();
} }
...@@ -216,7 +214,8 @@ public class MVPrimaryIndex extends BaseIndex { ...@@ -216,7 +214,8 @@ public class MVPrimaryIndex extends BaseIndex {
public void remove(Session session) { public void remove(Session session) {
TransactionMap<Value, Value> map = getMap(session); TransactionMap<Value, Value> map = getMap(session);
if (!map.isClosed()) { if (!map.isClosed()) {
map.removeMap(); Transaction t = mvTable.getTransaction(session);
t.removeMap(map);
} }
} }
......
...@@ -9,6 +9,7 @@ package org.h2.mvstore.db; ...@@ -9,6 +9,7 @@ package org.h2.mvstore.db;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
import org.h2.engine.Database; import org.h2.engine.Database;
import org.h2.engine.Session; import org.h2.engine.Session;
...@@ -16,7 +17,6 @@ import org.h2.index.BaseIndex; ...@@ -16,7 +17,6 @@ import org.h2.index.BaseIndex;
import org.h2.index.Cursor; import org.h2.index.Cursor;
import org.h2.index.IndexType; import org.h2.index.IndexType;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.mvstore.MVMap;
import org.h2.mvstore.db.TransactionStore.Transaction; import org.h2.mvstore.db.TransactionStore.Transaction;
import org.h2.mvstore.db.TransactionStore.TransactionMap; import org.h2.mvstore.db.TransactionStore.TransactionMap;
import org.h2.result.Row; import org.h2.result.Row;
...@@ -64,10 +64,8 @@ public class MVSecondaryIndex extends BaseIndex { ...@@ -64,10 +64,8 @@ public class MVSecondaryIndex extends BaseIndex {
ValueDataType keyType = new ValueDataType( ValueDataType keyType = new ValueDataType(
db.getCompareMode(), db, sortTypes); db.getCompareMode(), db, sortTypes);
ValueDataType valueType = new ValueDataType(null, null, null); ValueDataType valueType = new ValueDataType(null, null, null);
MVMap.Builder<Value, Value> mapBuilder = new MVMap.Builder<Value, Value>(). dataMap = mvTable.getTransaction(null).openMap(
keyType(keyType). mapName, keyType, valueType);
valueType(valueType);
dataMap = mvTable.getTransaction(null).openMap(mapName, mapBuilder);
if (keyType != dataMap.map.getKeyType()) { if (keyType != dataMap.map.getKeyType()) {
throw DbException.throwInternalError("Incompatible key type"); throw DbException.throwInternalError("Incompatible key type");
} }
...@@ -204,7 +202,8 @@ public class MVSecondaryIndex extends BaseIndex { ...@@ -204,7 +202,8 @@ public class MVSecondaryIndex extends BaseIndex {
public void remove(Session session) { public void remove(Session session) {
TransactionMap<Value, Value> map = getMap(session); TransactionMap<Value, Value> map = getMap(session);
if (!map.isClosed()) { if (!map.isClosed()) {
map.removeMap(); Transaction t = mvTable.getTransaction(session);
t.removeMap(map);
} }
} }
......
...@@ -11,6 +11,7 @@ import java.util.Collections; ...@@ -11,6 +11,7 @@ import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import org.h2.api.DatabaseEventListener; import org.h2.api.DatabaseEventListener;
import org.h2.command.ddl.Analyze; import org.h2.command.ddl.Analyze;
import org.h2.command.ddl.CreateTableData; import org.h2.command.ddl.CreateTableData;
...@@ -398,6 +399,7 @@ public class MVTable extends TableBase { ...@@ -398,6 +399,7 @@ public class MVTable extends TableBase {
index = new MVDelegateIndex(this, indexId, index = new MVDelegateIndex(this, indexId,
indexName, primaryIndex, indexType); indexName, primaryIndex, indexType);
} else if (indexType.isSpatial()) { } else if (indexType.isSpatial()) {
int todo;
index = new SpatialTreeIndex(this, indexId, indexName, cols, index = new SpatialTreeIndex(this, indexId, indexName, cols,
indexType, true, create, session); indexType, true, create, session);
} else { } else {
......
...@@ -15,7 +15,6 @@ import java.util.Map; ...@@ -15,7 +15,6 @@ import java.util.Map;
import org.h2.mvstore.Cursor; import org.h2.mvstore.Cursor;
import org.h2.mvstore.DataUtils; import org.h2.mvstore.DataUtils;
import org.h2.mvstore.MVMap; import org.h2.mvstore.MVMap;
import org.h2.mvstore.MVMap.Builder;
import org.h2.mvstore.MVStore; import org.h2.mvstore.MVStore;
import org.h2.mvstore.WriteBuffer; import org.h2.mvstore.WriteBuffer;
import org.h2.mvstore.type.DataType; import org.h2.mvstore.type.DataType;
...@@ -630,9 +629,7 @@ public class TransactionStore { ...@@ -630,9 +629,7 @@ public class TransactionStore {
* @return the transaction map * @return the transaction map
*/ */
public <K, V> TransactionMap<K, V> openMap(String name) { public <K, V> TransactionMap<K, V> openMap(String name) {
checkNotClosed(); return openMap(name, null, null);
return new TransactionMap<K, V>(this, name, new ObjectDataType(),
new ObjectDataType());
} }
/** /**
...@@ -641,20 +638,31 @@ public class TransactionStore { ...@@ -641,20 +638,31 @@ public class TransactionStore {
* @param <K> the key type * @param <K> the key type
* @param <V> the value type * @param <V> the value type
* @param name the name of the map * @param name the name of the map
* @param builder the builder * @param keyType the key data type
* @param valueType the value data type
* @return the transaction map * @return the transaction map
*/ */
public <K, V> TransactionMap<K, V> openMap(String name, Builder<K, V> builder) { public <K, V> TransactionMap<K, V> openMap(String name, DataType keyType, DataType valueType) {
checkNotClosed(); checkNotClosed();
DataType keyType = builder.getKeyType();
if (keyType == null) { if (keyType == null) {
keyType = new ObjectDataType(); keyType = new ObjectDataType();
} }
DataType valueType = builder.getValueType();
if (valueType == null) { if (valueType == null) {
valueType = new ObjectDataType(); valueType = new ObjectDataType();
} }
return new TransactionMap<K, V>(this, name, keyType, valueType); VersionedValueType vt = new VersionedValueType(valueType);
MVMap.Builder<K, VersionedValue> builder = new MVMap.Builder<K, VersionedValue>()
.keyType(keyType).valueType(vt);
MVMap<K, VersionedValue> map = store.store.openMap(name, builder);
int mapId = map.getId();
return new TransactionMap<K, V>(this, map, mapId);
}
public <K, V> TransactionMap<K, V> openMap(String name, MVMap.Builder<K, VersionedValue> builder) {
checkNotClosed();
MVMap<K, VersionedValue> map = store.store.openMap(name, builder);
int mapId = map.getId();
return new TransactionMap<K, V>(this, map, mapId);
} }
/** /**
...@@ -719,6 +727,13 @@ public class TransactionStore { ...@@ -719,6 +727,13 @@ public class TransactionStore {
} }
} }
/**
* Remove the map.
*/
public <K, V> void removeMap(TransactionMap<K, V> map) {
store.store.removeMap(map.map);
}
} }
/** /**
...@@ -749,17 +764,7 @@ public class TransactionStore { ...@@ -749,17 +764,7 @@ public class TransactionStore {
*/ */
private long readLogId = Long.MAX_VALUE; private long readLogId = Long.MAX_VALUE;
TransactionMap(Transaction transaction, String name, DataType keyType, TransactionMap(Transaction transaction, MVMap<K, VersionedValue> map, int mapId) {
DataType valueType) {
this.transaction = transaction;
VersionedValueType vt = new VersionedValueType(valueType);
MVMap.Builder<K, VersionedValue> builder = new MVMap.Builder<K, VersionedValue>()
.keyType(keyType).valueType(vt);
map = transaction.store.store.openMap(name, builder);
mapId = map.getId();
}
private TransactionMap(Transaction transaction, MVMap<K, VersionedValue> map, int mapId) {
this.transaction = transaction; this.transaction = transaction;
this.map = map; this.map = map;
this.mapId = mapId; this.mapId = mapId;
...@@ -1080,17 +1085,6 @@ public class TransactionStore { ...@@ -1080,17 +1085,6 @@ public class TransactionStore {
} }
} }
/**
* Rename the map.
*
* @param newMapName the new map name
*/
public void renameMap(String newMapName) {
// TODO rename maps transactionally
map.renameMap(newMapName);
}
/** /**
* Check whether this map is closed. * Check whether this map is closed.
* *
...@@ -1100,14 +1094,6 @@ public class TransactionStore { ...@@ -1100,14 +1094,6 @@ public class TransactionStore {
return map.isClosed(); return map.isClosed();
} }
/**
* Remove the map.
*/
public void removeMap() {
// TODO remove in a transaction
map.removeMap();
}
/** /**
* Clear the map. * Clear the map.
*/ */
...@@ -1204,25 +1190,36 @@ public class TransactionStore { ...@@ -1204,25 +1190,36 @@ public class TransactionStore {
} }
/** /**
* Iterate over all keys. * Iterate over keys.
* *
* @param from the first key to return * @param from the first key to return
* @return the iterator * @return the iterator
*/ */
public Iterator<K> keyIterator(final K from) { public Iterator<K> keyIterator(K from) {
return keyIterator(from, false); return keyIterator(from, false);
} }
/** /**
* Iterate over all keys. * Iterate over keys.
* *
* @param from the first key to return * @param from the first key to return
* @param includeUncommitted whether uncommitted entries should be included * @param includeUncommitted whether uncommitted entries should be included
* @return the iterator * @return the iterator
*/ */
public Iterator<K> keyIterator(final K from, final boolean includeUncommitted) { public Iterator<K> keyIterator(K from, boolean includeUncommitted) {
Cursor<K> it = map.keyIterator(from);
return wrapIterator(it, false);
}
/**
* Iterate over keys.
*
* @param cursor the wrapped cursor
* @param includeUncommitted whether uncommitted entries should be included
* @return the iterator
*/
private Iterator<K> wrapIterator(final Cursor<K> cursor, final boolean includeUncommitted) {
return new Iterator<K>() { return new Iterator<K>() {
private final Cursor<K> cursor = map.keyIterator(from);
private K current; private K current;
{ {
......
...@@ -15,7 +15,6 @@ import org.h2.mvstore.MVMap; ...@@ -15,7 +15,6 @@ import org.h2.mvstore.MVMap;
import org.h2.mvstore.Page; import org.h2.mvstore.Page;
import org.h2.mvstore.type.DataType; import org.h2.mvstore.type.DataType;
import org.h2.mvstore.type.ObjectDataType; import org.h2.mvstore.type.ObjectDataType;
import org.h2.mvstore.type.StringDataType;
import org.h2.util.New; import org.h2.util.New;
/** /**
...@@ -744,7 +743,7 @@ public class MVRTreeMap<V> extends MVMap<SpatialKey, V> { ...@@ -744,7 +743,7 @@ public class MVRTreeMap<V> extends MVMap<SpatialKey, V> {
* @param valueType the key type * @param valueType the key type
* @return this * @return this
*/ */
public Builder<V> valueType(StringDataType valueType) { public Builder<V> valueType(DataType valueType) {
this.valueType = valueType; this.valueType = valueType;
return this; return this;
} }
......
...@@ -95,7 +95,7 @@ public class TestConcurrent extends TestMVStore { ...@@ -95,7 +95,7 @@ public class TestConcurrent extends TestMVStore {
} }
MVMap<Integer, Integer> m = list.get(x); MVMap<Integer, Integer> m = list.get(x);
m.clear(); m.clear();
m.removeMap(); s.removeMap(m);
} }
} }
}; };
...@@ -108,7 +108,7 @@ public class TestConcurrent extends TestMVStore { ...@@ -108,7 +108,7 @@ public class TestConcurrent extends TestMVStore {
} }
MVMap<Integer, Integer> m = list.get(x); MVMap<Integer, Integer> m = list.get(x);
m.clear(); m.clear();
m.removeMap(); s.removeMap(m);
if (x % 5 == 0) { if (x % 5 == 0) {
s.incrementVersion(); s.incrementVersion();
} }
...@@ -152,7 +152,7 @@ public class TestConcurrent extends TestMVStore { ...@@ -152,7 +152,7 @@ public class TestConcurrent extends TestMVStore {
for (int i = 0; i < count || counter.get() < count; i++) { for (int i = 0; i < count || counter.get() < count; i++) {
MVMap<Integer, Integer> m = s.openMap("d" + i); MVMap<Integer, Integer> m = s.openMap("d" + i);
m.put(1, 10); m.put(1, 10);
m.removeMap(); s.removeMap(m);
if (task.isFinished()) { if (task.isFinished()) {
break; break;
} }
......
...@@ -110,7 +110,7 @@ public class TestMVStore extends TestBase { ...@@ -110,7 +110,7 @@ public class TestMVStore extends TestBase {
assertEquals(1, map.get(1).intValue()); assertEquals(1, map.get(1).intValue());
s.store(); s.store();
map.removeMap(); s.removeMap(map);
s.store(); s.store();
map = s.openMap("data"); map = s.openMap("data");
...@@ -222,7 +222,7 @@ public class TestMVStore extends TestBase { ...@@ -222,7 +222,7 @@ public class TestMVStore extends TestBase {
} }
for (int i = 0; i < 10; i += 2) { for (int i = 0; i < 10; i += 2) {
m = s.openMap("data" + i); m = s.openMap("data" + i);
m.removeMap(); s.removeMap(m);
s.store(); s.store();
} }
long sizeOld = s.getFileStore().size(); long sizeOld = s.getFileStore().size();
...@@ -503,7 +503,7 @@ public class TestMVStore extends TestBase { ...@@ -503,7 +503,7 @@ public class TestMVStore extends TestBase {
MVMap<Integer, Integer> m = s.openMap("test"); MVMap<Integer, Integer> m = s.openMap("test");
m.put(1, 1); m.put(1, 1);
s.store(); s.store();
m.removeMap(); s.removeMap(m);
s.store(); s.store();
s.close(); s.close();
s = openStore(fileName); s = openStore(fileName);
...@@ -518,7 +518,7 @@ public class TestMVStore extends TestBase { ...@@ -518,7 +518,7 @@ public class TestMVStore extends TestBase {
map = s.openMap("hello"); map = s.openMap("hello");
map.put(1, 10); map.put(1, 10);
long old = s.incrementVersion(); long old = s.incrementVersion();
map.renameMap("world"); s.renameMap(map, "world");
map.put(2, 20); map.put(2, 20);
assertEquals("world", map.getName()); assertEquals("world", map.getName());
s.rollbackTo(old); s.rollbackTo(old);
...@@ -635,7 +635,7 @@ public class TestMVStore extends TestBase { ...@@ -635,7 +635,7 @@ public class TestMVStore extends TestBase {
long size = fs.getFile().size(); long size = fs.getFile().size();
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
map = s.openMap("test" + i); map = s.openMap("test" + i);
map.removeMap(); s.removeMap(map);
s.store(); s.store();
s.commit(); s.commit();
s.compact(100); s.compact(100);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论