Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

539 lines
17 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. centctrl.cpp
  5. Abstract:
  6. SIS Groveler central controller
  7. Authors:
  8. John Douceur, 1998
  9. Environment:
  10. User Mode
  11. Revision History:
  12. --*/
  13. #include "all.hxx"
  14. const _TCHAR total_processor_time_path[] = _T("\\Processor(_Total#0)\\% Processor Time");
  15. CentralController::CentralController(
  16. int num_partitions,
  17. Groveler *grovelers,
  18. GrovelStatus *groveler_statuses,
  19. ReadParameters *read_parameters,
  20. WriteParameters *write_parameters,
  21. ReadDiskInformation **read_disk_info,
  22. WriteDiskInformation **write_disk_info,
  23. int *num_excluded_paths,
  24. const _TCHAR ***excluded_paths)
  25. : hash_match_ratio_filter(read_parameters->sis_efficacy_history_size,
  26. write_parameters->hash_match_ratio),
  27. compare_match_ratio_filter(read_parameters->sis_efficacy_history_size,
  28. write_parameters->compare_match_ratio),
  29. dequeue_hash_ratio_filter(read_parameters->log_winnow_history_size,
  30. write_parameters->dequeue_hash_ratio)
  31. {
  32. ASSERT(this != 0);
  33. unsigned int current_time = GET_TICK_COUNT();
  34. this->num_partitions = num_partitions;
  35. ASSERT(num_partitions > 0);
  36. this->grovelers = grovelers;
  37. ASSERT(grovelers != 0);
  38. base_grovel_interval = read_parameters->base_grovel_interval;
  39. ASSERT(base_grovel_interval > 0);
  40. max_grovel_interval = read_parameters->max_grovel_interval;
  41. ASSERT(max_grovel_interval > 0);
  42. ASSERT(max_grovel_interval >= base_grovel_interval);
  43. max_response_lag = read_parameters->max_response_lag;
  44. ASSERT(max_response_lag > 0);
  45. working_grovel_interval = read_parameters->working_grovel_interval;
  46. ASSERT(working_grovel_interval > 0);
  47. ASSERT(base_grovel_interval >= working_grovel_interval);
  48. grovel_duration = read_parameters->grovel_duration;
  49. ASSERT(grovel_duration > 0);
  50. ASSERT(grovel_duration <= base_grovel_interval);
  51. ASSERT(grovel_duration <= max_grovel_interval);
  52. ASSERT(grovel_duration <= working_grovel_interval);
  53. hash_match_ratio = &write_parameters->hash_match_ratio;
  54. ASSERT(hash_match_ratio != 0);
  55. ASSERT(*hash_match_ratio >= 0.0);
  56. ASSERT(*hash_match_ratio <= 1.0);
  57. compare_match_ratio = &write_parameters->compare_match_ratio;
  58. ASSERT(compare_match_ratio != 0);
  59. ASSERT(*compare_match_ratio >= 0.0);
  60. ASSERT(*compare_match_ratio <= 1.0);
  61. dequeue_hash_ratio = &write_parameters->dequeue_hash_ratio;
  62. ASSERT(dequeue_hash_ratio != 0);
  63. ASSERT(*dequeue_hash_ratio >= 0.0);
  64. ASSERT(*dequeue_hash_ratio <= 1.0);
  65. foreground_partition_index = 0;
  66. num_alive_partitions = 0;
  67. bool some_groveler_dead = false;
  68. //
  69. // Create the control structure for each partion
  70. //
  71. part_controllers = new PartitionController*[num_partitions];
  72. for (int index = 0; index < num_partitions; index++)
  73. {
  74. part_controllers[index] = new PartitionController(
  75. &grovelers[index],
  76. groveler_statuses[index],
  77. read_parameters->target_entries_per_extraction,
  78. read_parameters->max_extraction_interval,
  79. base_grovel_interval,
  80. max_grovel_interval,
  81. read_parameters->low_confidence_grovel_interval,
  82. read_parameters->low_disk_space_grovel_interval,
  83. read_parameters->partition_info_update_interval,
  84. read_parameters->base_restart_extraction_interval,
  85. read_parameters->max_restart_extraction_interval,
  86. read_parameters->base_restart_groveling_interval,
  87. read_parameters->max_restart_groveling_interval,
  88. read_parameters->base_regrovel_interval,
  89. read_parameters->max_regrovel_interval,
  90. read_parameters->volscan_regrovel_threshold,
  91. read_parameters->partition_balance_time_constant,
  92. read_parameters->read_time_increase_history_size,
  93. read_parameters->read_time_decrease_history_size,
  94. read_parameters->file_size_history_size,
  95. read_disk_info[index]->error_retry_log_extraction,
  96. read_disk_info[index]->error_retry_groveling,
  97. read_disk_info[index]->base_usn_log_size,
  98. read_disk_info[index]->max_usn_log_size,
  99. read_parameters->sample_group_size,
  100. read_parameters->acceptance_p_value,
  101. read_parameters->rejection_p_value,
  102. read_parameters->base_use_multiplier,
  103. read_parameters->max_use_multiplier,
  104. read_parameters->peak_finder_accuracy,
  105. read_parameters->peak_finder_range,
  106. read_parameters->base_cpu_load_threshold,
  107. read_parameters->max_cpu_load_threshold,
  108. hash_match_ratio,
  109. compare_match_ratio,
  110. dequeue_hash_ratio,
  111. &write_disk_info[index]->partition_hash_read_time_estimate,
  112. &write_disk_info[index]->partition_compare_read_time_estimate,
  113. &write_disk_info[index]->mean_file_size,
  114. &write_disk_info[index]->read_time_confidence,
  115. &write_disk_info[index]->volume_serial_number,
  116. index,
  117. read_parameters->read_report_discard_threshold,
  118. read_disk_info[index]->min_file_size,
  119. read_disk_info[index]->min_file_age,
  120. read_disk_info[index]->allow_compressed_files,
  121. read_disk_info[index]->allow_encrypted_files,
  122. read_disk_info[index]->allow_hidden_files,
  123. read_disk_info[index]->allow_offline_files,
  124. read_disk_info[index]->allow_temporary_files,
  125. num_excluded_paths[index],
  126. excluded_paths[index]);
  127. if (groveler_statuses[index] != Grovel_disable)
  128. {
  129. if (groveler_statuses[index] == Grovel_ok ||
  130. groveler_statuses[index] == Grovel_new ||
  131. read_disk_info[index]->error_retry_groveling)
  132. {
  133. num_alive_partitions++;
  134. }
  135. else
  136. {
  137. ASSERT(groveler_statuses[index] == Grovel_error);
  138. some_groveler_dead = true;
  139. }
  140. }
  141. }
  142. if (num_alive_partitions == 0)
  143. {
  144. if (some_groveler_dead)
  145. {
  146. eventlog.report_event(GROVMSG_ALL_GROVELERS_DEAD, 0);
  147. }
  148. else
  149. {
  150. eventlog.report_event(GROVMSG_ALL_GROVELERS_DISABLED, 0);
  151. }
  152. return;
  153. }
  154. cpu_load_determinable = false;
  155. PDH_STATUS status = PdhOpenQuery(0, 0, &qhandle);
  156. if (status == ERROR_SUCCESS)
  157. {
  158. ASSERT(qhandle != 0);
  159. status = PdhAddCounter(qhandle, total_processor_time_path, 0, &ctr_handle);
  160. if (status == ERROR_SUCCESS)
  161. {
  162. ASSERT(ctr_handle != 0);
  163. cpu_load_determinable = true;
  164. get_cpu_load();
  165. }
  166. else
  167. {
  168. PRINT_DEBUG_MSG(
  169. (_T("GROVELER: PdhAddCounter returned error. PDH_STATUS = %lx\n"),
  170. status));
  171. }
  172. }
  173. else
  174. {
  175. PRINT_DEBUG_MSG((_T("GROVELER: PdhOpenQuery returned error. PDH_STATUS = %lx\n"),
  176. status));
  177. }
  178. last_invokation_time = current_time;
  179. event_timer.schedule(current_time + base_grovel_interval,
  180. (void *)this, control_groveling);
  181. }
  182. CentralController::~CentralController()
  183. {
  184. ASSERT(this != 0);
  185. ASSERT(num_partitions > 0);
  186. if (cpu_load_determinable)
  187. {
  188. ASSERT(qhandle != 0);
  189. PDH_STATUS status = PdhCloseQuery(qhandle);
  190. if (status != ERROR_SUCCESS)
  191. {
  192. PRINT_DEBUG_MSG(
  193. (_T("GROVELER: PdhCloseQuery returned error. PDH_STATUS = %lx\n"),
  194. status));
  195. }
  196. qhandle = 0;
  197. }
  198. for (int index = 0; index < num_partitions; index++)
  199. {
  200. ASSERT(part_controllers[index] != 0);
  201. delete part_controllers[index];
  202. part_controllers[index] = 0;
  203. }
  204. ASSERT(part_controllers != 0);
  205. delete[] part_controllers;
  206. part_controllers = 0;
  207. }
  208. bool
  209. CentralController::any_grovelers_alive()
  210. {
  211. ASSERT(this != 0);
  212. return num_alive_partitions > 0;
  213. }
  214. void
  215. CentralController::demarcate_foreground_batch(
  216. int partition_index)
  217. {
  218. ASSERT(this != 0);
  219. ASSERT(partition_index >= 0);
  220. ASSERT(partition_index < num_partitions);
  221. part_controllers[partition_index]->demarcate_foreground_batch();
  222. }
  223. void
  224. CentralController::command_full_volume_scan(
  225. int partition_index)
  226. {
  227. ASSERT(this != 0);
  228. ASSERT(partition_index >= 0);
  229. ASSERT(partition_index < num_partitions);
  230. part_controllers[partition_index]->command_full_volume_scan();
  231. }
  232. void
  233. CentralController::control_groveling(
  234. void *context)
  235. {
  236. ASSERT(context != 0);
  237. unsigned int invokation_time = GET_TICK_COUNT();
  238. TRACE_PRINTF(TC_centctrl, 3, (_T("time: %d\n"), invokation_time));
  239. TRACE_PRINTF(TC_centctrl, 3, (_T("\tCCcg -\tcontrolling groveling\n")));
  240. CentralController *me = (CentralController *)context;
  241. ASSERT(me->num_partitions > 0);
  242. ASSERT(me->num_alive_partitions > 0);
  243. if (SERVICE_GROVELING_PAUSED() || SERVICE_FOREGROUND_GROVELING())
  244. {
  245. TRACE_PRINTF(TC_centctrl, 1, (_T("\tCCcg -\tsuspending controller\n")));
  246. SERVICE_SUSPENDING_CONTROLLER();
  247. return; // return without scheduling another control_groveling()
  248. }
  249. int partition_index = -1;
  250. double top_priority = DBL_MAX;
  251. unsigned int time_delta = invokation_time - me->last_invokation_time;
  252. ASSERT(signed(time_delta) >= 0);
  253. for (int index = 0; index < me->num_partitions; index++)
  254. {
  255. me->part_controllers[index]->advance(time_delta);
  256. if (me->part_controllers[index]->wait() == 0)
  257. {
  258. double partition_priority = me->part_controllers[index]->priority();
  259. if (partition_priority < top_priority)
  260. {
  261. partition_index = index;
  262. top_priority = partition_priority;
  263. }
  264. }
  265. }
  266. if (partition_index >= 0)
  267. {
  268. ASSERT(partition_index < me->num_partitions);
  269. TRACE_PRINTF(TC_centctrl, 5,
  270. (_T("\tCCcg -\tgroveling partition %d\n"), partition_index));
  271. me->grovel_partition(partition_index);
  272. }
  273. else
  274. {
  275. TRACE_PRINTF(TC_centctrl, 4,
  276. (_T("\tCCcg -\tno partition controllers ready to grovel.\n")));
  277. }
  278. int grovel_interval = me->max_response_lag;
  279. ASSERT(grovel_interval > 0);
  280. for (index = 0; index < me->num_partitions; index++)
  281. {
  282. int wait = me->part_controllers[index]->wait();
  283. if (wait < grovel_interval)
  284. {
  285. grovel_interval = wait;
  286. }
  287. }
  288. if (grovel_interval < me->working_grovel_interval)
  289. {
  290. grovel_interval = me->working_grovel_interval;
  291. }
  292. TRACE_PRINTF(TC_centctrl, 5,
  293. (_T("\tCCcg -\tgrovel interval = %d\n"), grovel_interval));
  294. me->last_invokation_time = invokation_time;
  295. ASSERT(grovel_interval > 0);
  296. event_timer.schedule(invokation_time + grovel_interval,
  297. context, control_groveling);
  298. }
  299. void
  300. CentralController::exhort_groveling(
  301. void *context)
  302. {
  303. ASSERT(context != 0);
  304. unsigned int invokation_time = GET_TICK_COUNT();
  305. TRACE_PRINTF(TC_centctrl, 3, (_T("time: %d\n"), invokation_time));
  306. TRACE_PRINTF(TC_centctrl, 3, (_T("\tCCcg -\texhorting groveling\n")));
  307. CentralController *me = (CentralController *)context;
  308. ASSERT(me->num_partitions > 0);
  309. ASSERT(me->num_alive_partitions > 0);
  310. if (SERVICE_GROVELING_PAUSED() || !SERVICE_FOREGROUND_GROVELING())
  311. {
  312. TRACE_PRINTF(TC_centctrl, 1, (_T("\tCCcg -\tsuspending exhorter\n")));
  313. SERVICE_SUSPENDING_EXHORTER();
  314. return; // return without scheduling another exhort_groveling()
  315. }
  316. for (int index = 0; index < me->num_partitions; index++)
  317. {
  318. me->foreground_partition_index =
  319. (me->foreground_partition_index + 1) % me->num_partitions;
  320. if (SERVICE_PARTITION_IN_FOREGROUND(me->foreground_partition_index))
  321. {
  322. break;
  323. }
  324. }
  325. ASSERT(me->foreground_partition_index >= 0);
  326. ASSERT(me->foreground_partition_index < me->num_partitions);
  327. ASSERT(SERVICE_PARTITION_IN_FOREGROUND(me->foreground_partition_index));
  328. TRACE_PRINTF(TC_centctrl, 5, (_T("\tCCcg -\tgroveling partition %d\n"),
  329. me->foreground_partition_index));
  330. me->grovel_partition(me->foreground_partition_index);
  331. event_timer.schedule(invokation_time + me->working_grovel_interval,
  332. context, exhort_groveling);
  333. }
  334. double
  335. CentralController::get_cpu_load()
  336. {
  337. ASSERT(this != 0);
  338. if (!cpu_load_determinable)
  339. {
  340. return 0.0;
  341. }
  342. ASSERT(qhandle != 0);
  343. ASSERT(ctr_handle != 0);
  344. PDH_STATUS status = PdhCollectQueryData(qhandle);
  345. if (status != ERROR_SUCCESS)
  346. {
  347. PRINT_DEBUG_MSG(
  348. (_T("GROVELER: PdhCollectQueryData returned error. PDH_STATUS = %lx\n"),
  349. status));
  350. return 0.0;
  351. }
  352. PDH_FMT_COUNTERVALUE pdh_value;
  353. status =
  354. PdhGetFormattedCounterValue(ctr_handle, PDH_FMT_LONG, 0, &pdh_value);
  355. if (status != ERROR_SUCCESS)
  356. {
  357. PRINT_DEBUG_MSG(
  358. (_T("GROVELER: PdhGetFormattedCounterValue returned error. PDH_STATUS = %lx\n"),
  359. status));
  360. return 0.0;
  361. }
  362. if (pdh_value.CStatus != ERROR_SUCCESS)
  363. {
  364. PRINT_DEBUG_MSG((_T("GROVELER: PDH_FMT_COUNTERVALUE::CStatus = %lx\n"), status));
  365. return 0.0;
  366. }
  367. double cpu_load = double(pdh_value.longValue) / 100.0;
  368. if (cpu_load < 0.0)
  369. {
  370. cpu_load = 0.0;
  371. }
  372. if (cpu_load > 1.0)
  373. {
  374. cpu_load = 1.0;
  375. }
  376. return cpu_load;
  377. }
  378. void
  379. CentralController::grovel_partition(
  380. int partition_index)
  381. {
  382. ASSERT(this != 0);
  383. DWORD count_of_files_hashed;
  384. DWORDLONG bytes_of_files_hashed;
  385. DWORD count_of_files_matching;
  386. DWORDLONG bytes_of_files_matching;
  387. DWORD count_of_files_compared;
  388. DWORDLONG bytes_of_files_compared;
  389. DWORD count_of_files_merged;
  390. DWORDLONG bytes_of_files_merged;
  391. DWORD count_of_files_enqueued;
  392. DWORD count_of_files_dequeued;
  393. double cpu_load = get_cpu_load();
  394. TRACE_PRINTF(TC_centctrl, 4, (_T("\tCCgp -\tcpu load = %f\n"), cpu_load));
  395. ASSERT(cpu_load >= 0.0);
  396. ASSERT(cpu_load <= 1.0);
  397. bool ok = part_controllers[partition_index]->
  398. control_operation(grovel_duration,
  399. &count_of_files_hashed, &bytes_of_files_hashed,
  400. &count_of_files_matching, &bytes_of_files_matching,
  401. &count_of_files_compared, &bytes_of_files_compared,
  402. &count_of_files_merged, &bytes_of_files_merged,
  403. &count_of_files_enqueued, &count_of_files_dequeued,
  404. cpu_load);
  405. if (ok)
  406. {
  407. ASSERT(bytes_of_files_hashed >= count_of_files_hashed);
  408. ASSERT(bytes_of_files_matching >= count_of_files_matching);
  409. ASSERT(bytes_of_files_compared >= count_of_files_compared);
  410. ASSERT(bytes_of_files_merged >= count_of_files_merged);
  411. ASSERT(count_of_files_hashed >= count_of_files_matching);
  412. ASSERT(bytes_of_files_hashed >= bytes_of_files_matching);
  413. ASSERT(count_of_files_compared >= count_of_files_merged);
  414. ASSERT(bytes_of_files_compared >= bytes_of_files_merged);
  415. ASSERT(count_of_files_dequeued >= count_of_files_hashed);
  416. TRACE_PRINTF(TC_centctrl, 3,
  417. (_T("\tCCgp -\tpartition %d groveled.\n"), partition_index));
  418. TRACE_PRINTF(TC_centctrl, 4,
  419. (_T("\tCCgp -\tfiles hashed = %d\n"), count_of_files_hashed));
  420. TRACE_PRINTF(TC_centctrl, 4,
  421. (_T("\tCCgp -\tbytes hashed = %I64d\n"), bytes_of_files_hashed));
  422. TRACE_PRINTF(TC_centctrl, 4,
  423. (_T("\tCCgp -\tfiles matching = %d\n"), count_of_files_matching));
  424. TRACE_PRINTF(TC_centctrl, 4,
  425. (_T("\tCCgp -\tbytes matching = %I64d\n"),
  426. bytes_of_files_matching));
  427. TRACE_PRINTF(TC_centctrl, 4,
  428. (_T("\tCCgp -\tfiles compared = %d\n"), count_of_files_matching));
  429. TRACE_PRINTF(TC_centctrl, 4,
  430. (_T("\tCCgp -\tbytes compared = %I64d\n"),
  431. bytes_of_files_matching));
  432. TRACE_PRINTF(TC_centctrl, 4,
  433. (_T("\tCCgp -\tfiles merged = %d\n"), count_of_files_merged));
  434. TRACE_PRINTF(TC_centctrl, 4,
  435. (_T("\tCCgp -\tbytes merged = %I64d\n"), bytes_of_files_merged));
  436. TRACE_PRINTF(TC_centctrl, 4,
  437. (_T("\tCCgp -\tfiles enqueued = %d\n"), count_of_files_enqueued));
  438. TRACE_PRINTF(TC_centctrl, 4,
  439. (_T("\tCCgp -\tfiles dequeued = %d\n"), count_of_files_dequeued));
  440. if (bytes_of_files_hashed > 0)
  441. {
  442. double sample_hash_match_ratio =
  443. double(__int64(bytes_of_files_matching))
  444. / double(__int64(bytes_of_files_hashed));
  445. ASSERT(sample_hash_match_ratio >= 0.0);
  446. ASSERT(sample_hash_match_ratio <= 1.0);
  447. TRACE_PRINTF(TC_centctrl, 4,
  448. (_T("\tCCgp -\tsample hash match ratio = %f\n"),
  449. sample_hash_match_ratio));
  450. hash_match_ratio_filter.update_value(
  451. sample_hash_match_ratio, count_of_files_hashed);
  452. *hash_match_ratio = hash_match_ratio_filter.retrieve_value();
  453. ASSERT(*hash_match_ratio >= 0.0);
  454. ASSERT(*hash_match_ratio <= 1.0);
  455. TRACE_PRINTF(TC_centctrl, 3,
  456. (_T("\tCCgp -\tfiltered hash match ratio = %f\n"),
  457. *hash_match_ratio));
  458. }
  459. if (bytes_of_files_compared > 0)
  460. {
  461. double sample_compare_match_ratio =
  462. double(__int64(bytes_of_files_merged))
  463. / double(__int64(bytes_of_files_compared));
  464. ASSERT(sample_compare_match_ratio >= 0.0);
  465. ASSERT(sample_compare_match_ratio <= 1.0);
  466. TRACE_PRINTF(TC_centctrl, 4,
  467. (_T("\tCCgp -\tsample compare match ratio = %f\n"),
  468. sample_compare_match_ratio));
  469. compare_match_ratio_filter.update_value(
  470. sample_compare_match_ratio, count_of_files_compared);
  471. *compare_match_ratio = compare_match_ratio_filter.retrieve_value();
  472. ASSERT(*compare_match_ratio >= 0.0);
  473. ASSERT(*compare_match_ratio <= 1.0);
  474. TRACE_PRINTF(TC_centctrl, 3,
  475. (_T("\tCCgp -\tfiltered compare match ratio = %f\n"),
  476. *compare_match_ratio));
  477. }
  478. if (count_of_files_dequeued > 0)
  479. {
  480. double sample_dequeue_hash_ratio =
  481. double(__int64(count_of_files_hashed))
  482. / double(__int64(count_of_files_dequeued));
  483. ASSERT(sample_dequeue_hash_ratio >= 0.0);
  484. ASSERT(sample_dequeue_hash_ratio <= 1.0);
  485. TRACE_PRINTF(TC_centctrl, 4,
  486. (_T("\tCCgp -\tsample dequeue hash ratio = %f\n"),
  487. sample_dequeue_hash_ratio));
  488. dequeue_hash_ratio_filter.update_value(
  489. sample_dequeue_hash_ratio, count_of_files_dequeued);
  490. *dequeue_hash_ratio = dequeue_hash_ratio_filter.retrieve_value();
  491. ASSERT(*dequeue_hash_ratio >= 0.0);
  492. ASSERT(*dequeue_hash_ratio <= 1.0);
  493. TRACE_PRINTF(TC_centctrl, 3,
  494. (_T("\tCCgp -\tfiltered dequeue hash ratio = %f\n"),
  495. *dequeue_hash_ratio));
  496. }
  497. }
  498. else
  499. {
  500. TRACE_PRINTF(TC_centctrl, 1,
  501. (_T("\tCCgp -\tpartition %d groveler dead.\n"), partition_index));
  502. num_alive_partitions--;
  503. if (num_alive_partitions <= 0)
  504. {
  505. ASSERT(num_alive_partitions == 0);
  506. eventlog.report_event(GROVMSG_ALL_GROVELERS_DEAD, 0);
  507. event_timer.halt();
  508. return;
  509. }
  510. }
  511. // get_cpu_load();
  512. }