| | |
| | | private final ConcurrentMap<Integer, CSN> serverIdToCSN = new ConcurrentSkipListMap<>(); |
| | | /** |
| | | * Whether the state has been saved to persistent storage. It starts at true, |
| | | * and moves to false when an update is made to the current object. |
| | | * and moves to false when a change is actually made to the current object - |
| | | * once that change is visible in {@link #serverIdToCSN}, never before, so |
| | | * that a reader cannot see the flag cleared for a change its own view of the |
| | | * map does not hold yet. |
| | | */ |
| | | private volatile boolean saved = true; |
| | | |
| | |
| | | |
| | | /** |
| | | * Empty the ServerState. |
| | | * After this call the Server State will be in the same state |
| | | * as if it was just created. |
| | | * After this call the Server State no longer holds any CSN. A state which |
| | | * held one is marked as not saved: dropping it is a change like any other, |
| | | * which persistent storage has yet to be told about. A state which held |
| | | * nothing is left alone, the way an update which changes nothing is. |
| | | */ |
| | | public void clear() |
| | | { |
| | | serverIdToCSN.clear(); |
| | | if (!serverIdToCSN.isEmpty()) |
| | | { |
| | | serverIdToCSN.clear(); |
| | | saved = false; |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | return false; |
| | | } |
| | | |
| | | saved = false; |
| | | |
| | | final int serverId = csn.getServerId(); |
| | | while (true) |
| | | { |
| | |
| | | { |
| | | if (serverIdToCSN.putIfAbsent(serverId, csn) == null) |
| | | { |
| | | saved = false; |
| | | return true; |
| | | } |
| | | // oops, a concurrent modification happened, run the same process again |
| | |
| | | { |
| | | if (serverIdToCSN.replace(serverId, existingCSN, csn)) |
| | | { |
| | | saved = false; |
| | | return true; |
| | | } |
| | | // oops, a concurrent modification happened, run the same process again |