* @return The next update that must be sent to the consumer.
* null when synchronous is false and queue is empty.
*/
protected UpdateMsg getnextMessage(boolean synchronous)
{
UpdateMsg msg;
while (activeConsumer == true)
{
if (following == false)
{
/* this server is late with regard to some other masters
* in the topology or just joined the topology.
* In such cases, we can't keep all changes in the queue
* without saturating the memory, we therefore use
* a lateQueue that is filled with a few changes from the changelogDB
* If this server is able to close the gap, it will start using again
* the regular msgQueue later.
*/
if (lateQueue.isEmpty())
{
/*
* Start from the server State
* Loop until the queue high mark or until no more changes
* for each known LDAP master
* get the next CSN after this last one :
* - try to get next from the file
* - if not found in the file
* - try to get the next from the queue
* select the smallest of changes
* check if it is in the memory tree
* yes : lock memory tree.
* check all changes from the list, remove the ones that
* are already sent
* unlock memory tree
* restart as usual
* load this change on the delayList
*
*/
ReplicationIteratorComparator comparator =
new ReplicationIteratorComparator();
SortedSet<ReplicationIterator> iteratorSortedSet =
new TreeSet<ReplicationIterator>(comparator);
/* fill the lateQueue */
for (int serverId : replicationServerDomain.getServers())
{
ChangeNumber lastCsn = serverState.getMaxChangeNumber(serverId);
ReplicationIterator iterator =
replicationServerDomain.getChangelogIterator(serverId, lastCsn);
if (iterator != null)
{
if (iterator.getChange() != null)
{
iteratorSortedSet.add(iterator);
} else
{
iterator.releaseCursor();
}
}
}
// The loop below relies on the fact that it is sorted based
// on the currentChange of each iterator to consider the next
// change across all servers.
// Hence it is necessary to remove and eventual add again an iterator
// when looping in order to keep consistent the order of the
// iterators (see ReplicationIteratorComparator.
while (!iteratorSortedSet.isEmpty() &&
(lateQueue.count()<100) &&
(lateQueue.bytesCount()<50000) )
{
ReplicationIterator iterator = iteratorSortedSet.first();
iteratorSortedSet.remove(iterator);
lateQueue.add(iterator.getChange());
if (iterator.next())
iteratorSortedSet.add(iterator);
else
iterator.releaseCursor();
}
for (ReplicationIterator iterator : iteratorSortedSet)
{
iterator.releaseCursor();
}
/*
* If the late queue is empty then we could not find any
* messages in the replication log so the remote serevr is not
* late anymore.
*/
if (lateQueue.isEmpty())
{
synchronized (msgQueue)
{
if ((msgQueue.count() < maxQueueSize) &&
(msgQueue.bytesCount() < maxQueueBytesSize))
{
setFollowing(true);
}
}
} else
{
/*
* if the first change in the lateQueue is also on the regular
* queue, we can resume the processing from the regular queue
* -> set following to true and empty the lateQueue.
*/
msg = lateQueue.first();
synchronized (msgQueue)
{
if (msgQueue.contains(msg))
{
/* we finally catch up with the regular queue */
setFollowing(true);
lateQueue.clear();
UpdateMsg msg1;
do
{
msg1 = msgQueue.removeFirst();
} while (!msg.getChangeNumber().equals(msg1.getChangeNumber()));
this.updateServerState(msg);
return msg1;
}
}
}