public void processResult(int code, String path, Object context, byte[] rawData, Stat stat) {
            String data = rawData == null ? null : new String(rawData, StandardCharsets.UTF_8);
            log.log(Level.INFO, "Fleetcontroller " + nodeIndex + ": Got vote data from path " + path +
                    " with code " + code + " and data " + data);

            int index = getIndex(path);
            synchronized (nextMasterData) {
                if (code != KeeperException.Code.OK.intValue()) {
                    if (code == KeeperException.Code.NONODE.intValue()) {
                        log.log(Level.INFO, "Fleetcontroller " + nodeIndex + ": Node at " + path +
                                " removed, got no other option than counting it as down.");
                    } else {
                        log.log(Level.WARNING, "Fleetcontroller " + nodeIndex + ": Failure code " + code +
                                " when listening to node at " + path + ", will assume it's down.");
                    }
                    if (nextMasterData.containsKey(index)) {
                        nextMasterData.remove(index);
                    } else {
                        // May happen when pending data watch error callbacks are triggered concurrently with
                        // internal voting state having already been cleared due to connectivity issues.
                        log.log(Level.INFO, String.format("Fleetcontroller %d: ignoring removal of vote from node %d " +
                                "since it was not present in existing vote mapping", nodeIndex, index));
                    }
                } else {
                    Integer value = Integer.valueOf(data);
                    if (nextMasterData.containsKey(index)) {
                        if (value.equals(nextMasterData.get(index))) {
                            log.log(Level.FINE, () -> "Fleetcontroller " + nodeIndex + ": Got vote from fleetcontroller " + index + ", which already was " + value + ".");
                        } else {
                            log.log(Level.INFO, "Fleetcontroller " + nodeIndex + ": Got vote from fleetcontroller " + index + ". Altering vote from " + nextMasterData.get(index) + " to " + value + ".");
                            nextMasterData.put(index, value);
                        }
                    } else {
                        log.log(Level.WARNING, "Fleetcontroller " + nodeIndex + ": Got vote from fleetcontroller " + index + " which is not alive according to current state. Ignoring it");
                    }
                }
                for(Integer vote : nextMasterData.values()) {
                    if (vote == null) {
                        log.log(Level.FINEST, () -> "Fleetcontroller " + nodeIndex + ": Still not received votes from all fleet controllers. Awaiting more responses.");
                        return;
                    }
                }
            }
            log.log(Level.FINE, () -> "Fleetcontroller " + nodeIndex + ": Got votes for all fleetcontrollers. Sending event with new fleet data for update");
            cycleCompleted();
        }
The node data callback class is responsible for fetching new votes from fleetcontrollers that have altered their vote.
clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/MasterDataGatherer.java