/** * This method is the main function of the thread of the collective. It does housekeeping and * regularly talks to peers to exchange information. It can be stopped by calling <code>close() * </code>. * * @see #close() */ public final void run() { while (shouldLive) { // try{ System.gc(); removeOldStuff(); if (!refresh()) { Address[] a = observer.getPeerAddresses(); if (a != null) synchronized (cache) { for (int i = 0; i < a.length; ++i) cache.put(a[i].name, new ContributionBox(a[i], null)); } } for (int i = 0; i < REFRESHRATE; i += 1000) { try { Thread.sleep(1000); } catch (InterruptedException e) { shouldLive = false; } if (shouldLive == false) break; Thread.yield(); } /*} catch( RuntimeException e ) { Logger.error( "Collective#run()", "Runtime exception caught, something is going wrong",e); }*/ } cache = null; observer = null; }
/** * Handles a message. Knows type "collectiveUpdate-"+name only. It is the responsibility of the * owner to propagate messages of this type using this method. */ public boolean handleMessage(Message m, Object o) { if (!shouldLive || !m.getType().equals("collectiveUpdate-" + name)) return false; final String logSender = observer + "#collectiveUpdate"; Logger.debug(logSender, "Update from " + m.getSender()); /**/ if (!m.getRecipient().name.equals(contributor.getName())) Logger.warning( logSender, "Recipient and my contributor are not the same:\n" + "Recipient: " + m.getRecipient().name + "\n" + "Contributor: " + contributor.getName(), null); /**/ Collective c = (Collective) o; // --- reset array representations cacheCollection = null; commandCollection = null; // --- remove possible garbage cache.remove(m.getRecipient().name); c.cache.remove(m.getRecipient().name); cache.remove(m.getSender().name); c.cache.remove(m.getSender().name); // --- sending our contributions if (contributor == null) Logger.warning(logSender, "Non-contributor observer is known by " + m.getSender(), null); updateLocalInfo(); m.setReply(this); // --- update containers repairSenderAddress(c, m.getSender()); merge(c); observer.collectiveUpdated((ContributionBox) cache.get(m.getSender().name)); return true; }
/** * Initiates an information exchange with a known and living other base if such a base exists. * * @return true if refresh was succesful, false otherwise. */ private boolean refresh() { final String logSender = observer + "#refresh"; final String contrName = ((contributor != null) ? contributor.getName() : null); // --- refreshing local contribution and commands updateLocalInfo(); // --- creating a random permutation of peers Vector peers = null; synchronized (cache) { peers = new Vector(cache.values()); // just to be sure, shouldn't be there anyway if (contrName != null) peers.remove(cache.get(contrName)); } Collections.shuffle(peers); if (peers.isEmpty()) { Logger.debug(logSender, "no peers in cache"); return false; } // --- reset array representations cacheCollection = null; commandCollection = null; // --- trying to talk to random peer IRequest answer = null; Address peer = null; for (int i = 0; i < peers.size(); ++i) { if (!shouldLive) return false; peer = ((ContributionBox) peers.get(i)).contributor; Logger.debug(logSender, "asking " + peer); answer = observer.fireMessage(peer, "collectiveUpdate-" + name, this); while (answer.getStatus() == IRequest.WAITING) { try { Thread.sleep(100); } catch (Exception e) { } } if (answer.getStatus() == IRequest.DONE) break; Logger.debug(logSender, "not accessable: " + peer); } if (answer.getStatus() != IRequest.DONE) { Logger.debug(logSender, "no accessable peers"); observer.collectiveUpdated(null); return false; } else { Collective c = (Collective) answer.getInfo("reply"); // --- remove possible garbage if (contributor != null) { cache.remove(contributor.getName()); c.cache.remove(contributor.getName()); } cache.remove(peer.name); c.cache.remove(peer.name); repairSenderAddress(c, peer); merge(c); observer.collectiveUpdated((ContributionBox) cache.get(c.myContribution.contributor.name)); return true; } }