Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id EE4BE2009F8 for ; Fri, 3 Jun 2016 15:17:16 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id ED350160A2A; Fri, 3 Jun 2016 13:17:16 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id D287F160A25 for ; Fri, 3 Jun 2016 15:17:15 +0200 (CEST) Received: (qmail 27428 invoked by uid 500); 3 Jun 2016 13:17:15 -0000 Mailing-List: contact dev-help@accumulo.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@accumulo.apache.org Delivered-To: mailing list dev@accumulo.apache.org Received: (qmail 27399 invoked by uid 99); 3 Jun 2016 13:17:14 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 03 Jun 2016 13:17:14 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id A45FCE083B; Fri, 3 Jun 2016 13:17:14 +0000 (UTC) From: mjwall To: dev@accumulo.apache.org Reply-To: dev@accumulo.apache.org References: In-Reply-To: Subject: [GitHub] accumulo pull request #107: ACCUMULO-4157 Bug fix for removing WALs to quick... Content-Type: text/plain Message-Id: <20160603131714.A45FCE083B@git1-us-west.apache.org> Date: Fri, 3 Jun 2016 13:17:14 +0000 (UTC) archived-at: Fri, 03 Jun 2016 13:17:17 -0000 Github user mjwall commented on a diff in the pull request: https://github.com/apache/accumulo/pull/107#discussion_r65704867 --- Diff: server/gc/src/test/java/org/apache/accumulo/gc/GarbageCollectWriteAheadLogsTest.java --- @@ -234,4 +257,288 @@ public void testIsUUID() { assertFalse(GarbageCollectWriteAheadLogs.isUUID("0" + UUID.randomUUID().toString())); assertFalse(GarbageCollectWriteAheadLogs.isUUID(null)); } + + @Test + public void testTimeToDeleteTrue() throws InterruptedException { + gcwal.clearFirstSeenDead(); + HostAndPort address = HostAndPort.fromString("tserver1:9998"); + long wait = AccumuloConfiguration.getTimeInMillis("1s"); + gcwal.timeToDelete(address, wait); // to store first seen dead + sleep(wait * 2); + assertTrue(gcwal.timeToDelete(address, wait)); + } + + @Test + public void testTimeToDeleteFalse() { + HostAndPort address = HostAndPort.fromString("tserver1:9998"); + long wait = AccumuloConfiguration.getTimeInMillis("1h"); + long t1, t2; + boolean ttd; + do { + t1 = System.nanoTime(); + gcwal.clearFirstSeenDead(); + gcwal.timeToDelete(address, wait); + ttd = gcwal.timeToDelete(address, wait); + t2 = System.nanoTime(); + } while (t2 - t1 > (wait / 2) * 1000000); // as long as it took less than half of the configured wait + + assertFalse(gcwal.timeToDelete(address, wait)); + } + + @Test + public void testTimeToDeleteWithNullAddress() { + assertFalse(gcwal.timeToDelete(null, 123l)); + } + + /** + * Wrapper class with some helper methods + *

