kezhuw commented on code in PR #2141: URL: https://github.com/apache/zookeeper/pull/2141#discussion_r1730657993
########## zookeeper-server/src/main/java/org/apache/zookeeper/server/persistence/FileTxnLog.java: ########## @@ -701,14 +708,26 @@ public long getStorageSize() { /** * go to the next logfile + * * @return true if there is one and false if there is no * new file to be read - * @throws IOException */ private boolean goToNextLog() throws IOException { - if (storedFiles.size() > 0) { + if (!storedFiles.isEmpty()) { this.logFile = storedFiles.remove(storedFiles.size() - 1); - ia = createInputArchive(this.logFile); + try { + ia = createInputArchive(this.logFile); + } catch (EOFException ex) { + // If this file is the last log file in the database and is empty, + // it means that the last time the file was created + // before the header was written. + if (storedFiles.isEmpty() && this.logFile.length() == 0) { + boolean deleted = this.logFile.delete(); + LOG.warn("Delete empty log file at the tail to recover from corruption. file: {}, deleted: {}", Review Comment: Also add hint to reboot ? ########## zookeeper-server/src/test/java/org/apache/zookeeper/server/persistence/FileTxnLogTest.java: ########## @@ -296,6 +302,73 @@ public void testLogSizeLimit(@TempDir File tmpDir) throws Exception { } } + private void prepareTxnLogs(File dir, int n) throws IOException { + FileTxnLog.setTxnLogSizeLimit(1); + FileTxnLog log = new FileTxnLog(dir); + CreateRequest record = new CreateRequest(null, new byte[NODE_SIZE], + ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT.toFlag()); + int zxid = 1; + for (int i = 0; i < n; i++) { + log.append(new Request(0, 0, 0, new TxnHeader(0, 0, zxid, 0, -1), record, zxid)); + zxid++; + log.commit(); + } + log.close(); + } + + public void testEmptyTxnLog(boolean clearTail) throws IOException { + // prepare a database with logs + File tmpDir = ClientBase.createTmpDir(); + LOG.info("tmp dir: {}", tmpDir.getPath()); + ClientBase.setupTestEnv(); + prepareTxnLogs(tmpDir, 4); + + // clear the log + List<File> files = Arrays. + stream(Objects.requireNonNull(tmpDir.listFiles((File f, String name) -> name.startsWith("log.")))). + sorted(Comparator.comparing(File::getName)). + collect(Collectors.toList()); + File toClear; + if (clearTail) { + toClear = files.get(files.size() - 1); + } else { + toClear = files.get(files.size() - 2); + } + PrintWriter writer = new PrintWriter(toClear); + writer.close(); + LOG.info("Txn log file {} cleared", toClear.getName()); + + // open txn log + boolean isEof = false; + try { + FileTxnLog.FileTxnIterator itr = new FileTxnLog.FileTxnIterator(tmpDir, 0x0, false); + while (itr.next()) {} + } catch (EOFException ex) { + isEof = true; + } + + if (clearTail) { + FileTxnLog.FileTxnIterator itr = new FileTxnLog.FileTxnIterator(tmpDir, 0x0, false); + while (itr.next()) {} + } else { + assertTrue(isEof, "Mid txn log file empty should throw Exception"); + } + } + + @Test + public void testEmptyTailTxnLog() throws IOException { + long limit = FileTxnLog.getTxnLogSizeLimit(); + testEmptyTxnLog(true); Review Comment: How about repeat some code to let's easy with testing code ? -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: notifications-unsubscr...@zookeeper.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org