in common/src/main/java/org/mvndaemon/mvnd/common/DaemonRegistry.java [182:306]
private void doUpdate(Runnable updater) {
if (!Files.isReadable(registryFile)) {
throw new DaemonException("Registry became unaccessible");
}
synchronized (lck) {
final long deadline = System.currentTimeMillis() + LOCK_TIMEOUT_MS;
while (System.currentTimeMillis() < deadline) {
try (FileLock l = tryLock()) {
BufferCaster.cast(buffer).position(0);
infosMap.clear();
int nb = buffer.getInt();
for (int i = 0; i < nb; i++) {
String daemonId = readString();
String javaHome = readString();
String mavenHome = readString();
int pid = buffer.getInt();
String address = readString();
byte[] token = new byte[DaemonInfo.TOKEN_SIZE];
buffer.get(token);
String locale = readString();
List<String> opts = new ArrayList<>();
int nbOpts = buffer.getInt();
for (int j = 0; j < nbOpts; j++) {
opts.add(readString());
}
DaemonState state = DaemonState.values()[buffer.get()];
long lastIdle = buffer.getLong();
long lastBusy = buffer.getLong();
DaemonInfo di = new DaemonInfo(
daemonId, javaHome, mavenHome, pid, address, token, locale, opts, state, lastIdle,
lastBusy);
infosMap.putIfAbsent(di.getId(), di);
}
stopEvents.clear();
nb = buffer.getInt();
for (int i = 0; i < nb; i++) {
String daemonId = readString();
long date = buffer.getLong();
int ord = buffer.get();
DaemonExpirationStatus des = ord >= 0 ? DaemonExpirationStatus.values()[ord] : null;
String reason = readString();
DaemonStopEvent se = new DaemonStopEvent(daemonId, date, des, reason);
stopEvents.add(se);
}
if (updater != null) {
updater.run();
BufferCaster.cast(buffer).position((int) 0);
buffer.putInt(infosMap.size());
for (DaemonInfo di : infosMap.values()) {
writeString(di.getId());
writeString(di.getJavaHome());
writeString(di.getMvndHome());
buffer.putInt(di.getPid());
writeString(di.getAddress());
buffer.put(di.getToken());
writeString(di.getLocale());
buffer.putInt(di.getOptions().size());
for (String opt : di.getOptions()) {
writeString(opt);
}
buffer.put((byte) di.getState().ordinal());
buffer.putLong(di.getLastIdle());
buffer.putLong(di.getLastBusy());
}
buffer.putInt(stopEvents.size());
for (DaemonStopEvent dse : stopEvents) {
writeString(dse.getDaemonId());
buffer.putLong(dse.getTimestamp());
buffer.put((byte)
(dse.getStatus() == null
? -1
: dse.getStatus().ordinal()));
writeString(dse.getReason());
}
}
if (buffer.remaining() >= buffer.position() * 2) {
long ns = nextPowerOf2(buffer.position(), MAX_LENGTH);
if (ns != size) {
size = ns;
LOGGER.info("Resizing registry to {} kb due to buffer underflow", (size / 1024));
l.release();
BufferHelper.closeDirectByteBuffer(buffer, LOGGER::debug);
// let the garbage collector invalidate the mapped byte buffer
// because it could be still valid when trying to truncate the file
buffer = null;
System.gc();
channel.truncate(size);
try {
buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, size);
} catch (IOException ex) {
throw new DaemonException("Could not resize registry " + registryFile, ex);
}
}
}
return;
} catch (BufferOverflowException e) {
size <<= 1;
LOGGER.info("Resizing registry to {} kb due to buffer overflow", (size / 1024));
try {
buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, size);
} catch (IOException ex) {
ex.addSuppressed(e);
throw new DaemonException("Could not resize registry " + registryFile, ex);
}
} catch (IOException e) {
throw new DaemonException(
"Exception while " + (updater != null ? "updating " : "reading ") + registryFile, e);
} catch (IllegalStateException | ArrayIndexOutOfBoundsException | BufferUnderflowException e) {
String absPath = registryFile.toAbsolutePath().normalize().toString();
LOGGER.warn(
"Invalid daemon registry info, trying to recover from this issue. "
+ "If you keep getting this warning, try deleting the `registry.bin` file at [{}]",
absPath,
e);
this.reset();
return;
}
}
throw new RuntimeException("Could not lock " + registryFile + " within " + LOCK_TIMEOUT_MS + " ms");
}
}