Exemple #1
0
bool ZTSoup::Sync()
	{
	ZMutexLocker locker_CallSync(fMutex_CallSync);
	ZMutexLocker locker_Structure(fMutex_Structure);

	ZMutexLocker locker_TSWatcher(fMutex_TSWatcher);
	ZRef<ZTSWatcher> theTSWatcher = fTSWatcher;
	if (!theTSWatcher)
		return false;
	locker_TSWatcher.Release();

	if (ZLOG(s, eDebug + 1, "ZTSoup"))
		s << "Sync start";

	fCalled_SyncNeeded = false;

	vector<uint64> removedIDs, addedIDs;

	// We put written tuples into a map, so that they can
	// be extracted in sorted order, required by ZTSWatcher::Sync.
	map<uint64, ZTuple> writtenTupleMap;

	if (sNotEmpty(fPCroutons_Sync))
		{
		removedIDs.reserve(fPCroutons_Sync.Size());
		addedIDs.reserve(fPCroutons_Sync.Size());
		for (DListEraser<PCrouton, DLink_PCrouton_Sync> iter = fPCroutons_Sync;
			iter; iter.Advance())
			{
			PCrouton* thePCrouton = iter.Current();

			if (thePCrouton->fHasValue_ForWatcher)
				{
				thePCrouton->fHasValue_ForWatcher = false;
				writtenTupleMap.insert(
					pair<uint64, ZTuple>(thePCrouton->fID, thePCrouton->fValue_ForWatcher));

				if (!thePCrouton->fWatcherKnown)
					{
					thePCrouton->fWatcherKnown = true;
					addedIDs.push_back(thePCrouton->fID);
					}

				// Put it on fPCroutons_Syncing, which will be transcribed
				// to fCroutons_Pending after we've called our watcher.
				sQInsertBack(fPCroutons_Syncing, thePCrouton);
				}
			else if (thePCrouton->fTCroutons_Using)
				{
				// It's in use.
				if (!thePCrouton->fWatcherKnown)
					{
					// But not known to the watcher.
					thePCrouton->fWatcherKnown = true;
					addedIDs.push_back(thePCrouton->fID);
					}
				}
			else if (thePCrouton->fWatcherKnown)
				{
				// It's not in use, and is known to the watcher.
				thePCrouton->fWatcherKnown = false;
				removedIDs.push_back(thePCrouton->fID);
				thePCrouton->fHasValue = false;
				sQInsertBack(fPCroutons_Update, thePCrouton);
				}
			else
				{
				// It's not in use, and not known to the watcher, so it should have
				// been pulled from the sync list by update and deleted.
#if 0 //##
				if (ZLOG(s, eNotice, "ZTSoup"))
					{
					s << "Got a PCrouton on the sync list that maybe shouldn't be there: "
						<< " On update list? "
						<< (static_cast<DLink_PCrouton_Update*>(thePCrouton)->fNext
							? "yes " : "no ")
						<< sStringf("%llX: ", thePCrouton->fID)
						<< thePCrouton->fValue;
					}
#endif
				}
			}
		}

	vector<int64> removedQueries;
	vector<ZTSWatcher::AddedQueryCombo> addedQueries;

	for (DListEraser<PSieve, DLink_PSieve_Sync> iter = fPSieves_Sync;
		iter; iter.Advance())
		{
		PSieve* thePSieve = iter.Current();

		if (thePSieve->fTSieves_Using)
			{
			// It's in use.
			if (!thePSieve->fWatcherKnown)
				{
				// But not known to the watcher.
				thePSieve->fWatcherKnown = true;

				ZTSWatcher::AddedQueryCombo theCombo;
				theCombo.fRefcon = reinterpret_cast<int64>(thePSieve);
				theCombo.fTBQuery = thePSieve->fTBQuery;
				theCombo.fPrefetch = thePSieve->fPrefetch;
				addedQueries.push_back(theCombo);
				}
			}
		else if (thePSieve->fWatcherKnown)
			{
			// It's not in use, and is known to the watcher.
			thePSieve->fWatcherKnown = false;
			thePSieve->fHasResults = false;
			removedQueries.push_back(reinterpret_cast<int64>(thePSieve));
			sQInsertBack(fPSieves_Update, thePSieve);
			}
		else
			{
			// Shouldn't still be on the sync list if it's not in use and not known to the watcher
#if 0 //##
			if (ZLOG(s, eNotice, "ZTSoup"))
				{
				s << "Got a PSieve on the sync list that maybe shouldn't be there: "
					<< " On update list? "
					<< (static_cast<DLink_PSieve_Update*>(thePSieve)->fNext ? "yes " : "no ")
					<< sStringf("ID: %llX, value: ", reinterpret_cast<int64>(thePSieve))
					<< thePSieve->fTBQuery.AsTuple();
				}
#endif
			}
		}

	if (ZLOG(s, eDebug + 1, "ZTSoup"))
		s << "Sync releasing lock";
	locker_Structure.Release();

	vector<uint64> writtenTupleIDs;
	vector<ZTuple> writtenTuples;
	writtenTupleIDs.reserve(writtenTupleMap.size());
	writtenTuples.reserve(writtenTupleMap.size());
	for (map<uint64, ZTuple>::const_iterator i = writtenTupleMap.begin();
		i != writtenTupleMap.end(); ++i)
		{
		writtenTupleIDs.push_back(i->first);
		writtenTuples.push_back(i->second);
		}

	vector<uint64> watcherAddedIDs;
	vector<uint64> changedTupleIDs;
	vector<ZTuple> changedTuples;
	map<int64, vector<uint64> > changedQueries;

	if (!theTSWatcher->Sync(
		sFirstOrNil(removedIDs), removedIDs.size(),
		sFirstOrNil(addedIDs), addedIDs.size(),
		sFirstOrNil(removedQueries), removedQueries.size(),
		sFirstOrNil(addedQueries), addedQueries.size(),
		watcherAddedIDs,
		changedTupleIDs, changedTuples,
		sFirstOrNil(writtenTupleIDs), sFirstOrNil(writtenTuples), writtenTupleIDs.size(),
		changedQueries))
		{
		// Possibly should move fPCroutons_Syncing stuff onto fPCroutons_Pending.
		// Might allow destructor to execute without needing explicit Purge.
		locker_TSWatcher.Acquire();
		fTSWatcher.Clear();
		return false;
		}

	locker_Structure.Acquire();

	if (ZLOG(s, eDebug + 1, "ZTSoup"))
		s << "Sync acquired lock";


	for (vector<uint64>::iterator iterWatcherAddedIDs = watcherAddedIDs.begin(),
		theEnd = watcherAddedIDs.end();
		iterWatcherAddedIDs != theEnd; ++iterWatcherAddedIDs)
		{
		PCrouton* thePCrouton = this->pGetPCrouton(*iterWatcherAddedIDs);
		ZAssertStop(ZTSoup::kDebug, !thePCrouton->fWatcherKnown);
		thePCrouton->fWatcherKnown = true;
		// Stick it on the pending list, so it will last past
		// the end of the next update.
		sQInsertBack(fPCroutons_Pending, thePCrouton);
		}

	for (vector<uint64>::iterator iterChangedTuples = changedTupleIDs.begin(),
		theEnd = changedTupleIDs.end();
		iterChangedTuples != theEnd; ++iterChangedTuples)
		{
		map<uint64, PCrouton>::iterator iterPCrouton =
			fID_To_PCrouton.find(*iterChangedTuples);

		// We never toss a PCrouton that has not positively been unregistered.
		ZAssertStop(ZTSoup::kDebug, fID_To_PCrouton.end() != iterPCrouton);

		PCrouton* thePCrouton = &(*iterPCrouton).second;
		if (!thePCrouton->fWrittenLocally)
			{
			thePCrouton->fValue_FromWatcher =
				*(changedTuples.begin() + (iterChangedTuples - changedTupleIDs.begin()));

			sQInsertBack(fPCroutons_Changed, thePCrouton);
			}
		}

	for (map<int64, vector<uint64> >::iterator i = changedQueries.begin(),
		theEnd = changedQueries.end();
		i != theEnd; ++i)
		{
		PSieve* thePSieve = reinterpret_cast<PSieve*>((*i).first);
		thePSieve->fResults_Remote.swap((*i).second);
		sQInsertBack(fPSieves_Changed, thePSieve);
		}

	for (DListEraser<PCrouton, DLink_PCrouton_Syncing>
		iter = fPCroutons_Syncing;
		iter; iter.Advance())
		{
		sQInsertBack(fPCroutons_Pending, iter.Current());
		}

	locker_CallSync.Release();

	if (fPSieves_Update || fPSieves_Changed
		|| fPCroutons_Update || fPCroutons_Changed
		|| fPCroutons_Pending)
		{
		this->pTriggerUpdate();
		}

	if (ZLOG(s, eDebug + 1, "ZTSoup"))
		s << "Sync exit";

	return true;
	}