Initially all peers are responsible for everything, or at least they think they are. If figure fig:pgridconnect describes a set of hosts that are all initially responsible for everything and the order of communication is determined by the numbered arrows. Table tbl:pgridconnect then shows how the prefixes and reference table that each host is responsible for could change during a sequence of exchanges.
The exchange algorithm used to distribute responsibilities between two peers 34#34 and 35#35 is shown in figure fig:pgridexchange. It is quite complicated, but simulations have shown that it reaches a stable state in about the same time as the Freenet information sharing system, as presented in [ACMD$^+$02] and [AHP03]. See section sec:freenet or [FNP03] and [CMH$^+$02] for more details on Freenet.
The algorithm presented here assumes that 34#34 initiates the exchange. The algorithm presented here is a reworked version of the algorithm that closer matches the way it would be implemented (in most cases). For details on the original formulations of the algorithm see [Abe02], [Abe01], [APHS02] or [ACMD$^+$02]. All of these sources present slightly different versions of the algorithm, which makes it a little unclear exactly how the algorithm should be formulated.
exchange(p1, p2) {
master = p1
slave = p2
// Make sure p2 has the longest key
if (length(p1.key) > length(p2.key))
swap(p1, p2)
common = length(common_prefix(p1.key, p2.key))
l1 = length(p1.key) - common
l2 = length(p2.key) - common
// Exchange references at common level
if (common > 0)
xchg_refs(p1, p2, common)
if (l1 == 0 && l2 == 0)
// Case 1: Extend both keys
if (MYSELF == master)
b = randombit()
master.key += b
sendbit(slave, 1 - b)
REFS(common + 1) = {slave}
else
slave.key += recvbit(master)
slave.refs(common + 1) = {master}
else if (l1 == 0 && l2 > 0)
// Case 2: Extend p1.key, which is shorter
if (MYSELF == p1)
p1.key += 1 - bit(p2.key, common + 1)
REFS(common + 1) = {p2}
else if (l1 > 0 && l2 > 0)
// Case 3: Exchange data and tell p2 to do another exchange
xchg_data(p1, p2)
if (MYSELF == p1)
p3 = recvpeer(p2)
connect(p3)
exchange(p1, p3)
else
sendpeer(p1, REFS(common + 1))
}
|
The algorithm, as it is described in figure fig:pgridexchange, does not converge to a stable state rapidly enough. By adding a threshold on the minimum number of elements stored in order to extend the key by one bit and a threshold on the number of recursive calls allowed the algorithm reaches a stable state faster. For further performance related details see chapter 6.