Whenever a new node joins, three invariants should be maintained (the first two ensure correctness and the last one keeps querying fast):
Each node's successor points to its immediate successor correctly.
Each key is stored in {displaystyle successor(k)} successor(k).
Each node's finger table should be correct.
To satisfy these invariants, a predecessor field is maintained for each node. As the successor is the first entry of the finger table, we do not need to maintain this field separately any more. The following tasks should be done for a newly joined node {displaystyle n} n:
Initialize node {displaystyle n} n (the predecessor and the finger table).
Notify other nodes to update their predecessors and finger tables.
The new node takes over its responsible keys from its successor.
The predecessor of {displaystyle n} n can be easily obtained from the predecessor of {displaystyle successor(n)} successor(n) (in the previous circle). As for its finger table, there are various initialization methods. The simplest one is to execute find successor queries for all {displaystyle m} m entries, resulting in {displaystyle O(Mlog N)} O(Mlog N) initialization time. A better method is to check whether {displaystyle i^{th}} i^{th} entry in the finger table is still correct for the {displaystyle (i+1)^{th}} (i+1)^{th} entry. This will lead to {displaystyle O(log ^{2}N)} O(log^2 N). The best method is to initialize the finger table from its immediate neighbours and make some updates, which is {displaystyle O(log N)} O(log N).