You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@accumulo.apache.org by kt...@apache.org on 2013/04/09 22:21:57 UTC
svn commit: r1466211 - in /accumulo/branches/1.5:
core/src/main/java/org/apache/accumulo/core/util/
server/src/main/java/org/apache/accumulo/server/tabletserver/
server/src/main/java/org/apache/accumulo/server/util/
server/src/test/java/org/apache/accu...
Author: kturner
Date: Tue Apr 9 20:21:57 2013
New Revision: 1466211
URL: http://svn.apache.org/r1466211
Log:
ACCUMULO-1243 Made tablet loading code only load one tablet when recovering a split. Made code more strict, it will only load an exact tablet. Made load code roll back splits that have started, but did not create a new tablet. Added some more test.
Added:
accumulo/branches/1.5/server/src/test/java/org/apache/accumulo/server/tabletserver/CheckTabletMetadataTest.java
accumulo/branches/1.5/test/src/test/java/org/apache/accumulo/test/TestAccumuloSplitRecovery.java
- copied, changed from r1466018, accumulo/branches/1.5/test/src/test/java/org/apache/accumulo/test/TestAccumulo1235.java
Removed:
accumulo/branches/1.5/test/src/test/java/org/apache/accumulo/test/TestAccumulo1235.java
Modified:
accumulo/branches/1.5/core/src/main/java/org/apache/accumulo/core/util/MetadataTable.java
accumulo/branches/1.5/server/src/main/java/org/apache/accumulo/server/tabletserver/TabletServer.java
accumulo/branches/1.5/server/src/main/java/org/apache/accumulo/server/util/MetadataTable.java
accumulo/branches/1.5/test/src/main/java/org/apache/accumulo/test/functional/SplitRecoveryTest.java
accumulo/branches/1.5/test/src/main/java/org/apache/accumulo/test/performance/scan/CollectTabletStats.java
Modified: accumulo/branches/1.5/core/src/main/java/org/apache/accumulo/core/util/MetadataTable.java
URL: http://svn.apache.org/viewvc/accumulo/branches/1.5/core/src/main/java/org/apache/accumulo/core/util/MetadataTable.java?rev=1466211&r1=1466210&r2=1466211&view=diff
==============================================================================
--- accumulo/branches/1.5/core/src/main/java/org/apache/accumulo/core/util/MetadataTable.java (original)
+++ accumulo/branches/1.5/core/src/main/java/org/apache/accumulo/core/util/MetadataTable.java Tue Apr 9 20:21:57 2013
@@ -32,7 +32,6 @@ import org.apache.accumulo.core.client.A
import org.apache.accumulo.core.client.Instance;
import org.apache.accumulo.core.client.Scanner;
import org.apache.accumulo.core.client.TableNotFoundException;
-import org.apache.accumulo.core.client.impl.ScannerImpl;
import org.apache.accumulo.core.client.impl.Tables;
import org.apache.accumulo.core.data.Key;
import org.apache.accumulo.core.data.KeyExtent;
@@ -173,13 +172,7 @@ public class MetadataTable {
return new Pair<SortedMap<KeyExtent,Text>,List<KeyExtent>>(results, locationless);
}
-
- public static SortedMap<Text,SortedMap<ColumnFQ,Value>> getTabletEntries(Instance instance, KeyExtent ke, List<ColumnFQ> columns, TCredentials credentials) {
- TreeMap<Key,Value> tkv = new TreeMap<Key,Value>();
- getTabletAndPrevTabletKeyValues(instance, tkv, ke, columns, credentials);
- return getTabletEntries(tkv, columns);
- }
-
+
public static SortedMap<Text,SortedMap<ColumnFQ,Value>> getTabletEntries(SortedMap<Key,Value> tabletKeyValues, List<ColumnFQ> columns) {
TreeMap<Text,SortedMap<ColumnFQ,Value>> tabletEntries = new TreeMap<Text,SortedMap<ColumnFQ,Value>>();
@@ -207,40 +200,7 @@ public class MetadataTable {
return tabletEntries;
}
-
- public static void getTabletAndPrevTabletKeyValues(Instance instance, SortedMap<Key,Value> tkv, KeyExtent ke, List<ColumnFQ> columns, TCredentials credentials) {
- Text startRow;
- Text endRow = ke.getMetadataEntry();
- if (ke.getPrevEndRow() == null) {
- startRow = new Text(KeyExtent.getMetadataEntry(ke.getTableId(), new Text()));
- } else {
- startRow = new Text(KeyExtent.getMetadataEntry(ke.getTableId(), ke.getPrevEndRow()));
- }
-
- Scanner scanner = new ScannerImpl(instance, credentials, Constants.METADATA_TABLE_ID, Constants.NO_AUTHS);
-
- if (columns != null) {
- for (ColumnFQ column : columns)
- column.fetch(scanner);
- }
-
- scanner.setRange(new Range(new Key(startRow), true, new Key(endRow).followingKey(PartialKey.ROW), false));
-
- tkv.clear();
- boolean successful = false;
- try {
- for (Entry<Key,Value> entry : scanner) {
- tkv.put(entry.getKey(), entry.getValue());
- }
- successful = true;
- } finally {
- if (!successful) {
- tkv.clear();
- }
- }
- }
-
public static void getEntries(Instance instance, TCredentials credentials, String table, boolean isTid, Map<KeyExtent,String> locations,
SortedSet<KeyExtent> tablets) throws AccumuloException, AccumuloSecurityException, TableNotFoundException {
String tableId = isTid ? table : Tables.getNameToIdMap(instance).get(table);
Modified: accumulo/branches/1.5/server/src/main/java/org/apache/accumulo/server/tabletserver/TabletServer.java
URL: http://svn.apache.org/viewvc/accumulo/branches/1.5/server/src/main/java/org/apache/accumulo/server/tabletserver/TabletServer.java?rev=1466211&r1=1466210&r2=1466211&view=diff
==============================================================================
--- accumulo/branches/1.5/server/src/main/java/org/apache/accumulo/server/tabletserver/TabletServer.java (original)
+++ accumulo/branches/1.5/server/src/main/java/org/apache/accumulo/server/tabletserver/TabletServer.java Tue Apr 9 20:21:57 2013
@@ -68,6 +68,7 @@ import org.apache.accumulo.core.Constant
import org.apache.accumulo.core.client.AccumuloException;
import org.apache.accumulo.core.client.AccumuloSecurityException;
import org.apache.accumulo.core.client.Instance;
+import org.apache.accumulo.core.client.impl.ScannerImpl;
import org.apache.accumulo.core.client.impl.TabletType;
import org.apache.accumulo.core.client.impl.Translator;
import org.apache.accumulo.core.client.impl.thrift.SecurityErrorCode;
@@ -2442,10 +2443,10 @@ public class TabletServer extends Abstra
log.debug("Loading extent: " + extent);
// check Metadata table before accepting assignment
- SortedMap<KeyExtent,Text> tabletsInRange = null;
+ Text locationToOpen = null;
SortedMap<Key,Value> tabletsKeyValues = new TreeMap<Key,Value>();
try {
- tabletsInRange = verifyTabletInformation(extent, TabletServer.this.getTabletSession(), tabletsKeyValues, getClientAddressString(), getLock());
+ locationToOpen = verifyTabletInformation(extent, TabletServer.this.getTabletSession(), tabletsKeyValues, getClientAddressString(), getLock());
} catch (Exception e) {
synchronized (openingTablets) {
openingTablets.remove(extent);
@@ -2454,131 +2455,92 @@ public class TabletServer extends Abstra
log.warn("Failed to verify tablet " + extent, e);
throw new RuntimeException(e);
}
-
- if (tabletsInRange == null) {
- log.info("Reporting tablet " + extent + " assignment failure: unable to verify Tablet Information");
+
+ if (locationToOpen == null) {
+ log.debug("Reporting tablet " + extent + " assignment failure: unable to verify Tablet Information");
enqueueMasterMessage(new TabletStatusMessage(TabletLoadState.LOAD_FAILURE, extent));
synchronized (openingTablets) {
openingTablets.remove(extent);
openingTablets.notifyAll();
}
+
return;
}
- // If extent given is not the one to be opened, update
- if (tabletsInRange.size() != 1 || !tabletsInRange.containsKey(extent)) {
- synchronized (openingTablets) {
- openingTablets.remove(extent);
- openingTablets.notifyAll();
- for (KeyExtent e : tabletsInRange.keySet())
- openingTablets.add(e);
+
+ Tablet tablet = null;
+ boolean successful = false;
+
+ try {
+ TabletResourceManager trm = resourceManager.createTabletResourceManager();
+
+ // this opens the tablet file and fills in the endKey in the
+ // extent
+ tablet = new Tablet(TabletServer.this, locationToOpen, extent, trm, tabletsKeyValues);
+ /*
+ * If a minor compaction starts after a tablet opens, this indicates a log recovery occurred. This recovered data must be minor compacted.
+ *
+ * There are three reasons to wait for this minor compaction to finish before placing the tablet in online tablets.
+ *
+ * 1) The log recovery code does not handle data written to the tablet on multiple tablet servers. 2) The log recovery code does not block if memory is
+ * full. Therefore recovering lots of tablets that use a lot of memory could run out of memory. 3) The minor compaction finish event did not make it to
+ * the logs (the file will be in !METADATA, preventing replay of compacted data)... but do not want a majc to wipe the file out from !METADATA and then
+ * have another process failure... this could cause duplicate data to replay
+ */
+ if (tablet.getNumEntriesInMemory() > 0 && !tablet.minorCompactNow(MinorCompactionReason.SYSTEM)) {
+ throw new RuntimeException("Minor compaction after recovery fails for " + extent);
}
- } else {
- // remove any metadata entries for the previous tablet
- Iterator<Key> iter = tabletsKeyValues.keySet().iterator();
- Text row = extent.getMetadataEntry();
- while (iter.hasNext()) {
- Key key = iter.next();
- if (!key.getRow().equals(row)) {
- iter.remove();
+
+ Assignment assignment = new Assignment(extent, getTabletSession());
+ TabletStateStore.setLocation(assignment);
+
+ synchronized (openingTablets) {
+ synchronized (onlineTablets) {
+ openingTablets.remove(extent);
+ onlineTablets.put(extent, tablet);
+ openingTablets.notifyAll();
+ recentlyUnloadedCache.remove(tablet);
}
}
+ tablet = null; // release this reference
+ successful = true;
+ } catch (Throwable e) {
+ log.warn("exception trying to assign tablet " + extent + " " + locationToOpen, e);
+ if (e.getMessage() != null)
+ log.warn(e.getMessage());
+ String table = extent.getTableId().toString();
+ ProblemReports.getInstance().report(new ProblemReport(table, TABLET_LOAD, extent.getUUID().toString(), getClientAddressString(), e));
}
- if (tabletsInRange.size() > 1) {
- log.debug("Master didn't know " + extent + " was split, letting it know about " + tabletsInRange.keySet());
- enqueueMasterMessage(new SplitReportMessage(extent, tabletsInRange));
- }
-
- // create the tablet object
- for (Entry<KeyExtent,Text> entry : tabletsInRange.entrySet()) {
- Tablet tablet = null;
- boolean successful = false;
-
- final KeyExtent extentToOpen = entry.getKey();
- Text locationToOpen = entry.getValue();
-
- if (onlineTablets.containsKey(extentToOpen)) {
- // know this was from fixing a split, because initial check
- // would have caught original extent
- log.warn("Something is screwy! Already serving tablet " + extentToOpen + " derived from fixing split. Original extent = " + extent);
+
+ if (!successful) {
+ synchronized (unopenedTablets) {
synchronized (openingTablets) {
- openingTablets.remove(extentToOpen);
+ openingTablets.remove(extent);
+ unopenedTablets.add(extent);
openingTablets.notifyAll();
}
- continue;
}
-
- try {
- TabletResourceManager trm = resourceManager.createTabletResourceManager();
-
- // this opens the tablet file and fills in the endKey in the
- // extent
- tablet = new Tablet(TabletServer.this, locationToOpen, extentToOpen, trm, tabletsKeyValues);
- /*
- * If a minor compaction starts after a tablet opens, this indicates a log recovery occurred. This recovered data must be minor compacted.
- *
- * There are three reasons to wait for this minor compaction to finish before placing the tablet in online tablets.
- *
- * 1) The log recovery code does not handle data written to the tablet on multiple tablet servers. 2) The log recovery code does not block if memory
- * is full. Therefore recovering lots of tablets that use a lot of memory could run out of memory. 3) The minor compaction finish event did not make
- * it to the logs (the file will be in !METADATA, preventing replay of compacted data)... but do not want a majc to wipe the file out from !METADATA
- * and then have another process failure... this could cause duplicate data to replay
- */
- if (tablet.getNumEntriesInMemory() > 0 && !tablet.minorCompactNow(MinorCompactionReason.SYSTEM)) {
- throw new RuntimeException("Minor compaction after recovery fails for " + extentToOpen);
- }
-
- Assignment assignment = new Assignment(extentToOpen, getTabletSession());
- TabletStateStore.setLocation(assignment);
-
- synchronized (openingTablets) {
- synchronized (onlineTablets) {
- openingTablets.remove(extentToOpen);
- onlineTablets.put(extentToOpen, tablet);
- openingTablets.notifyAll();
- recentlyUnloadedCache.remove(tablet);
- }
- }
- tablet = null; // release this reference
- successful = true;
- } catch (Throwable e) {
- log.warn("exception trying to assign tablet " + extentToOpen + " " + locationToOpen, e);
- if (e.getMessage() != null)
- log.warn(e.getMessage());
- String table = extent.getTableId().toString();
- ProblemReports.getInstance().report(new ProblemReport(table, TABLET_LOAD, extentToOpen.getUUID().toString(), getClientAddressString(), e));
- }
-
- if (!successful) {
- synchronized (unopenedTablets) {
- synchronized (openingTablets) {
- openingTablets.remove(extentToOpen);
- unopenedTablets.add(extentToOpen);
- openingTablets.notifyAll();
- }
- }
- log.warn("failed to open tablet " + extentToOpen + " reporting failure to master");
- enqueueMasterMessage(new TabletStatusMessage(TabletLoadState.LOAD_FAILURE, extentToOpen));
- long reschedule = Math.min((1l << Math.min(32, retryAttempt)) * 1000, 10 * 60 * 1000l);
- log.warn(String.format("rescheduling tablet load in %.2f seconds", reschedule / 1000.));
- SimpleTimer.getInstance().schedule(new TimerTask() {
- @Override
- public void run() {
- log.info("adding tablet " + extent + " back to the assignment pool (retry " + retryAttempt + ")");
- AssignmentHandler handler = new AssignmentHandler(extentToOpen, retryAttempt + 1);
- if (extent.isMeta()) {
- if (extent.isRootTablet()) {
- new Daemon(new LoggingRunnable(log, handler), "Root tablet assignment retry").start();
- } else {
- resourceManager.addMetaDataAssignment(handler);
- }
+ log.warn("failed to open tablet " + extent + " reporting failure to master");
+ enqueueMasterMessage(new TabletStatusMessage(TabletLoadState.LOAD_FAILURE, extent));
+ long reschedule = Math.min((1l << Math.min(32, retryAttempt)) * 1000, 10 * 60 * 1000l);
+ log.warn(String.format("rescheduling tablet load in %.2f seconds", reschedule / 1000.));
+ SimpleTimer.getInstance().schedule(new TimerTask() {
+ @Override
+ public void run() {
+ log.info("adding tablet " + extent + " back to the assignment pool (retry " + retryAttempt + ")");
+ AssignmentHandler handler = new AssignmentHandler(extent, retryAttempt + 1);
+ if (extent.isMeta()) {
+ if (extent.isRootTablet()) {
+ new Daemon(new LoggingRunnable(log, handler), "Root tablet assignment retry").start();
} else {
- resourceManager.addAssignment(handler);
+ resourceManager.addMetaDataAssignment(handler);
}
+ } else {
+ resourceManager.addAssignment(handler);
}
- }, reschedule);
- } else {
- enqueueMasterMessage(new TabletStatusMessage(TabletLoadState.LOADED, extentToOpen));
- }
+ }
+ }, reschedule);
+ } else {
+ enqueueMasterMessage(new TabletStatusMessage(TabletLoadState.LOADED, extent));
}
}
}
@@ -2890,148 +2852,141 @@ public class TabletServer extends Abstra
private long totalMinorCompactions;
- public static SortedMap<KeyExtent,Text> verifyTabletInformation(KeyExtent extent, TServerInstance instance, SortedMap<Key,Value> tabletsKeyValues,
- String clientAddress, ZooLock lock) throws AccumuloSecurityException, DistributedStoreException {
- for (int tries = 0; tries < 3; tries++) {
- try {
- log.debug("verifying extent " + extent);
- if (extent.isRootTablet()) {
- ZooTabletStateStore store = new ZooTabletStateStore();
- if (!store.iterator().hasNext()) {
- log.warn("Illegal state: location is not set in zookeeper");
- return null;
- }
- TabletLocationState next = store.iterator().next();
- if (!instance.equals(next.future)) {
- log.warn("Future location is not to this server for the root tablet");
- return null;
- }
- TreeMap<KeyExtent,Text> set = new TreeMap<KeyExtent,Text>();
- set.put(extent, new Text(Constants.ZROOT_TABLET));
- return set;
- }
-
- List<ColumnFQ> columnsToFetch = Arrays.asList(new ColumnFQ[] {Constants.METADATA_DIRECTORY_COLUMN, Constants.METADATA_PREV_ROW_COLUMN,
- Constants.METADATA_SPLIT_RATIO_COLUMN, Constants.METADATA_OLD_PREV_ROW_COLUMN, Constants.METADATA_TIME_COLUMN});
-
- if (tabletsKeyValues == null) {
- tabletsKeyValues = new TreeMap<Key,Value>();
- }
- MetadataTable.getTabletAndPrevTabletKeyValues(tabletsKeyValues, extent, null, SecurityConstants.getSystemCredentials());
-
- SortedMap<Text,SortedMap<ColumnFQ,Value>> tabletEntries;
- tabletEntries = MetadataTable.getTabletEntries(tabletsKeyValues, columnsToFetch);
-
- if (tabletEntries.size() == 0) {
- log.warn("Failed to find any metadata entries for " + extent);
- return null;
- }
-
- // ensure last key in map is same as extent that was passed in
- if (!tabletEntries.lastKey().equals(extent.getMetadataEntry())) {
- log.warn("Failed to find metadata entry for " + extent + " found " + tabletEntries.lastKey());
- return null;
- }
-
- TServerInstance future = null;
- Text metadataEntry = extent.getMetadataEntry();
- for (Entry<Key,Value> entry : tabletsKeyValues.entrySet()) {
- Key key = entry.getKey();
- if (!metadataEntry.equals(key.getRow()))
- continue;
- Text cf = key.getColumnFamily();
- if (cf.equals(Constants.METADATA_FUTURE_LOCATION_COLUMN_FAMILY)) {
- future = new TServerInstance(entry.getValue(), key.getColumnQualifier());
- } else if (cf.equals(Constants.METADATA_CURRENT_LOCATION_COLUMN_FAMILY)) {
- log.error("Tablet seems to be already assigned to " + new TServerInstance(entry.getValue(), key.getColumnQualifier()));
- return null;
- }
- }
- if (future == null) {
- log.warn("The master has not assigned " + extent + " to " + instance);
- return null;
- }
- if (!instance.equals(future)) {
- log.warn("Table " + extent + " has been assigned to " + future + " which is not " + instance);
- return null;
- }
-
- // look for incomplete splits
- int splitsFixed = 0;
- for (Entry<Text,SortedMap<ColumnFQ,Value>> entry : tabletEntries.entrySet()) {
-
- if (extent.getPrevEndRow() != null) {
- Text prevRowMetadataEntry = new Text(KeyExtent.getMetadataEntry(extent.getTableId(), extent.getPrevEndRow()));
- if (entry.getKey().compareTo(prevRowMetadataEntry) <= 0) {
- continue;
- }
- }
-
- if (entry.getValue().containsKey(Constants.METADATA_OLD_PREV_ROW_COLUMN)) {
- KeyExtent fixedke = MetadataTable.fixSplit(entry.getKey(), entry.getValue(), instance, SecurityConstants.getSystemCredentials(), lock);
- if (fixedke != null) {
- if (fixedke.getPrevEndRow() == null || fixedke.getPrevEndRow().compareTo(extent.getPrevEndRow()) < 0) {
- extent = new KeyExtent(extent);
- extent.setPrevEndRow(fixedke.getPrevEndRow());
- }
- splitsFixed++;
- }
- }
- }
-
- if (splitsFixed > 0) {
- // reread and reverify metadata entries now that metadata
- // entries were fixed
- tabletsKeyValues.clear();
- return verifyTabletInformation(extent, instance, tabletsKeyValues, clientAddress, lock);
- }
-
- SortedMap<KeyExtent,Text> children = new TreeMap<KeyExtent,Text>();
-
- for (Entry<Text,SortedMap<ColumnFQ,Value>> entry : tabletEntries.entrySet()) {
- if (extent.getPrevEndRow() != null) {
- Text prevRowMetadataEntry = new Text(KeyExtent.getMetadataEntry(extent.getTableId(), extent.getPrevEndRow()));
-
- if (entry.getKey().compareTo(prevRowMetadataEntry) <= 0) {
- continue;
- }
- }
-
- Value prevEndRowIBW = entry.getValue().get(Constants.METADATA_PREV_ROW_COLUMN);
- if (prevEndRowIBW == null) {
- log.warn("Metadata entry does not have prev row (" + entry.getKey() + ")");
- return null;
- }
-
- Value dirIBW = entry.getValue().get(Constants.METADATA_DIRECTORY_COLUMN);
- if (dirIBW == null) {
- log.warn("Metadata entry does not have directory (" + entry.getKey() + ")");
- return null;
- }
-
- Text dir = new Text(dirIBW.get());
-
- KeyExtent child = new KeyExtent(entry.getKey(), prevEndRowIBW);
- children.put(child, dir);
- }
-
- if (!MetadataTable.isContiguousRange(extent, new TreeSet<KeyExtent>(children.keySet()))) {
- log.warn("For extent " + extent + " metadata entries " + children + " do not form a contiguous range.");
- return null;
- }
- return children;
- } catch (AccumuloException e) {
- log.error("error verifying metadata information. retrying ...");
- log.error(e.toString());
- UtilWaitThread.sleep(1000);
- } catch (AccumuloSecurityException e) {
- // if it's a security exception, retrying won't work either.
- log.error(e.toString());
- throw e;
+ private static Text verifyRootTablet(KeyExtent extent, TServerInstance instance) throws DistributedStoreException, AccumuloException {
+ ZooTabletStateStore store = new ZooTabletStateStore();
+ if (!store.iterator().hasNext()) {
+ throw new AccumuloException("Illegal state: location is not set in zookeeper");
+ }
+ TabletLocationState next = store.iterator().next();
+ if (!instance.equals(next.future)) {
+ throw new AccumuloException("Future location is not to this server for the root tablet");
+ }
+
+ if (next.current != null) {
+ throw new AccumuloException("Root tablet already has a location set");
+ }
+
+ return new Text(Constants.ZROOT_TABLET);
+ }
+
+ public static Text verifyTabletInformation(KeyExtent extent, TServerInstance instance, SortedMap<Key,Value> tabletsKeyValues, String clientAddress,
+ ZooLock lock) throws AccumuloSecurityException, DistributedStoreException, AccumuloException {
+
+ log.debug("verifying extent " + extent);
+ if (extent.isRootTablet()) {
+ return verifyRootTablet(extent, instance);
+ }
+
+ List<ColumnFQ> columnsToFetch = Arrays.asList(new ColumnFQ[] {Constants.METADATA_DIRECTORY_COLUMN, Constants.METADATA_PREV_ROW_COLUMN,
+ Constants.METADATA_SPLIT_RATIO_COLUMN, Constants.METADATA_OLD_PREV_ROW_COLUMN, Constants.METADATA_TIME_COLUMN});
+
+ ScannerImpl scanner = new ScannerImpl(HdfsZooInstance.getInstance(), SecurityConstants.getSystemCredentials(), Constants.METADATA_TABLE_ID,
+ Constants.NO_AUTHS);
+ scanner.setRange(extent.toMetadataRange());
+
+ TreeMap<Key,Value> tkv = new TreeMap<Key,Value>();
+ for (Entry<Key,Value> entry : scanner)
+ tkv.put(entry.getKey(), entry.getValue());
+
+ // only populate map after success
+ if (tabletsKeyValues == null) {
+ tabletsKeyValues = tkv;
+ } else {
+ tabletsKeyValues.clear();
+ tabletsKeyValues.putAll(tkv);
+ }
+
+ Text metadataEntry = extent.getMetadataEntry();
+
+ Value dir = checkTabletMetadata(extent, instance, tabletsKeyValues, metadataEntry);
+ if (dir == null)
+ return null;
+
+ Value oldPrevEndRow = null;
+ for (Entry<Key,Value> entry : tabletsKeyValues.entrySet()) {
+ if (Constants.METADATA_OLD_PREV_ROW_COLUMN.hasColumns(entry.getKey())) {
+ oldPrevEndRow = entry.getValue();
}
}
- // default is to accept
- return null;
+
+ if (oldPrevEndRow != null) {
+ SortedMap<Text,SortedMap<ColumnFQ,Value>> tabletEntries;
+ tabletEntries = MetadataTable.getTabletEntries(tabletsKeyValues, columnsToFetch);
+
+ KeyExtent fke = MetadataTable.fixSplit(metadataEntry, tabletEntries.get(metadataEntry), instance, SecurityConstants.getSystemCredentials(), lock);
+
+ if (!fke.equals(extent)) {
+ return null;
+ }
+
+ // reread and reverify metadata entries now that metadata entries were fixed
+ tabletsKeyValues.clear();
+ return verifyTabletInformation(fke, instance, tabletsKeyValues, clientAddress, lock);
+ }
+
+ return new Text(dir.get());
+ }
+
+ static Value checkTabletMetadata(KeyExtent extent, TServerInstance instance, SortedMap<Key,Value> tabletsKeyValues, Text metadataEntry)
+ throws AccumuloException {
+
+ TServerInstance future = null;
+ Value prevEndRow = null;
+ Value dir = null;
+ Value time = null;
+ for (Entry<Key,Value> entry : tabletsKeyValues.entrySet()) {
+ Key key = entry.getKey();
+ if (!metadataEntry.equals(key.getRow())) {
+ log.info("Unexpected row in tablet metadata " + metadataEntry + " " + key.getRow());
+ return null;
+ }
+ Text cf = key.getColumnFamily();
+ if (cf.equals(Constants.METADATA_FUTURE_LOCATION_COLUMN_FAMILY)) {
+ if (future != null) {
+ throw new AccumuloException("Tablet has multiple future locations " + extent);
+ }
+ future = new TServerInstance(entry.getValue(), key.getColumnQualifier());
+ } else if (cf.equals(Constants.METADATA_CURRENT_LOCATION_COLUMN_FAMILY)) {
+ log.info("Tablet seems to be already assigned to " + new TServerInstance(entry.getValue(), key.getColumnQualifier()));
+ return null;
+ } else if (Constants.METADATA_PREV_ROW_COLUMN.hasColumns(key)) {
+ prevEndRow = entry.getValue();
+ } else if (Constants.METADATA_DIRECTORY_COLUMN.hasColumns(key)) {
+ dir = entry.getValue();
+ } else if (Constants.METADATA_TIME_COLUMN.hasColumns(key)) {
+ time = entry.getValue();
+ }
+ }
+
+ if (prevEndRow == null) {
+ throw new AccumuloException("Metadata entry does not have prev row (" + metadataEntry + ")");
+ } else {
+ KeyExtent ke2 = new KeyExtent(metadataEntry, prevEndRow);
+ if (!extent.equals(ke2)) {
+ log.info("Tablet prev end row mismatch " + extent + " " + ke2.getPrevEndRow());
+ return null;
+ }
+ }
+
+ if (dir == null) {
+ throw new AccumuloException("Metadata entry does not have directory (" + metadataEntry + ")");
+ }
+
+ if (time == null) {
+ throw new AccumuloException("Metadata entry does not have time (" + metadataEntry + ")");
+ }
+
+ if (future == null) {
+ log.info("The master has not assigned " + extent + " to " + instance);
+ return null;
+ }
+
+ if (!instance.equals(future)) {
+ log.info("Table " + extent + " has been assigned to " + future + " which is not " + instance);
+ return null;
+ }
+
+ return dir;
}
public String getClientAddressString() {
Modified: accumulo/branches/1.5/server/src/main/java/org/apache/accumulo/server/util/MetadataTable.java
URL: http://svn.apache.org/viewvc/accumulo/branches/1.5/server/src/main/java/org/apache/accumulo/server/util/MetadataTable.java?rev=1466211&r1=1466210&r2=1466211&view=diff
==============================================================================
--- accumulo/branches/1.5/server/src/main/java/org/apache/accumulo/server/util/MetadataTable.java (original)
+++ accumulo/branches/1.5/server/src/main/java/org/apache/accumulo/server/util/MetadataTable.java Tue Apr 9 20:21:57 2013
@@ -339,7 +339,6 @@ public class MetadataTable extends org.a
TreeMap<String,DataFileValue> sizes = new TreeMap<String,DataFileValue>();
Scanner mdScanner = new ScannerImpl(HdfsZooInstance.getInstance(), credentials, Constants.METADATA_TABLE_ID, Constants.NO_AUTHS);
- mdScanner.setRange(Constants.METADATA_KEYSPACE);
mdScanner.fetchColumnFamily(Constants.METADATA_DATAFILE_COLUMN_FAMILY);
Text row = extent.getMetadataEntry();
@@ -386,6 +385,14 @@ public class MetadataTable extends org.a
update(credentials, zooLock, m);
}
+ public static void rollBackSplit(Text metadataEntry, Text oldPrevEndRow, TCredentials credentials, ZooLock zooLock) {
+ KeyExtent ke = new KeyExtent(metadataEntry, oldPrevEndRow);
+ Mutation m = ke.getPrevRowUpdateMutation();
+ Constants.METADATA_SPLIT_RATIO_COLUMN.putDelete(m);
+ Constants.METADATA_OLD_PREV_ROW_COLUMN.putDelete(m);
+ update(credentials, zooLock, m);
+ }
+
public static void splitTablet(KeyExtent extent, Text oldPrevEndRow, double splitRatio, TCredentials credentials, ZooLock zooLock) {
Mutation m = extent.getPrevRowUpdateMutation(); //
@@ -490,14 +497,6 @@ public class MetadataTable extends org.a
update(credentials, zooLock, m);
}
- public static void getTabletAndPrevTabletKeyValues(SortedMap<Key,Value> tkv, KeyExtent ke, List<ColumnFQ> columns, TCredentials credentials) {
- getTabletAndPrevTabletKeyValues(HdfsZooInstance.getInstance(), tkv, ke, columns, credentials);
- }
-
- public static SortedMap<Text,SortedMap<ColumnFQ,Value>> getTabletEntries(KeyExtent ke, List<ColumnFQ> columns, TCredentials credentials) {
- return getTabletEntries(HdfsZooInstance.getInstance(), ke, columns, credentials);
- }
-
private static KeyExtent fixSplit(Text table, Text metadataEntry, Text metadataPrevEndRow, Value oper, double splitRatio, TServerInstance tserver,
TCredentials credentials, String time, long initFlushID, long initCompactID, ZooLock lock) throws AccumuloException {
if (metadataPrevEndRow == null)
@@ -505,51 +504,45 @@ public class MetadataTable extends org.a
// prev end row....
throw new AccumuloException("Split tablet does not have prev end row, something is amiss, extent = " + metadataEntry);
- KeyExtent low = null;
-
- List<String> highDatafilesToRemove = new ArrayList<String>();
-
- String lowDirectory = TabletOperations.createTabletDirectory(ServerConstants.getTablesDir() + "/" + table, metadataPrevEndRow);
-
- Text prevPrevEndRow = KeyExtent.decodePrevEndRow(oper);
-
- low = new KeyExtent(table, metadataPrevEndRow, prevPrevEndRow);
-
- Scanner scanner3 = new ScannerImpl(HdfsZooInstance.getInstance(), credentials, Constants.METADATA_TABLE_ID, Constants.NO_AUTHS);
- Key rowKey = new Key(metadataEntry);
-
- SortedMap<String,DataFileValue> origDatafileSizes = new TreeMap<String,DataFileValue>();
- SortedMap<String,DataFileValue> highDatafileSizes = new TreeMap<String,DataFileValue>();
- SortedMap<String,DataFileValue> lowDatafileSizes = new TreeMap<String,DataFileValue>();
- scanner3.fetchColumnFamily(Constants.METADATA_DATAFILE_COLUMN_FAMILY);
- scanner3.setRange(new Range(rowKey, rowKey.followingKey(PartialKey.ROW)));
-
- for (Entry<Key,Value> entry : scanner3) {
- if (entry.getKey().compareColumnFamily(Constants.METADATA_DATAFILE_COLUMN_FAMILY) == 0) {
- origDatafileSizes.put(entry.getKey().getColumnQualifier().toString(), new DataFileValue(entry.getValue().get()));
- }
- }
-
- splitDatafiles(table, metadataPrevEndRow, splitRatio, new HashMap<String,FileUtil.FileInfo>(), origDatafileSizes, lowDatafileSizes, highDatafileSizes,
- highDatafilesToRemove);
-
// check to see if prev tablet exist in metadata tablet
Key prevRowKey = new Key(new Text(KeyExtent.getMetadataEntry(table, metadataPrevEndRow)));
-
+
ScannerImpl scanner2 = new ScannerImpl(HdfsZooInstance.getInstance(), credentials, Constants.METADATA_TABLE_ID, Constants.NO_AUTHS);
scanner2.setRange(new Range(prevRowKey, prevRowKey.followingKey(PartialKey.ROW)));
if (!scanner2.iterator().hasNext()) {
- log.debug("Prev tablet " + prevRowKey + " does not exist, need to create it " + metadataPrevEndRow + " " + prevPrevEndRow + " " + splitRatio);
- Map<String,Long> bulkFiles = getBulkFilesLoaded(credentials, metadataEntry);
- MetadataTable.addNewTablet(low, lowDirectory, tserver, lowDatafileSizes, bulkFiles, credentials, time, initFlushID, initCompactID, lock);
+ log.info("Rolling back incomplete split " + metadataEntry + " " + metadataPrevEndRow);
+ rollBackSplit(metadataEntry, KeyExtent.decodePrevEndRow(oper), credentials, lock);
+ return new KeyExtent(metadataEntry, KeyExtent.decodePrevEndRow(oper));
} else {
- log.debug("Prev tablet " + prevRowKey + " exist, do not need to add it");
- }
-
- MetadataTable.finishSplit(metadataEntry, highDatafileSizes, highDatafilesToRemove, credentials, lock);
+ log.info("Finishing incomplete split " + metadataEntry + " " + metadataPrevEndRow);
+
+ List<String> highDatafilesToRemove = new ArrayList<String>();
+
+ Scanner scanner3 = new ScannerImpl(HdfsZooInstance.getInstance(), credentials, Constants.METADATA_TABLE_ID, Constants.NO_AUTHS);
+ Key rowKey = new Key(metadataEntry);
+
+ SortedMap<String,DataFileValue> origDatafileSizes = new TreeMap<String,DataFileValue>();
+ SortedMap<String,DataFileValue> highDatafileSizes = new TreeMap<String,DataFileValue>();
+ SortedMap<String,DataFileValue> lowDatafileSizes = new TreeMap<String,DataFileValue>();
+ scanner3.fetchColumnFamily(Constants.METADATA_DATAFILE_COLUMN_FAMILY);
+ scanner3.setRange(new Range(rowKey, rowKey.followingKey(PartialKey.ROW)));
+
+ for (Entry<Key,Value> entry : scanner3) {
+ if (entry.getKey().compareColumnFamily(Constants.METADATA_DATAFILE_COLUMN_FAMILY) == 0) {
+ origDatafileSizes.put(entry.getKey().getColumnQualifier().toString(), new DataFileValue(entry.getValue().get()));
+ }
+ }
+
+ splitDatafiles(table, metadataPrevEndRow, splitRatio, new HashMap<String,FileUtil.FileInfo>(), origDatafileSizes, lowDatafileSizes, highDatafileSizes,
+ highDatafilesToRemove);
- return low;
+ MetadataTable.finishSplit(metadataEntry, highDatafileSizes, highDatafilesToRemove, credentials, lock);
+
+ return new KeyExtent(metadataEntry, KeyExtent.encodePrevEndRow(metadataPrevEndRow));
+ }
+
+
}
public static void splitDatafiles(Text table, Text midRow, double splitRatio, Map<String,FileUtil.FileInfo> firstAndLastRows,
@@ -597,13 +590,12 @@ public class MetadataTable extends org.a
public static KeyExtent fixSplit(Text metadataEntry, SortedMap<ColumnFQ,Value> columns, TServerInstance tserver, TCredentials credentials, ZooLock lock)
throws AccumuloException {
- log.warn("Incomplete split " + metadataEntry + " attempting to fix");
+ log.info("Incomplete split " + metadataEntry + " attempting to fix");
Value oper = columns.get(Constants.METADATA_OLD_PREV_ROW_COLUMN);
if (columns.get(Constants.METADATA_SPLIT_RATIO_COLUMN) == null) {
- log.warn("Metadata entry does not have split ratio (" + metadataEntry + ")");
- return null;
+ throw new IllegalArgumentException("Metadata entry does not have split ratio (" + metadataEntry + ")");
}
double splitRatio = Double.parseDouble(new String(columns.get(Constants.METADATA_SPLIT_RATIO_COLUMN).get()));
@@ -611,15 +603,13 @@ public class MetadataTable extends org.a
Value prevEndRowIBW = columns.get(Constants.METADATA_PREV_ROW_COLUMN);
if (prevEndRowIBW == null) {
- log.warn("Metadata entry does not have prev row (" + metadataEntry + ")");
- return null;
+ throw new IllegalArgumentException("Metadata entry does not have prev row (" + metadataEntry + ")");
}
Value time = columns.get(Constants.METADATA_TIME_COLUMN);
if (time == null) {
- log.warn("Metadata entry does not have time (" + metadataEntry + ")");
- return null;
+ throw new IllegalArgumentException("Metadata entry does not have time (" + metadataEntry + ")");
}
Value flushID = columns.get(Constants.METADATA_FLUSH_COLUMN);
Added: accumulo/branches/1.5/server/src/test/java/org/apache/accumulo/server/tabletserver/CheckTabletMetadataTest.java
URL: http://svn.apache.org/viewvc/accumulo/branches/1.5/server/src/test/java/org/apache/accumulo/server/tabletserver/CheckTabletMetadataTest.java?rev=1466211&view=auto
==============================================================================
--- accumulo/branches/1.5/server/src/test/java/org/apache/accumulo/server/tabletserver/CheckTabletMetadataTest.java (added)
+++ accumulo/branches/1.5/server/src/test/java/org/apache/accumulo/server/tabletserver/CheckTabletMetadataTest.java Tue Apr 9 20:21:57 2013
@@ -0,0 +1,106 @@
+package org.apache.accumulo.server.tabletserver;
+
+import java.util.TreeMap;
+
+import org.apache.accumulo.core.Constants;
+import org.apache.accumulo.core.data.Key;
+import org.apache.accumulo.core.data.KeyExtent;
+import org.apache.accumulo.core.data.Value;
+import org.apache.accumulo.core.util.ColumnFQ;
+import org.apache.accumulo.server.master.state.TServerInstance;
+import org.apache.hadoop.io.Text;
+import org.junit.Assert;
+import org.junit.Test;
+
+
+public class CheckTabletMetadataTest {
+
+ private static Key nk(String row, ColumnFQ cfq) {
+ return new Key(new Text(row), cfq.getColumnFamily(), cfq.getColumnQualifier());
+ }
+
+ private static Key nk(String row, Text cf, String cq) {
+ return new Key(row, cf.toString(), cq);
+ }
+
+ private static void put(TreeMap<Key,Value> tabletMeta, String row, ColumnFQ cfq, byte[] val) {
+ Key k = new Key(new Text(row), cfq.getColumnFamily(), cfq.getColumnQualifier());
+ tabletMeta.put(k, new Value(val));
+ }
+
+ private static void put(TreeMap<Key,Value> tabletMeta, String row, Text cf, String cq, String val) {
+ Key k = new Key(new Text(row), cf, new Text(cq));
+ tabletMeta.put(k, new Value(val.getBytes()));
+ }
+
+ private static void assertFail(TreeMap<Key,Value> tabletMeta, KeyExtent ke, TServerInstance tsi) {
+ try {
+ Assert.assertNull(TabletServer.checkTabletMetadata(ke, tsi, tabletMeta, ke.getMetadataEntry()));
+ } catch (Exception e) {
+
+ }
+ }
+
+ private static void assertFail(TreeMap<Key,Value> tabletMeta, KeyExtent ke, TServerInstance tsi, Key keyToDelete) {
+ TreeMap<Key,Value> copy = new TreeMap<Key,Value>(tabletMeta);
+ Assert.assertNotNull(copy.remove(keyToDelete));
+ try {
+ Assert.assertNull(TabletServer.checkTabletMetadata(ke, tsi, copy, ke.getMetadataEntry()));
+ } catch (Exception e) {
+
+ }
+ }
+
+ @Test
+ public void testBadTabletMetadata() throws Exception {
+
+ KeyExtent ke = new KeyExtent(new Text("1"), null, null);
+
+ TreeMap<Key,Value> tabletMeta = new TreeMap<Key,Value>();
+
+ put(tabletMeta, "1<", Constants.METADATA_PREV_ROW_COLUMN, KeyExtent.encodePrevEndRow(null).get());
+ put(tabletMeta, "1<", Constants.METADATA_DIRECTORY_COLUMN, "/t1".getBytes());
+ put(tabletMeta, "1<", Constants.METADATA_TIME_COLUMN, "M0".getBytes());
+ put(tabletMeta, "1<", Constants.METADATA_FUTURE_LOCATION_COLUMN_FAMILY, "4", "127.0.0.1:9997");
+
+ TServerInstance tsi = new TServerInstance("127.0.0.1:9997", 4);
+
+ Assert.assertNotNull(TabletServer.checkTabletMetadata(ke, tsi, tabletMeta, ke.getMetadataEntry()));
+
+ assertFail(tabletMeta, ke, new TServerInstance("127.0.0.1:9998", 4));
+ assertFail(tabletMeta, ke, new TServerInstance("127.0.0.1:9998", 5));
+ assertFail(tabletMeta, ke, new TServerInstance("127.0.0.1:9997", 5));
+ assertFail(tabletMeta, ke, new TServerInstance("127.0.0.2:9997", 4));
+ assertFail(tabletMeta, ke, new TServerInstance("127.0.0.2:9997", 5));
+
+ assertFail(tabletMeta, new KeyExtent(new Text("1"), null, new Text("m")), tsi);
+
+ assertFail(tabletMeta, new KeyExtent(new Text("1"), new Text("r"), new Text("m")), tsi);
+
+ assertFail(tabletMeta, ke, tsi, nk("1<", Constants.METADATA_PREV_ROW_COLUMN));
+
+ assertFail(tabletMeta, ke, tsi, nk("1<", Constants.METADATA_DIRECTORY_COLUMN));
+
+ assertFail(tabletMeta, ke, tsi, nk("1<", Constants.METADATA_TIME_COLUMN));
+
+ assertFail(tabletMeta, ke, tsi, nk("1<", Constants.METADATA_FUTURE_LOCATION_COLUMN_FAMILY, "4"));
+
+ TreeMap<Key,Value> copy = new TreeMap<Key,Value>(tabletMeta);
+ put(copy, "1<", Constants.METADATA_CURRENT_LOCATION_COLUMN_FAMILY, "4", "127.0.0.1:9997");
+ assertFail(copy, ke, tsi);
+ assertFail(copy, ke, tsi, nk("1<", Constants.METADATA_FUTURE_LOCATION_COLUMN_FAMILY, "4"));
+
+ copy = new TreeMap<Key,Value>(tabletMeta);
+ put(copy, "1<", Constants.METADATA_CURRENT_LOCATION_COLUMN_FAMILY, "5", "127.0.0.1:9998");
+ assertFail(copy, ke, tsi);
+ put(copy, "1<", Constants.METADATA_CURRENT_LOCATION_COLUMN_FAMILY, "6", "127.0.0.1:9999");
+ assertFail(copy, ke, tsi);
+
+ copy = new TreeMap<Key,Value>(tabletMeta);
+ put(copy, "1<", Constants.METADATA_FUTURE_LOCATION_COLUMN_FAMILY, "5", "127.0.0.1:9998");
+ assertFail(copy, ke, tsi);
+
+ assertFail(new TreeMap<Key,Value>(), ke, tsi);
+
+ }
+}
Modified: accumulo/branches/1.5/test/src/main/java/org/apache/accumulo/test/functional/SplitRecoveryTest.java
URL: http://svn.apache.org/viewvc/accumulo/branches/1.5/test/src/main/java/org/apache/accumulo/test/functional/SplitRecoveryTest.java?rev=1466211&r1=1466210&r2=1466211&view=diff
==============================================================================
--- accumulo/branches/1.5/test/src/main/java/org/apache/accumulo/test/functional/SplitRecoveryTest.java (original)
+++ accumulo/branches/1.5/test/src/main/java/org/apache/accumulo/test/functional/SplitRecoveryTest.java Tue Apr 9 20:21:57 2013
@@ -28,6 +28,8 @@ import java.util.SortedMap;
import java.util.TreeMap;
import org.apache.accumulo.core.Constants;
+import org.apache.accumulo.core.client.Scanner;
+import org.apache.accumulo.core.client.impl.ScannerImpl;
import org.apache.accumulo.core.client.impl.Writer;
import org.apache.accumulo.core.data.Key;
import org.apache.accumulo.core.data.KeyExtent;
@@ -176,34 +178,32 @@ public class SplitRecoveryTest extends F
if (steps >= 2)
MetadataTable.finishSplit(high, highDatafileSizes, highDatafilesToRemove, SecurityConstants.getSystemCredentials(), zl);
- SortedMap<KeyExtent,Text> vtiRet = TabletServer.verifyTabletInformation(extent, instance, null, "127.0.0.1:0", zl);
- if (vtiRet.size() != 2) {
- throw new Exception("verifyTabletInformation did not return two tablets, " + vtiRet.size());
- }
-
- if (!vtiRet.containsKey(high) || !vtiRet.containsKey(low)) {
- throw new Exception("verifyTabletInformation did not return correct tablets, " + vtiRet.keySet());
- }
-
- ensureTabletHasNoUnexpectedMetadataEntries(low, lowDatafileSizes);
- ensureTabletHasNoUnexpectedMetadataEntries(high, highDatafileSizes);
+ TabletServer.verifyTabletInformation(high, instance, null, "127.0.0.1:0", zl);
+
+ if (steps >= 1) {
+ ensureTabletHasNoUnexpectedMetadataEntries(low, lowDatafileSizes);
+ ensureTabletHasNoUnexpectedMetadataEntries(high, highDatafileSizes);
- Map<String,Long> lowBulkFiles = MetadataTable.getBulkFilesLoaded(SecurityConstants.getSystemCredentials(), low);
- Map<String,Long> highBulkFiles = MetadataTable.getBulkFilesLoaded(SecurityConstants.getSystemCredentials(), high);
+ Map<String,Long> lowBulkFiles = MetadataTable.getBulkFilesLoaded(SecurityConstants.getSystemCredentials(), low);
+ Map<String,Long> highBulkFiles = MetadataTable.getBulkFilesLoaded(SecurityConstants.getSystemCredentials(), high);
- if (!lowBulkFiles.equals(highBulkFiles)) {
- throw new Exception(" " + lowBulkFiles + " != " + highBulkFiles + " " + low + " " + high);
- }
+ if (!lowBulkFiles.equals(highBulkFiles)) {
+ throw new Exception(" " + lowBulkFiles + " != " + highBulkFiles + " " + low + " " + high);
+ }
- if (lowBulkFiles.size() == 0) {
- throw new Exception(" no bulk files " + low);
+ if (lowBulkFiles.size() == 0) {
+ throw new Exception(" no bulk files " + low);
+ }
+ } else {
+ ensureTabletHasNoUnexpectedMetadataEntries(extent, mapFiles);
}
}
private void ensureTabletHasNoUnexpectedMetadataEntries(KeyExtent extent, SortedMap<String,DataFileValue> expectedMapFiles) throws Exception {
- SortedMap<Key,Value> tkv = new TreeMap<Key,Value>();
- MetadataTable.getTabletAndPrevTabletKeyValues(tkv, extent, null, SecurityConstants.getSystemCredentials());
+ Scanner scanner = new ScannerImpl(HdfsZooInstance.getInstance(), SecurityConstants.getSystemCredentials(), Constants.METADATA_TABLE_ID,
+ Constants.NO_AUTHS);
+ scanner.setRange(extent.toMetadataRange());
HashSet<ColumnFQ> expectedColumns = new HashSet<ColumnFQ>();
expectedColumns.add(Constants.METADATA_DIRECTORY_COLUMN);
@@ -218,12 +218,12 @@ public class SplitRecoveryTest extends F
expectedColumnFamilies.add(Constants.METADATA_LAST_LOCATION_COLUMN_FAMILY);
expectedColumnFamilies.add(Constants.METADATA_BULKFILE_COLUMN_FAMILY);
- Iterator<Key> iter = tkv.keySet().iterator();
+ Iterator<Entry<Key,Value>> iter = scanner.iterator();
while (iter.hasNext()) {
- Key key = iter.next();
+ Key key = iter.next().getKey();
if (!key.getRow().equals(extent.getMetadataEntry())) {
- continue;
+ throw new Exception("Tablet " + extent + " contained unexpected " + Constants.METADATA_TABLE_NAME + " entry " + key);
}
if (expectedColumnFamilies.contains(key.getColumnFamily())) {
Modified: accumulo/branches/1.5/test/src/main/java/org/apache/accumulo/test/performance/scan/CollectTabletStats.java
URL: http://svn.apache.org/viewvc/accumulo/branches/1.5/test/src/main/java/org/apache/accumulo/test/performance/scan/CollectTabletStats.java?rev=1466211&r1=1466210&r2=1466211&view=diff
==============================================================================
--- accumulo/branches/1.5/test/src/main/java/org/apache/accumulo/test/performance/scan/CollectTabletStats.java (original)
+++ accumulo/branches/1.5/test/src/main/java/org/apache/accumulo/test/performance/scan/CollectTabletStats.java Tue Apr 9 20:21:57 2013
@@ -27,8 +27,6 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
-import java.util.Set;
-import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
@@ -36,7 +34,6 @@ import java.util.concurrent.CountDownLat
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
-import org.apache.accumulo.core.Constants;
import org.apache.accumulo.core.cli.ScannerOpts;
import org.apache.accumulo.core.client.Connector;
import org.apache.accumulo.core.client.Instance;
@@ -67,12 +64,12 @@ import org.apache.accumulo.core.security
import org.apache.accumulo.core.security.thrift.TCredentials;
import org.apache.accumulo.core.util.AddressUtil;
import org.apache.accumulo.core.util.CachedConfiguration;
-import org.apache.accumulo.core.util.MetadataTable;
import org.apache.accumulo.core.util.Stat;
import org.apache.accumulo.server.ServerConstants;
import org.apache.accumulo.server.cli.ClientOnRequiredTable;
import org.apache.accumulo.server.conf.ServerConfiguration;
import org.apache.accumulo.server.conf.TableConfiguration;
+import org.apache.accumulo.server.util.MetadataTable;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.BlockLocation;
import org.apache.hadoop.fs.FileStatus;
@@ -378,16 +375,8 @@ public class CollectTabletStats {
private static List<String> getTabletFiles(TCredentials token, Instance zki, String tableId, KeyExtent ke) {
List<String> files = new ArrayList<String>();
- SortedMap<Key,Value> tkv = new TreeMap<Key,Value>();
- MetadataTable.getTabletAndPrevTabletKeyValues(zki, tkv, ke, null, token);
-
- Set<Entry<Key,Value>> es = tkv.entrySet();
- for (Entry<Key,Value> entry : es) {
- if (entry.getKey().compareRow(ke.getMetadataEntry()) == 0) {
- if (entry.getKey().compareColumnFamily(Constants.METADATA_DATAFILE_COLUMN_FAMILY) == 0) {
- files.add(ServerConstants.getTablesDir() + "/" + tableId + entry.getKey().getColumnQualifier());
- }
- }
+ for (String cq : MetadataTable.getDataFileSizes(ke, token).keySet()) {
+ files.add(ServerConstants.getTablesDir() + "/" + tableId + cq);
}
return files;
}
Copied: accumulo/branches/1.5/test/src/test/java/org/apache/accumulo/test/TestAccumuloSplitRecovery.java (from r1466018, accumulo/branches/1.5/test/src/test/java/org/apache/accumulo/test/TestAccumulo1235.java)
URL: http://svn.apache.org/viewvc/accumulo/branches/1.5/test/src/test/java/org/apache/accumulo/test/TestAccumuloSplitRecovery.java?p2=accumulo/branches/1.5/test/src/test/java/org/apache/accumulo/test/TestAccumuloSplitRecovery.java&p1=accumulo/branches/1.5/test/src/test/java/org/apache/accumulo/test/TestAccumulo1235.java&r1=1466018&r2=1466211&rev=1466211&view=diff
==============================================================================
--- accumulo/branches/1.5/test/src/test/java/org/apache/accumulo/test/TestAccumulo1235.java (original)
+++ accumulo/branches/1.5/test/src/test/java/org/apache/accumulo/test/TestAccumuloSplitRecovery.java Tue Apr 9 20:21:57 2013
@@ -41,7 +41,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
-public class TestAccumulo1235 {
+public class TestAccumuloSplitRecovery {
private static final String TABLE = "simple";
public static TemporaryFolder folder = new TemporaryFolder();
@@ -81,44 +81,71 @@ public class TestAccumulo1235 {
@Test
public void test() throws Exception {
- ZooKeeperInstance instance = new ZooKeeperInstance(accumulo.getInstanceName(), accumulo.getZooKeepers());
- Connector connector = instance.getConnector("root", new PasswordToken(secret));
- // create a table and put some data in it
- connector.tableOperations().create(TABLE);
- BatchWriter bw = connector.createBatchWriter(TABLE, new BatchWriterConfig());
- bw.addMutation(m("a"));
- bw.addMutation(m("b"));
- bw.addMutation(m("c"));
- bw.close();
- // take the table offline
- connector.tableOperations().offline(TABLE);
- while (!isOffline(TABLE, connector))
- UtilWaitThread.sleep(200);
+ for (int tn = 0; tn < 2; tn++) {
- // poke a partial split into the !METADATA table
- connector.securityOperations().grantTablePermission("root", Constants.METADATA_TABLE_NAME, TablePermission.WRITE);
- String tableId = connector.tableOperations().tableIdMap().get(TABLE);
-
- KeyExtent extent = new KeyExtent(new Text(tableId), null, new Text("b"));
- Mutation m = extent.getPrevRowUpdateMutation();
-
- Constants.METADATA_SPLIT_RATIO_COLUMN.put(m, new Value(Double.toString(0.5).getBytes()));
- Constants.METADATA_OLD_PREV_ROW_COLUMN.put(m, KeyExtent.encodePrevEndRow(null));
- bw = connector.createBatchWriter(Constants.METADATA_TABLE_NAME, new BatchWriterConfig());
- bw.addMutation(m);
- bw.close();
- // bring the table online
- connector.tableOperations().online(TABLE);
+ ZooKeeperInstance instance = new ZooKeeperInstance(accumulo.getInstanceName(), accumulo.getZooKeepers());
+ Connector connector = instance.getConnector("root", new PasswordToken(secret));
+ // create a table and put some data in it
+ connector.tableOperations().create(TABLE);
+ BatchWriter bw = connector.createBatchWriter(TABLE, new BatchWriterConfig());
+ bw.addMutation(m("a"));
+ bw.addMutation(m("b"));
+ bw.addMutation(m("c"));
+ bw.close();
+ // take the table offline
+ connector.tableOperations().offline(TABLE);
+ while (!isOffline(TABLE, connector))
+ UtilWaitThread.sleep(200);
+
+ // poke a partial split into the !METADATA table
+ connector.securityOperations().grantTablePermission("root", Constants.METADATA_TABLE_NAME, TablePermission.WRITE);
+ String tableId = connector.tableOperations().tableIdMap().get(TABLE);
+
+ KeyExtent extent = new KeyExtent(new Text(tableId), null, new Text("b"));
+ Mutation m = extent.getPrevRowUpdateMutation();
+
+ Constants.METADATA_SPLIT_RATIO_COLUMN.put(m, new Value(Double.toString(0.5).getBytes()));
+ Constants.METADATA_OLD_PREV_ROW_COLUMN.put(m, KeyExtent.encodePrevEndRow(null));
+ bw = connector.createBatchWriter(Constants.METADATA_TABLE_NAME, new BatchWriterConfig());
+ bw.addMutation(m);
+
+ if (tn == 1) {
+
+ bw.flush();
+
+ Scanner scanner = connector.createScanner(Constants.METADATA_TABLE_NAME, Constants.NO_AUTHS);
+ scanner.setRange(extent.toMetadataRange());
+ scanner.fetchColumnFamily(Constants.METADATA_DATAFILE_COLUMN_FAMILY);
+
+ KeyExtent extent2 = new KeyExtent(new Text(tableId), new Text("b"), null);
+ m = extent2.getPrevRowUpdateMutation();
+ Constants.METADATA_DIRECTORY_COLUMN.put(m, new Value("/t2".getBytes()));
+ Constants.METADATA_TIME_COLUMN.put(m, new Value("M0".getBytes()));
+
+ for (Entry<Key,Value> entry : scanner) {
+ m.put(Constants.METADATA_DATAFILE_COLUMN_FAMILY, entry.getKey().getColumnQualifier(), entry.getValue());
+ }
+
+ bw.addMutation(m);
+ }
+
+ bw.close();
+ // bring the table online
+ connector.tableOperations().online(TABLE);
+
+ // verify the tablets went online
+ Scanner scanner = connector.createScanner(TABLE, Constants.NO_AUTHS);
+ int i = 0;
+ String expected[] = {"a", "b", "c"};
+ for (Entry<Key,Value> entry : scanner) {
+ assertEquals(expected[i], entry.getKey().getRow().toString());
+ i++;
+ }
+ assertEquals(3, i);
+
+ connector.tableOperations().delete(TABLE);
- // verify the tablets went online
- Scanner scanner = connector.createScanner(TABLE, Constants.NO_AUTHS);
- int i = 0;
- String expected[] = { "a", "b", "c" };
- for (Entry<Key,Value> entry: scanner) {
- assertEquals(expected[i], entry.getKey().getRow().toString());
- i++;
}
- assertEquals(3, i);
}
}