+ * Just a wrapper around a LinkedHashMap that store method name and argument information. Also includes some convenience methods to make usage cleaner. + */ + class MethodCalls { + + private LinkedHashMap> mapWrapper; + + public MethodCalls() { + mapWrapper = new LinkedHashMap>(); + } + + public void put(String methodName, Object... args) { + mapWrapper.put(methodName, Arrays.asList(args)); + } + + public int size() { + return mapWrapper.size(); + } + + public boolean hasOneEntry() { + return size() == 1; + } + + public Map.Entry> getFirstEntry() { + return mapWrapper.entrySet().iterator().next(); + } + + public String getFirstEntryMethod() { + return getFirstEntry().getKey(); + } + + public List getFirstEntryArgs() { + return getFirstEntry().getValue(); + } + + public Object getFirstEntryArg(int number) { + return getFirstEntryArgs().get(number); + } + } + + /** + * Partial mock of the GarbageCollectWriteAheadLogs for testing the removeFile method + *

+ * There is a map named methodCalls that can be used to assert parameters on methods called inside the removeFile method + */ + class GCWALPartialMock extends GarbageCollectWriteAheadLogs { + + private boolean holdsLockBool = false; + + public GCWALPartialMock(Instance i, VolumeManager vm, boolean useTrash, boolean holdLock) throws IOException { + super(i, vm, useTrash); + this.holdsLockBool = holdLock; + } + + public MethodCalls methodCalls = new MethodCalls(); + + @Override + boolean holdsLock(HostAndPort addr) { + return holdsLockBool; + } + + @Override + void removeWALfromDownTserver(HostAndPort address, AccumuloConfiguration conf, Entry> entry, final GCStatus status) { + methodCalls.put("removeWALFromDownTserver", address, conf, entry, status); + } + + @Override + void askTserverToRemoveWAL(HostAndPort address, AccumuloConfiguration conf, Entry> entry, final GCStatus status) { + methodCalls.put("askTserverToRemoveWAL", address, conf, entry, status); + } + + @Override + void removeOldStyleWAL(Entry> entry, final GCStatus status) { + methodCalls.put("removeOldStyleWAL", entry, status); + } + + @Override + void removeSortedWAL(Path swalog) { + methodCalls.put("removeSortedWAL", swalog); + } + } + + private GCWALPartialMock getGCWALForRemoveFileTest(GCStatus s, final boolean locked) throws IOException { + return new GCWALPartialMock(new MockInstance("accumulo"), VolumeManagerImpl.get(), false, locked); + } + + private Map getEmptyMap() { + return new HashMap(); + } + + private Map> getServerToFileMap1(String key, Path singlePath) { + Map> serverToFileMap = new HashMap>(); + serverToFileMap.put(key, new ArrayList(Arrays.asList(singlePath))); + return serverToFileMap; + } + + @Test + public void testRemoveFilesWithOldStyle() throws IOException { + GCStatus status = new GCStatus(); + GarbageCollectWriteAheadLogs realGCWAL = getGCWALForRemoveFileTest(status, true); + Path p1 = new Path("hdfs://localhost:9000/accumulo/wal/tserver1+9997/" + UUID.randomUUID().toString()); + Map> serverToFileMap = getServerToFileMap1("", p1); + + realGCWAL.removeFiles(getEmptyMap(), serverToFileMap, getEmptyMap(), status); + + MethodCalls calls = ((GCWALPartialMock) realGCWAL).methodCalls; + assertEquals("Only one method should have been called", 1, calls.size()); + assertEquals("Method should be removeOldStyleWAL", "removeOldStyleWAL", calls.getFirstEntryMethod()); + Entry> firstServerToFileMap = serverToFileMap.entrySet().iterator().next(); + assertEquals("First param should be empty", firstServerToFileMap, calls.getFirstEntryArg(0)); + assertEquals("Second param should be the status", status, calls.getFirstEntryArg(1)); + } + + @Test + public void testRemoveFilesWithDeadTservers() throws IOException { + GCStatus status = new GCStatus(); + GarbageCollectWriteAheadLogs realGCWAL = getGCWALForRemoveFileTest(status, false); + String server = "tserver1+9997"; + Path p1 = new Path("hdfs://localhost:9000/accumulo/wal/" + server + "/" + UUID.randomUUID().toString()); + Map> serverToFileMap = getServerToFileMap1(server, p1); + + realGCWAL.removeFiles(getEmptyMap(), serverToFileMap, getEmptyMap(), status); + + MethodCalls calls = ((GCWALPartialMock) realGCWAL).methodCalls; + assertEquals("Only one method should have been called", 1, calls.size()); + assertEquals("Method should be removeWALfromDownTserver", "removeWALFromDownTserver", calls.getFirstEntryMethod()); + assertEquals("First param should be address", HostAndPort.fromString(server.replaceAll("[+]", ":")), calls.getFirstEntryArg(0)); + assertTrue("Second param should be an AccumuloConfiguration", calls.getFirstEntryArg(1) instanceof AccumuloConfiguration); + Entry> firstServerToFileMap = serverToFileMap.entrySet().iterator().next(); + assertEquals("Third param should be the entry", firstServerToFileMap, calls.getFirstEntryArg(2)); + assertEquals("Forth param should be the status", status, calls.getFirstEntryArg(3)); + } + + @Test + public void testRemoveFilesWithLiveTservers() throws IOException { + GCStatus status = new GCStatus(); + GarbageCollectWriteAheadLogs realGCWAL = getGCWALForRemoveFileTest(status, true); + String server = "tserver1+9997"; + Path p1 = new Path("hdfs://localhost:9000/accumulo/wal/" + server + "/" + UUID.randomUUID().toString()); + Map> serverToFileMap = getServerToFileMap1(server, p1); + + realGCWAL.removeFiles(getEmptyMap(), serverToFileMap, getEmptyMap(), status); + + MethodCalls calls = ((GCWALPartialMock) realGCWAL).methodCalls; + assertEquals("Only one method should have been called", 1, calls.size()); + assertEquals("Method should be askTserverToRemoveWAL", "askTserverToRemoveWAL", calls.getFirstEntryMethod()); + assertEquals("First param should be address", HostAndPort.fromString(server.replaceAll("[+]", ":")), calls.getFirstEntryArg(0)); + assertTrue("Second param should be an AccumuloConfiguration", calls.getFirstEntryArg(1) instanceof AccumuloConfiguration); + Entry> firstServerToFileMap = serverToFileMap.entrySet().iterator().next(); + assertEquals("Third param should be the entry", firstServerToFileMap, calls.getFirstEntryArg(2)); + assertEquals("Forth param should be the status", status, calls.getFirstEntryArg(3)); + } + + @Test + public void testRemoveFilesRemovesSortedWALs() throws IOException { + GCStatus status = new GCStatus(); + GarbageCollectWriteAheadLogs realGCWAL = getGCWALForRemoveFileTest(status, true); + Map> serverToFileMap = new HashMap>(); + Map sortedWALogs = new HashMap(); + Path p1 = new Path("hdfs://localhost:9000/accumulo/wal/tserver1+9997/" + UUID.randomUUID().toString()); + sortedWALogs.put("junk", p1); // TODO: see if this key is actually used here, maybe can be removed + + realGCWAL.removeFiles(getEmptyMap(), serverToFileMap, sortedWALogs, status); + MethodCalls calls = ((GCWALPartialMock) realGCWAL).methodCalls; + assertEquals("Only one method should have been called", 1, calls.size()); + assertEquals("Method should be removeSortedWAL", "removeSortedWAL", calls.getFirstEntryMethod()); + assertEquals("First param should be the Path", p1, calls.getFirstEntryArg(0)); + + } + + static String GCWAL_DEAD_DIR = "gcwal-collect-deadtserver"; + static String GCWAL_DEAD_TSERVER = "tserver1"; + static String GCWAL_DEAD_TSERVER_PORT = "9995"; + static String GCWAL_DEAD_TSERVER_COLLECT_FILE = UUID.randomUUID().toString(); + + class GCWALDeadTserverCollectMock extends GarbageCollectWriteAheadLogs { + + public GCWALDeadTserverCollectMock(Instance i, VolumeManager vm, boolean useTrash) throws IOException { + super(i, vm, useTrash); + } + + @Override + boolean holdsLock(HostAndPort addr) { + // tries use zookeeper + return false; + } + + @Override + Map getSortedWALogs() { + return new HashMap(); + } + + @Override + int scanServers(Map fileToServerMap, Map nameToFileMap) throws Exception { + String sep = File.separator; + Path p = new Path(System.getProperty("java.io.tmpdir") + sep + GCWAL_DEAD_DIR + sep + GCWAL_DEAD_TSERVER + "+" + GCWAL_DEAD_TSERVER_PORT + sep + + GCWAL_DEAD_TSERVER_COLLECT_FILE); + fileToServerMap.put(p, GCWAL_DEAD_TSERVER + ":" + GCWAL_DEAD_TSERVER_PORT); + nameToFileMap.put(GCWAL_DEAD_TSERVER_COLLECT_FILE, p); + return 1; + } + + @Override + int removeMetadataEntries(Map nameToFileMap, Map sortedWALogs, GCStatus status) throws IOException, KeeperException, + InterruptedException { + return 0; + } + + long getGCWALDeadServerWaitTime(AccumuloConfiguration conf) { + // tries to use zookeeper + return 1000l; + } + } + + @Test + public void testCollectWithDeadTserver() throws IOException, InterruptedException { + Instance i = new MockInstance(); + File walDir = new File(System.getProperty("java.io.tmpdir") + File.separator + GCWAL_DEAD_DIR); --- End diff -- will update, thanks --- If your project is set up for it, you can reply to this email and have your reply appear on GitHub as well. If your project does not have this feature enabled and wishes so, or if the feature is enabled but not working, please contact infrastructure at infrastructure@apache.org or file a JIRA ticket with INFRA. ---