1/*
2 * Copyright 2010, Haiku.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Clemens Zeidler <haiku@clemens-zeidler.de>
7 */
8
9#include "CatchUpManager.h"
10
11#include <vector>
12
13#include <Debug.h>
14#include <Query.h>
15
16#include "IndexServer.h"
17
18
19const uint32 kCatchUp = '&CaU';
20const uint32 kCatchUpDone = '&CUD';
21
22const bigtime_t kSecond = 1000000;
23
24
25CatchUpAnalyser::CatchUpAnalyser(const BVolume& volume, time_t start,
26	time_t end, BHandler* manager)
27	:
28	AnalyserDispatcher("CatchUpAnalyser"),
29
30	fVolume(volume),
31	fStart(start),
32	fEnd(end),
33	fCatchUpManager(manager)
34{
35
36}
37
38
39void
40CatchUpAnalyser::MessageReceived(BMessage *message)
41{
42	switch (message->what) {
43		case kCatchUp:
44			_CatchUp();
45		break;
46
47		default:
48			BLooper::MessageReceived(message);
49	}
50}
51
52
53void
54CatchUpAnalyser::StartAnalysing()
55{
56	PostMessage(kCatchUp);
57	Run();
58}
59
60
61void
62CatchUpAnalyser::AnalyseEntry(const entry_ref& ref)
63{
64	for (int i = 0; i < fFileAnalyserList.CountItems(); i++) {
65		FileAnalyser* analyser = fFileAnalyserList.ItemAt(i);
66		const analyser_settings& settings = analyser->CachedSettings();
67		if (settings.syncPosition / kSecond >= fStart
68			&& settings.watchingStart / kSecond <= fEnd)
69			analyser->AnalyseEntry(ref);
70	}
71}
72
73
74void
75CatchUpAnalyser::_CatchUp()
76{
77	STRACE("_CatchUp start %i, end %i\n", (int)fStart, (int)fEnd);
78	for (int i = 0; i < fFileAnalyserList.CountItems(); i++)
79		STRACE("- Analyser %s\n", fFileAnalyserList.ItemAt(i)->Name().String());
80
81	BQuery query;
82	query.SetVolume(&fVolume);
83	query.PushAttr("last_modified");
84	query.PushInt32(fStart);
85	query.PushOp(B_GE);
86	query.PushAttr("last_modified");
87	query.PushInt32(fEnd);
88	query.PushOp(B_LE);
89	query.PushOp(B_AND);
90
91	query.Fetch();
92
93	std::vector<entry_ref> entryList;
94	entry_ref ref;
95	while (query.GetNextRef(&ref) == B_OK)
96		entryList.push_back(ref);
97
98	printf("CatchUpAnalyser:: entryList.size() %i\n", (int)entryList.size());
99
100	if (entryList.size() == 0)
101		return;
102
103	for (uint32 i = 0; i < entryList.size(); i++) {
104		if (Stopped())
105			return;
106		if (i % 100 == 0)
107			printf("Catch up: %i/%i\n", (int)i,(int)entryList.size());
108		AnalyseEntry(entryList[i]);
109	}
110	LastEntry();
111
112	_WriteSyncSatus(fEnd * kSecond);
113	printf("Catched up.\n");
114
115	BMessenger managerMessenger(fCatchUpManager);
116	BMessage msg(kCatchUpDone);
117	msg.AddPointer("Analyser", this);
118	managerMessenger.SendMessage(&msg);
119}
120
121
122void
123CatchUpAnalyser::_WriteSyncSatus(bigtime_t syncTime)
124{
125	for (int i = 0; i < fFileAnalyserList.CountItems(); i++) {
126		AnalyserSettings* settings = fFileAnalyserList.ItemAt(i)->Settings();
127		ASSERT(settings);
128		settings->SetSyncPosition(syncTime);
129		settings->WriteSettings();
130	}
131
132}
133
134
135CatchUpManager::CatchUpManager(const BVolume& volume)
136	:
137	fVolume(volume)
138{
139
140}
141
142
143CatchUpManager::~CatchUpManager()
144{
145	Stop();
146
147	for (int i = 0; i < fFileAnalyserQueue.CountItems(); i++)
148		delete fFileAnalyserQueue.ItemAt(i);
149}
150
151
152void
153CatchUpManager::MessageReceived(BMessage *message)
154{
155	CatchUpAnalyser* analyser;
156	switch (message->what) {
157		case kCatchUpDone:
158			message->AddPointer("Analyser", &analyser);
159			fCatchUpAnalyserList.RemoveItem(analyser);
160			analyser->PostMessage(B_QUIT_REQUESTED);
161		break;
162
163		default:
164			BHandler::MessageReceived(message);
165	}
166}
167
168
169bool
170CatchUpManager::AddAnalyser(const FileAnalyser* analyserOrg)
171{
172	IndexServer* server = (IndexServer*)be_app;
173	FileAnalyser* analyser = server->CreateFileAnalyser(analyserOrg->Name(),
174		fVolume);
175	if (!analyser)
176		return false;
177	ASSERT(analyserOrg->Settings());
178	analyser->SetSettings(analyserOrg->Settings());
179
180	bool status = fFileAnalyserQueue.AddItem(analyser);
181	if (!status)
182		delete analyser;
183	return status;
184}
185
186
187void
188CatchUpManager::RemoveAnalyser(const BString& name)
189{
190	for (int i = 0; i < fFileAnalyserQueue.CountItems(); i++) {
191		FileAnalyser* analyser = fFileAnalyserQueue.ItemAt(i);
192		if (analyser->Name() == name) {
193			fFileAnalyserQueue.RemoveItem(analyser);
194			delete analyser;
195		}
196	}
197
198	for (int i = 0; i < fCatchUpAnalyserList.CountItems(); i++)
199		fCatchUpAnalyserList.ItemAt(i)->RemoveAnalyser(name);
200}
201
202
203bool
204CatchUpManager::CatchUp()
205{
206	STRACE("CatchUpManager::CatchUp()\n");
207	bigtime_t startBig = real_time_clock_usecs();
208	bigtime_t endBig = 0;
209	for (int i = 0; i < fFileAnalyserQueue.CountItems(); i++) {
210		FileAnalyser* analyser = fFileAnalyserQueue.ItemAt(i);
211 		analyser->UpdateSettingsCache();
212		const analyser_settings& settings = analyser->CachedSettings();
213		STRACE("%s, %i, %i\n", analyser->Name().String(),
214			  (int)settings.syncPosition, (int)settings.watchingStart);
215		if (settings.syncPosition < startBig)
216			startBig = settings.syncPosition;
217		if (settings.watchingStart > endBig)
218			endBig = settings.watchingStart;
219	}
220
221	CatchUpAnalyser* catchUpAnalyser = new CatchUpAnalyser(fVolume,
222		startBig / kSecond, endBig / kSecond, this);
223	if (!catchUpAnalyser)
224		return false;
225	if (!fCatchUpAnalyserList.AddItem(catchUpAnalyser)) {
226		delete catchUpAnalyser;
227		return false;
228	}
229
230	for (int i = 0; i < fFileAnalyserQueue.CountItems(); i++) {
231		FileAnalyser* analyser = fFileAnalyserQueue.ItemAt(i);
232		// if AddAnalyser fails at least don't leak
233		if (!catchUpAnalyser->AddAnalyser(analyser))
234			delete analyser;
235
236	}
237	fFileAnalyserQueue.MakeEmpty();
238
239	catchUpAnalyser->StartAnalysing();
240	return true;
241}
242
243
244void
245CatchUpManager::Stop()
246{
247	for (int i = 0; i < fCatchUpAnalyserList.CountItems(); i++) {
248		CatchUpAnalyser* catchUpAnalyser = fCatchUpAnalyserList.ItemAt(i);
249		catchUpAnalyser->Stop();
250		catchUpAnalyser->PostMessage(B_QUIT_REQUESTED);
251	}
252	fCatchUpAnalyserList.MakeEmpty();
253}
254