public EmailJournal(String journalDir, int maxFileLength, int delay, MetricRegistry registry) throws IOException {Preconditions.checkArgument(!Strings.isNullOrEmpty(journalDir));Preconditions.checkArgument(maxFileLength > 0);Preconditions.checkArgument(delay > 0);Preconditions.checkArgument(registry != null);journal = JournalBuilder.of(new File(journalDir)).setPhysicalSync(true).setMaxFileLength(maxFileLength).setMaxWriteBatchSize(maxFileLength).open();this.readTimer = registry.timer(name(EmailJournal.class, "readTimer"));this.writeTimer = registry.timer(name(EmailJournal.class, "writeTimer"));this.compactionTimer = registry.timer(name(EmailJournal.class, "compactionTimer"));this.delay = delay;}public EmailJournal(String journalDir, MetricRegistry registry) throws IOException {this(journalDir, DEFAULT_FILE_LENGTH, DEFAULT_DELAY, registry);}@Overridepublic String write(InputStream stream) {Preconditions.checkArgument(stream != null);try (Timer.Context ignored = writeTimer.time()) {byte[] data = ByteStreams.toByteArray(stream);Location location = journal.write(data, Journal.WriteType.SYNC);String id = UUID.randomUUID().toString();idToLocationMap.put(id, location);return id;} catch (Throwable t) {Throwables.propagate(t);}return null;}@Overridepublic void delete(String key) {Preconditions.checkArgument(key != null);try {Location location = idToLocationMap.get(key);Preconditions.checkState(location != null);journal.delete(location);idToLocationMap.remove(key);} catch (IOException e) {Throwables.propagate(e);}}@Overridepublic InputStream read(String key) {Preconditions.checkArgument(key != null);try (Timer.Context ignored = readTimer.time()) {Location location = idToLocationMap.get(key);byte[] data = journal.read(location, Journal.ReadType.SYNC);return new ByteArrayInputStream(data);} catch (IOException e) {Throwables.propagate(e);}return null;}@Overridepublic Map<String, InputStream> redo() {Map<String, InputStream> redoEmails = new HashMap<>();try {for (Location location : journal.redo()) {String id = UUID.randomUUID().toString();idToLocationMap.put(id, location);InputStream is = read(id);redoEmails.put(id, is);}} catch (Throwable t) {Throwables.propagate(t);}return redoEmails;}@PreDestroyprotected void close() throws IOException {logger.log(Level.INFO, "Closing journal.");journal.compact();journal.close();}@Overridepublic void start() throws Exception {journalCompactor.scheduleWithFixedDelay(new JournalCompactTask(), delay, delay, TimeUnit.SECONDS);}@Overridepublic void stop() throws Exception {journalCompactor.shutdownNow();}private class JournalCompactTask implements Runnable {@Overridepublic void run() {try (Timer.Context ignored = compactionTimer.time()) {journal.compact();logger.log(Level.FINE, "Done compacting journal");} catch (IOException e) {logger.log(Level.WARNING, "Error compacting journal {0}.", Throwables.propagate(e));}}}
I am not sure if its the same problem, this exception happens in the middle of the journal file, meaning there are more records after the record where the exception happens and the exception thrown is java.lang.NegativeArraySizeException.
When creating the journal I set physicalSync to true and every write with ReadSync.SYNC parameter to make sure that the record has been written to disk, as we need recovery guarantees if our server crashes. So this makes me wonder why a record in the middle of the journal could be corrupt or missing.
ThanksÂ