private void doUpdate()

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");
        }
    }