Leaked source code of windows server 2003
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.

1368 lines
57 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. partctrl.cpp
  5. Abstract:
  6. SIS Groveler partition controller
  7. Authors:
  8. John Douceur, 1998
  9. Environment:
  10. User Mode
  11. Revision History:
  12. --*/
  13. #include "all.hxx"
  14. PartitionController::PartitionController(
  15. Groveler *groveler,
  16. GrovelStatus groveler_status,
  17. int target_entries_per_extraction,
  18. int max_extraction_interval,
  19. int base_grovel_interval,
  20. int max_grovel_interval,
  21. int low_confidence_grovel_interval,
  22. int low_disk_space_grovel_interval,
  23. int partition_info_update_interval,
  24. int base_restart_extraction_interval,
  25. int max_restart_extraction_interval,
  26. int base_restart_groveling_interval,
  27. int max_restart_groveling_interval,
  28. int base_regrovel_interval,
  29. int max_regrovel_interval,
  30. int volscan_regrovel_threshold,
  31. int partition_balance_time_constant,
  32. int read_time_increase_history_size,
  33. int read_time_decrease_history_size,
  34. int file_size_history_size,
  35. bool error_retry_log_extraction,
  36. bool error_retry_groveling,
  37. __int64 base_usn_log_size,
  38. __int64 max_usn_log_size,
  39. int sample_group_size,
  40. double acceptance_p_value,
  41. double rejection_p_value,
  42. double base_use_multiplier,
  43. double max_use_multiplier,
  44. double peak_finder_accuracy,
  45. double peak_finder_range,
  46. double base_cpu_load_threshold,
  47. double max_cpu_load_threshold,
  48. double *hash_match_ratio,
  49. double *compare_match_ratio,
  50. double *dequeue_hash_ratio,
  51. double *hash_read_time_estimate,
  52. double *compare_read_time_estimate,
  53. double *mean_file_size,
  54. double *read_time_confidence,
  55. int *volume_serial_number,
  56. int partition_index,
  57. double read_report_discard_threshold,
  58. int min_file_size,
  59. int min_file_age,
  60. bool allow_compressed_files,
  61. bool allow_encrypted_files,
  62. bool allow_hidden_files,
  63. bool allow_offline_files,
  64. bool allow_temporary_files,
  65. int num_excluded_paths,
  66. const _TCHAR **excluded_paths)
  67. : read_mean_comparator(2, sample_group_size,
  68. acceptance_p_value, rejection_p_value, peak_finder_accuracy),
  69. file_size_filter(file_size_history_size, *mean_file_size),
  70. read_time_confidence_estimator(2, *read_time_confidence),
  71. partition_grovel_accumulator(partition_balance_time_constant)
  72. {
  73. ASSERT(this != 0);
  74. unsigned int current_time = GET_TICK_COUNT();
  75. TRACE_PRINTF(TC_partctrl, 1, (_T("time: %d\n"), current_time));
  76. TRACE_PRINTF(TC_partctrl, 1,
  77. (_T("\tPC -\tconstructing PartitionController for drive %s\n"),
  78. sis_drives.partition_mount_name(partition_index)));
  79. ASSERT(groveler != 0);
  80. this->groveler = groveler;
  81. ASSERT(target_entries_per_extraction > 0);
  82. this->target_entries_per_extraction = target_entries_per_extraction;
  83. ASSERT(max_extraction_interval > 0);
  84. this->max_extraction_interval = max_extraction_interval;
  85. ASSERT(base_grovel_interval > 0);
  86. this->base_grovel_interval = base_grovel_interval;
  87. ASSERT(max_grovel_interval > 0);
  88. ASSERT(max_grovel_interval >= base_grovel_interval);
  89. this->max_grovel_interval = max_grovel_interval;
  90. ASSERT(partition_info_update_interval > 0);
  91. this->partition_info_update_interval = partition_info_update_interval;
  92. ASSERT(base_restart_extraction_interval > 0);
  93. this->base_restart_extraction_interval = base_restart_extraction_interval;
  94. ASSERT(max_restart_extraction_interval > 0);
  95. ASSERT(max_restart_extraction_interval >= base_restart_extraction_interval);
  96. this->max_restart_extraction_interval = max_restart_extraction_interval;
  97. ASSERT(base_restart_groveling_interval > 0);
  98. this->base_restart_groveling_interval = base_restart_groveling_interval;
  99. ASSERT(max_restart_groveling_interval > 0);
  100. ASSERT(max_restart_groveling_interval >= base_restart_groveling_interval);
  101. this->max_restart_groveling_interval = max_restart_groveling_interval;
  102. this->error_retry_log_extraction = error_retry_log_extraction;
  103. this->error_retry_groveling = error_retry_groveling;
  104. ASSERT(base_usn_log_size > 0);
  105. this->base_usn_log_size = base_usn_log_size;
  106. ASSERT(max_usn_log_size > 0);
  107. ASSERT(max_usn_log_size >= base_usn_log_size);
  108. this->max_usn_log_size = max_usn_log_size;
  109. ASSERT(hash_match_ratio != 0);
  110. ASSERT(*hash_match_ratio >= 0.0);
  111. ASSERT(*hash_match_ratio <= 1.0);
  112. this->hash_match_ratio = hash_match_ratio;
  113. ASSERT(compare_match_ratio != 0);
  114. ASSERT(*compare_match_ratio >= 0.0);
  115. ASSERT(*compare_match_ratio <= 1.0);
  116. this->compare_match_ratio = compare_match_ratio;
  117. ASSERT(dequeue_hash_ratio != 0);
  118. ASSERT(*dequeue_hash_ratio >= 0.0);
  119. ASSERT(*dequeue_hash_ratio <= 1.0);
  120. this->dequeue_hash_ratio = dequeue_hash_ratio;
  121. ASSERT(mean_file_size != 0);
  122. ASSERT(*mean_file_size >= 0.0);
  123. this->mean_file_size = mean_file_size;
  124. ASSERT(read_time_confidence != 0);
  125. ASSERT(*read_time_confidence >= 0.0);
  126. ASSERT(*read_time_confidence <= 1.0);
  127. this->read_time_confidence = read_time_confidence;
  128. ASSERT(base_use_multiplier > 0.0);
  129. this->base_use_multiplier = base_use_multiplier;
  130. ASSERT(partition_index >= 0);
  131. this->partition_index = partition_index;
  132. ASSERT(base_regrovel_interval > 0);
  133. this->base_regrovel_interval = base_regrovel_interval;
  134. ASSERT(max_regrovel_interval >= base_regrovel_interval);
  135. this->max_regrovel_interval = max_regrovel_interval;
  136. ASSERT(volscan_regrovel_threshold >= base_regrovel_interval);
  137. ASSERT(volscan_regrovel_threshold <= max_regrovel_interval);
  138. this->volscan_regrovel_threshold = volscan_regrovel_threshold;
  139. ASSERT(read_report_discard_threshold >= 0.0);
  140. ASSERT(read_report_discard_threshold <= 1.0);
  141. this->read_report_discard_threshold = read_report_discard_threshold;
  142. ASSERT(min_file_size >= 0);
  143. this->min_file_size = min_file_size;
  144. ASSERT(min_file_age >= 0);
  145. this->min_file_age = min_file_age;
  146. this->allow_compressed_files = allow_compressed_files;
  147. this->allow_encrypted_files = allow_encrypted_files;
  148. this->allow_hidden_files = allow_hidden_files;
  149. this->allow_offline_files = allow_offline_files;
  150. this->allow_temporary_files = allow_temporary_files;
  151. ASSERT(num_excluded_paths >= 0);
  152. this->num_excluded_paths = num_excluded_paths;
  153. ASSERT(excluded_paths != 0);
  154. this->excluded_paths = excluded_paths;
  155. ASSERT(peak_finder_accuracy > 0.0);
  156. ASSERT(peak_finder_accuracy <= 1.0);
  157. this->peak_finder_accuracy = peak_finder_accuracy;
  158. ASSERT(peak_finder_range >= 1.0);
  159. read_peak_finder[RT_hash] =
  160. new PeakFinder(peak_finder_accuracy, peak_finder_range);
  161. read_peak_finder[RT_compare] =
  162. new PeakFinder(peak_finder_accuracy, peak_finder_range);
  163. ASSERT(base_cpu_load_threshold >= 0.0);
  164. this->base_cpu_load_threshold = base_cpu_load_threshold;
  165. ASSERT(read_time_increase_history_size > 0);
  166. ASSERT(read_time_decrease_history_size > 0);
  167. ASSERT(hash_read_time_estimate != 0);
  168. ASSERT(*hash_read_time_estimate >= 0.0);
  169. read_time_filter[RT_hash] =
  170. new DirectedIncidentFilter(read_time_increase_history_size,
  171. read_time_decrease_history_size, *hash_read_time_estimate);
  172. ASSERT(compare_read_time_estimate != 0);
  173. ASSERT(*compare_read_time_estimate >= 0.0);
  174. read_time_filter[RT_compare] =
  175. new DirectedIncidentFilter(read_time_increase_history_size,
  176. read_time_decrease_history_size, *compare_read_time_estimate);
  177. read_time_estimate[RT_hash] = hash_read_time_estimate;
  178. read_time_estimate[RT_compare] = compare_read_time_estimate;
  179. log_max_grovel_interval = log(double(max_grovel_interval));
  180. ASSERT(low_confidence_grovel_interval > 0);
  181. log_low_confidence_slope =
  182. log_max_grovel_interval - log(double(low_confidence_grovel_interval));
  183. if (log_low_confidence_slope < 0.0)
  184. {
  185. log_low_confidence_slope = 0.0;
  186. }
  187. ASSERT(low_disk_space_grovel_interval > 0);
  188. low_disk_space_slope = max_grovel_interval - low_disk_space_grovel_interval;
  189. if (low_disk_space_slope < 0.0)
  190. {
  191. low_disk_space_slope = 0.0;
  192. }
  193. ASSERT(max_use_multiplier >= base_use_multiplier);
  194. use_multiplier_slope = max_use_multiplier - base_use_multiplier;
  195. ASSERT(max_cpu_load_threshold <= 1.0);
  196. ASSERT(max_cpu_load_threshold >= base_cpu_load_threshold);
  197. cpu_load_threshold_slope = max_cpu_load_threshold - base_cpu_load_threshold;
  198. ASSERT(volume_serial_number != 0);
  199. this->volume_serial_number = volume_serial_number;
  200. update_partition_info((void *)this);
  201. ASSERT(volume_total_bytes > 0.0);
  202. ASSERT(volume_free_bytes >= 0.0);
  203. current_usn_log_size = base_usn_log_size;
  204. restart_groveling_interval = base_restart_groveling_interval;
  205. remaining_grovel_interval = 0;
  206. restart_volume_scan = false;
  207. extended_restart_in_progress = false;
  208. initialize_groveling(groveler_status);
  209. log_extractor_dead = true;
  210. restart_extraction_interval = base_restart_extraction_interval;
  211. remaining_restart_extraction_interval = 0;
  212. restart_extraction((void *)this);
  213. }
  214. PartitionController::~PartitionController()
  215. {
  216. ASSERT(read_peak_finder[RT_hash] != 0);
  217. delete read_peak_finder[RT_hash];
  218. read_peak_finder[RT_hash] = 0;
  219. ASSERT(read_peak_finder[RT_compare] != 0);
  220. delete read_peak_finder[RT_compare];
  221. read_peak_finder[RT_hash] = 0;
  222. ASSERT(read_time_filter[RT_hash] != 0);
  223. delete read_time_filter[RT_hash];
  224. read_time_filter[RT_hash] = 0;
  225. ASSERT(read_time_filter[RT_compare] != 0);
  226. delete read_time_filter[RT_compare];
  227. read_time_filter[RT_compare] = 0;
  228. }
  229. bool
  230. PartitionController::control_operation(
  231. DWORD grovel_duration,
  232. DWORD *count_of_files_hashed,
  233. DWORDLONG *bytes_of_files_hashed,
  234. DWORD *count_of_files_matching,
  235. DWORDLONG *bytes_of_files_matching,
  236. DWORD *count_of_files_compared,
  237. DWORDLONG *bytes_of_files_compared,
  238. DWORD *count_of_files_merged,
  239. DWORDLONG *bytes_of_files_merged,
  240. DWORD *count_of_files_enqueued,
  241. DWORD *count_of_files_dequeued,
  242. double cpu_load)
  243. {
  244. ASSERT(this != 0);
  245. ASSERT(grovel_duration > 0);
  246. ASSERT(count_of_files_hashed != 0);
  247. ASSERT(bytes_of_files_hashed != 0);
  248. ASSERT(count_of_files_matching != 0);
  249. ASSERT(bytes_of_files_matching != 0);
  250. ASSERT(count_of_files_compared != 0);
  251. ASSERT(bytes_of_files_compared != 0);
  252. ASSERT(count_of_files_merged != 0);
  253. ASSERT(bytes_of_files_merged != 0);
  254. ASSERT(count_of_files_enqueued != 0);
  255. ASSERT(count_of_files_dequeued != 0);
  256. ASSERT(cpu_load >= 0.0);
  257. ASSERT(cpu_load <= 1.0);
  258. ASSERT(!groveler_dead);
  259. unsigned int current_time = GET_TICK_COUNT();
  260. TRACE_PRINTF(TC_partctrl, 3, (_T("time: %d\n"), current_time));
  261. TRACE_PRINTF(TC_partctrl, 3, (_T("\tPCco -\toperating on drive %s\n"),
  262. sis_drives.partition_mount_name(partition_index)));
  263. int files_to_compare = groveler->count_of_files_to_compare();
  264. ASSERT(files_to_compare >= 0);
  265. int files_in_queue = groveler->count_of_files_in_queue();
  266. ASSERT(files_in_queue >= 0);
  267. int ready_time = groveler->time_to_first_file_ready();
  268. ASSERT(files_in_queue == 0 || ready_time >= 0);
  269. bool more_work_to_do = files_to_compare > 0 ||
  270. files_in_queue > 0 && ready_time < volscan_regrovel_threshold;
  271. if (log_extractor_dead && !performing_full_volume_scan && !more_work_to_do)
  272. {
  273. initiate_full_volume_scan = true;
  274. }
  275. partition_grovel_accumulator.increment();
  276. ASSERT(groveler != 0);
  277. bool ok;
  278. if (initiate_full_volume_scan ||
  279. performing_full_volume_scan && !more_work_to_do)
  280. {
  281. if (initiate_full_volume_scan)
  282. {
  283. TRACE_PRINTF(TC_partctrl, 1,
  284. (_T("\tPCco -\tinitiating full volume scan\n")));
  285. initiate_full_volume_scan = false;
  286. performing_full_volume_scan = true;
  287. restart_volume_scan = true;
  288. }
  289. TRACE_PRINTF(TC_partctrl, 4,
  290. (_T("\tPCco -\tperforming full volume scan\n")));
  291. ok = control_volume_scan(grovel_duration, count_of_files_enqueued);
  292. *count_of_files_hashed = 0;
  293. *bytes_of_files_hashed = 0;
  294. *count_of_files_matching = 0;
  295. *bytes_of_files_matching = 0;
  296. *count_of_files_compared = 0;
  297. *bytes_of_files_compared = 0;
  298. *count_of_files_merged = 0;
  299. *bytes_of_files_merged = 0;
  300. *count_of_files_dequeued = 0;
  301. }
  302. else
  303. {
  304. TRACE_PRINTF(TC_partctrl, 4, (_T("\tPCco -\tgroveling\n")));
  305. ok = control_groveling(grovel_duration,
  306. count_of_files_hashed, bytes_of_files_hashed,
  307. count_of_files_matching, bytes_of_files_matching,
  308. count_of_files_compared, bytes_of_files_compared,
  309. count_of_files_merged, bytes_of_files_merged,
  310. count_of_files_enqueued, count_of_files_dequeued,
  311. cpu_load);
  312. }
  313. if (groveler_dead)
  314. {
  315. TRACE_PRINTF(TC_partctrl, 1,
  316. (_T("\tPCco -\tconcluding foreground batch for drive %s\n"),
  317. sis_drives.partition_mount_name(partition_index)));
  318. SERVICE_SET_FOREGROUND_BATCH_IN_PROGRESS(partition_index, false);
  319. }
  320. else
  321. {
  322. files_to_compare = groveler->count_of_files_to_compare();
  323. ASSERT(files_to_compare >= 0);
  324. files_in_queue = groveler->count_of_files_in_queue();
  325. ASSERT(files_in_queue >= 0);
  326. ready_time = groveler->time_to_first_file_ready();
  327. ASSERT(files_in_queue == 0 || ready_time >= 0);
  328. more_work_to_do = files_to_compare > 0 ||
  329. files_in_queue > 0 && ready_time < volscan_regrovel_threshold;
  330. if (!performing_full_volume_scan && !more_work_to_do)
  331. {
  332. TRACE_PRINTF(TC_partctrl, 1,
  333. (_T("\tPCco -\tconcluding foreground batch for drive %s\n"),
  334. sis_drives.partition_mount_name(partition_index)));
  335. SERVICE_SET_FOREGROUND_BATCH_IN_PROGRESS(partition_index, false);
  336. }
  337. }
  338. return ok;
  339. }
  340. void
  341. PartitionController::advance(
  342. int time_delta)
  343. {
  344. ASSERT(this != 0);
  345. ASSERT(time_delta >= 0);
  346. unsigned int current_time = GET_TICK_COUNT();
  347. TRACE_PRINTF(TC_partctrl, 4, (_T("time: %d\n"), current_time));
  348. TRACE_PRINTF(TC_partctrl, 4,
  349. (_T("\tPCa -\tadvancing time for drive %s by %d\n"),
  350. sis_drives.partition_mount_name(partition_index), time_delta));
  351. if (groveler_dead)
  352. {
  353. return;
  354. }
  355. ASSERT(remaining_grovel_interval >= 0);
  356. remaining_grovel_interval -= time_delta;
  357. if (remaining_grovel_interval < 0)
  358. {
  359. remaining_grovel_interval = 0;
  360. }
  361. TRACE_PRINTF(TC_partctrl, 4,
  362. (_T("\tPCa -\tremaining grovel interval = %d\n"),
  363. remaining_grovel_interval));
  364. }
  365. double
  366. PartitionController::priority() const
  367. {
  368. ASSERT(this != 0);
  369. unsigned int current_time = GET_TICK_COUNT();
  370. TRACE_PRINTF(TC_partctrl, 4, (_T("time: %d\n"), current_time));
  371. TRACE_PRINTF(TC_partctrl, 4,
  372. (_T("\tPCp -\tcalculating priority on drive %s\n"),
  373. sis_drives.partition_mount_name(partition_index)));
  374. if (groveler_dead)
  375. {
  376. return DBL_MAX;
  377. }
  378. double accumulated_groveling =
  379. partition_grovel_accumulator.retrieve_value();
  380. ASSERT(accumulated_groveling >= 0.0);
  381. TRACE_PRINTF(TC_partctrl, 5,
  382. (_T("\tPCp -\taccumulated groveling = %f\n"), accumulated_groveling));
  383. double calculated_priority =
  384. (1.0 + accumulated_groveling) * (1.0 + volume_free_bytes);
  385. ASSERT(calculated_priority > 1.0);
  386. TRACE_PRINTF(TC_partctrl, 4,
  387. (_T("\tPCp -\tcalculated priority = %f\n"), calculated_priority));
  388. return calculated_priority;
  389. }
  390. int
  391. PartitionController::wait() const
  392. {
  393. ASSERT(this != 0);
  394. ASSERT(groveler != 0);
  395. unsigned int current_time = GET_TICK_COUNT();
  396. TRACE_PRINTF(TC_partctrl, 4, (_T("time: %d\n"), current_time));
  397. TRACE_PRINTF(TC_partctrl, 4,
  398. (_T("\tPCw -\tcalculating wait time for drive %s\n"),
  399. sis_drives.partition_mount_name(partition_index)));
  400. int time_until_groveler_ready = max_grovel_interval;
  401. if (!groveler_dead)
  402. {
  403. int files_to_compare = groveler->count_of_files_to_compare();
  404. ASSERT(files_to_compare >= 0);
  405. int files_in_queue = groveler->count_of_files_in_queue();
  406. ASSERT(files_in_queue >= 0);
  407. int ready_time = groveler->time_to_first_file_ready();
  408. ASSERT(files_in_queue == 0 || ready_time >= 0);
  409. bool more_work_to_do = files_to_compare > 0 ||
  410. files_in_queue > 0 && ready_time < volscan_regrovel_threshold;
  411. if (files_to_compare > 0 ||
  412. initiate_full_volume_scan && !more_work_to_do ||
  413. performing_full_volume_scan && !more_work_to_do ||
  414. log_extractor_dead && !more_work_to_do)
  415. {
  416. time_until_groveler_ready = 0;
  417. TRACE_PRINTF(TC_partctrl, 5, (_T("\tPCw -\tgroveler ready now\n")));
  418. }
  419. else if (files_in_queue > 0)
  420. {
  421. time_until_groveler_ready = ready_time;
  422. ASSERT(time_until_groveler_ready >= 0);
  423. TRACE_PRINTF(TC_partctrl, 5,
  424. (_T("\tPCw -\ttime until groveler ready = %d\n"),
  425. time_until_groveler_ready));
  426. }
  427. }
  428. TRACE_PRINTF(TC_partctrl, 5,
  429. (_T("\tPCw -\tremaining grovel interval = %d\n"),
  430. remaining_grovel_interval));
  431. int wait_time = __max(remaining_grovel_interval, time_until_groveler_ready);
  432. TRACE_PRINTF(TC_partctrl, 4, (_T("\tPCw -\twait time = %d\n"), wait_time));
  433. return wait_time;
  434. }
  435. void
  436. PartitionController::demarcate_foreground_batch()
  437. {
  438. ASSERT(this != 0);
  439. unsigned int current_time = GET_TICK_COUNT();
  440. if (!groveler_dead)
  441. {
  442. TRACE_PRINTF(TC_partctrl, 1, (_T("time: %d\n"), current_time));
  443. TRACE_PRINTF(TC_partctrl, 1,
  444. (_T("\tPCdfb -\tdemarcating foreground batch for drive %s\n"),
  445. sis_drives.partition_mount_name(partition_index)));
  446. SERVICE_SET_FOREGROUND_BATCH_IN_PROGRESS(partition_index, true);
  447. }
  448. }
  449. void
  450. PartitionController::command_full_volume_scan()
  451. {
  452. ASSERT(this != 0);
  453. unsigned int current_time = GET_TICK_COUNT();
  454. TRACE_PRINTF(TC_partctrl, 1, (_T("time: %d\n"), current_time));
  455. TRACE_PRINTF(TC_partctrl, 1,
  456. (_T("\tPCcfvs -\tcommanding full volume scan for drive %s\n"),
  457. sis_drives.partition_mount_name(partition_index)));
  458. initiate_full_volume_scan = true;
  459. }
  460. void
  461. PartitionController::control_extraction(
  462. void *context)
  463. {
  464. ASSERT(context != 0);
  465. unsigned int invokation_time = GET_TICK_COUNT();
  466. TRACE_PRINTF(TC_partctrl, 3, (_T("time: %d\n"), invokation_time));
  467. PartitionController *me = (PartitionController *)context;
  468. TRACE_PRINTF(TC_partctrl, 3, (_T("\tPCce -\textracting log on drive %s\n"),
  469. sis_drives.partition_mount_name(me->partition_index)));
  470. ASSERT(!me->log_extractor_dead);
  471. if (me->groveler_dead || me->restart_extraction_required)
  472. {
  473. TRACE_PRINTF(TC_partctrl, 4, (_T("\tPCce -\trestarting extraction\n")));
  474. me->log_extractor_dead = true;
  475. me->restart_extraction_interval = me->base_restart_extraction_interval;
  476. me->remaining_restart_extraction_interval = 0;
  477. restart_extraction(context);
  478. return;
  479. }
  480. DWORD num_entries_extracted;
  481. DWORDLONG num_bytes_extracted;
  482. DWORDLONG num_bytes_skipped;
  483. DWORD num_files_enqueued;
  484. DWORD num_files_dequeued;
  485. GrovelStatus status =
  486. me->groveler->extract_log(&num_entries_extracted, &num_bytes_extracted,
  487. &num_bytes_skipped, &num_files_enqueued, &num_files_dequeued);
  488. unsigned int completion_time = GET_TICK_COUNT();
  489. if (status == Grovel_overrun)
  490. {
  491. ASSERT(signed(num_entries_extracted) >= 0);
  492. ASSERT(signed(num_bytes_extracted) >= 0);
  493. ASSERT(signed(num_bytes_skipped) >= 0);
  494. ASSERT(signed(num_files_enqueued) >= 0);
  495. ASSERT(signed(num_files_dequeued) >= 0);
  496. TRACE_PRINTF(TC_partctrl, 1,
  497. (_T("\tPCce -\textract_log() returned Grovel_overrun\n")));
  498. me->initiate_full_volume_scan = true;
  499. eventlog.report_event(GROVMSG_USN_LOG_OVERRUN, ERROR_SUCCESS,
  500. 1, sis_drives.partition_mount_name(me->partition_index));
  501. if (!me->first_extraction)
  502. {
  503. __int64 usn_log_size = num_bytes_extracted + num_bytes_skipped;
  504. ASSERT(me->base_usn_log_size > 0);
  505. ASSERT(me->max_usn_log_size > 0);
  506. ASSERT(me->current_usn_log_size >= me->base_usn_log_size);
  507. ASSERT(me->current_usn_log_size <= me->max_usn_log_size);
  508. if (usn_log_size > me->current_usn_log_size &&
  509. me->current_usn_log_size < me->max_usn_log_size)
  510. {
  511. if (usn_log_size > me->max_usn_log_size)
  512. {
  513. usn_log_size = me->max_usn_log_size;
  514. }
  515. _TCHAR size_string[32];
  516. (void)StringCbPrintf(size_string, sizeof(size_string), _T("%d"), usn_log_size);
  517. eventlog.report_event(GROVMSG_SET_USN_LOG_SIZE, ERROR_SUCCESS,
  518. 2,
  519. sis_drives.partition_mount_name(me->partition_index),
  520. size_string);
  521. TRACE_PRINTF(TC_partctrl, 2,
  522. (_T("\tPCce -\tincreasing USN log size from %d to %d\n"),
  523. me->current_usn_log_size, usn_log_size));
  524. me->current_usn_log_size = usn_log_size;
  525. DWORD lstatus = me->groveler->set_usn_log_size(usn_log_size);
  526. if (lstatus != ERROR_SUCCESS)
  527. {
  528. TRACE_PRINTF(TC_partctrl, 1,
  529. (_T("\tPCce -\tset_usn_log_size() returned error, status=%d\n"),lstatus));
  530. TRACE_PRINTF(TC_partctrl, 1,
  531. (_T("\t\tsuspending control_extraction()\n")));
  532. eventlog.report_event(GROVMSG_LOG_EXTRACTOR_DEAD, lstatus,
  533. 1,sis_drives.partition_mount_name(me->partition_index));
  534. me->log_extractor_dead = true;
  535. me->restart_extraction_interval =
  536. me->base_restart_extraction_interval;
  537. me->remaining_restart_extraction_interval =
  538. me->restart_extraction_interval;
  539. event_timer.schedule(
  540. completion_time + me->max_extraction_interval,
  541. context, restart_extraction);
  542. return;
  543. }
  544. }
  545. }
  546. }
  547. else if (status != Grovel_ok)
  548. {
  549. ASSERT(status == Grovel_error);
  550. TRACE_PRINTF(TC_partctrl, 1,
  551. (_T("\tPCce -\textract_log() returned error\n")));
  552. TRACE_PRINTF(TC_partctrl, 1,
  553. (_T("\t\tsuspending control_extraction()\n")));
  554. eventlog.report_event(GROVMSG_LOG_EXTRACTOR_DEAD, GetLastError(),
  555. 1,sis_drives.partition_mount_name(me->partition_index));
  556. me->log_extractor_dead = true;
  557. me->restart_extraction_interval = me->base_restart_extraction_interval;
  558. me->remaining_restart_extraction_interval =
  559. me->restart_extraction_interval;
  560. event_timer.schedule(completion_time + me->max_extraction_interval,
  561. context, restart_extraction);
  562. return;
  563. }
  564. unsigned int extraction_time = completion_time - invokation_time;
  565. ASSERT(signed(extraction_time) >= 0);
  566. shared_data->increment_value(me->partition_index,
  567. SDF_extract_time, extraction_time);
  568. shared_data->increment_value(me->partition_index,
  569. SDF_working_time, extraction_time);
  570. int queue_length = me->groveler->count_of_files_in_queue();
  571. ASSERT(queue_length >= 0);
  572. shared_data->set_value(me->partition_index, SDF_queue_length, queue_length);
  573. TRACE_PRINTF(TC_partctrl, 4,
  574. (_T("\tPCce -\tnum entries extracted = %d\n"), num_entries_extracted));
  575. TRACE_PRINTF(TC_partctrl, 4,
  576. (_T("\tPCce -\tnum files enqueued = %d\n"), num_files_enqueued));
  577. ASSERT(signed(num_entries_extracted) >= 0);
  578. ASSERT(signed(num_bytes_extracted) >= 0);
  579. ASSERT(signed(num_bytes_skipped) >= 0);
  580. ASSERT(signed(num_files_enqueued) >= 0);
  581. ASSERT(signed(num_files_dequeued) >= 0);
  582. ASSERT(num_bytes_extracted >= num_entries_extracted);
  583. ASSERT(num_files_enqueued <= num_entries_extracted);
  584. ASSERT(status == Grovel_overrun || num_bytes_skipped == 0);
  585. me->first_extraction = false;
  586. if (num_entries_extracted < 1)
  587. {
  588. num_entries_extracted = 1;
  589. }
  590. ASSERT(me->extraction_interval > 0);
  591. ASSERT(me->target_entries_per_extraction > 0);
  592. int ideal_extraction_interval = me->extraction_interval *
  593. me->target_entries_per_extraction / num_entries_extracted + 1;
  594. ASSERT(ideal_extraction_interval > 0);
  595. TRACE_PRINTF(TC_partctrl, 5,
  596. (_T("\tPCce -\tideal extraction interval = %d\n"),
  597. ideal_extraction_interval));
  598. if (ideal_extraction_interval < me->extraction_interval)
  599. {
  600. me->extraction_interval = ideal_extraction_interval;
  601. }
  602. else
  603. {
  604. me->extraction_interval = int(sqrt(double(me->extraction_interval)
  605. * double(ideal_extraction_interval)));
  606. ASSERT(me->max_extraction_interval > 0);
  607. if (me->extraction_interval > me->max_extraction_interval)
  608. {
  609. me->extraction_interval = me->max_extraction_interval;
  610. }
  611. }
  612. TRACE_PRINTF(TC_partctrl, 5,
  613. (_T("\tPCce -\textraction interval = %d\n"), me->extraction_interval));
  614. ASSERT(me->extraction_interval > 0);
  615. ASSERT(me->extraction_interval <= me->max_extraction_interval);
  616. event_timer.schedule(invokation_time + me->extraction_interval,
  617. context, control_extraction);
  618. }
  619. void
  620. PartitionController::restart_extraction(
  621. void *context)
  622. {
  623. ASSERT(context != 0);
  624. unsigned int invokation_time = GET_TICK_COUNT();
  625. TRACE_PRINTF(TC_partctrl, 3, (_T("time: %d\n"), invokation_time));
  626. PartitionController *me = (PartitionController *)context;
  627. TRACE_PRINTF(TC_partctrl, 3,
  628. (_T("\tPCre -\tconsidering restart extraction on drive %s\n"),
  629. sis_drives.partition_mount_name(me->partition_index)));
  630. ASSERT(me->log_extractor_dead);
  631. me->remaining_restart_extraction_interval -=
  632. __min(me->remaining_restart_extraction_interval,
  633. me->max_extraction_interval);
  634. TRACE_PRINTF(TC_partctrl, 4, (_T("\tPCre -\tremaining restart extraction interval = %d\n"),
  635. me->remaining_restart_extraction_interval));
  636. if (!me->groveler_dead && me->remaining_restart_extraction_interval == 0)
  637. {
  638. TRACE_PRINTF(TC_partctrl, 2, (_T("time: %d\n"), invokation_time));
  639. TRACE_PRINTF(TC_partctrl, 2,
  640. (_T("\tPCre -\tattempting restart extraction on drive %s\n"),
  641. sis_drives.partition_mount_name(me->partition_index)));
  642. // Disabled this message since it serves no purpose, nealch 4/17/02
  643. // eventlog.report_event(GROVMSG_USN_LOG_RETRY, ERROR_SUCCESS,
  644. // 1,sis_drives.partition_mount_name(me->partition_index));
  645. DWORD lstatus = me->groveler->set_usn_log_size(me->current_usn_log_size);
  646. if (lstatus == ERROR_SUCCESS)
  647. {
  648. TRACE_PRINTF(TC_partctrl, 2,
  649. (_T("\tPCre -\tset_usn_log_size() returned success\n")));
  650. _TCHAR size_string[32];
  651. (void)StringCbPrintf(size_string, sizeof(size_string), _T("%d"), me->current_usn_log_size);
  652. eventlog.report_event(GROVMSG_INIT_USN_LOG, ERROR_SUCCESS,
  653. 2,
  654. sis_drives.partition_mount_name(me->partition_index),
  655. size_string);
  656. me->restart_extraction_required = false;
  657. me->log_extractor_dead = false;
  658. me->first_extraction = true;
  659. control_extraction(context);
  660. return;
  661. }
  662. else
  663. {
  664. TRACE_PRINTF(TC_partctrl, 3,
  665. (_T("\tPCre -\tset_usn_log_size() returned error, status=%d\n"),lstatus));
  666. ASSERT(lstatus != ERROR_SUCCESS);
  667. me->remaining_restart_extraction_interval =
  668. me->restart_extraction_interval;
  669. TRACE_PRINTF(TC_partctrl, 4,
  670. (_T("\tPCre -\tremaining restart extraction interval = %d\n"),
  671. me->remaining_restart_extraction_interval));
  672. me->restart_extraction_interval *= 2;
  673. if (me->restart_extraction_interval >
  674. me->max_restart_extraction_interval)
  675. {
  676. me->restart_extraction_interval =
  677. me->max_restart_extraction_interval;
  678. }
  679. TRACE_PRINTF(TC_partctrl, 4,
  680. (_T("\tPCre -\tnext restart extraction interval = %d\n"),
  681. me->restart_extraction_interval));
  682. }
  683. }
  684. event_timer.schedule(invokation_time + me->max_extraction_interval,
  685. context, restart_extraction);
  686. }
  687. void
  688. PartitionController::restart_groveling(
  689. void *context)
  690. {
  691. ASSERT(context != 0);
  692. unsigned int invokation_time = GET_TICK_COUNT();
  693. TRACE_PRINTF(TC_partctrl, 2, (_T("time: %d\n"), invokation_time));
  694. PartitionController *me = (PartitionController *)context;
  695. TRACE_PRINTF(TC_partctrl, 2,
  696. (_T("\tPCrg -\tattempting to restart groveler on drive %s\n"),
  697. sis_drives.partition_mount_name(me->partition_index)));
  698. ASSERT(me->groveler_dead);
  699. me->groveler->close();
  700. eventlog.report_event(GROVMSG_GROVELER_RETRY, ERROR_SUCCESS,
  701. 1,sis_drives.partition_mount_name(me->partition_index));
  702. GrovelStatus status = me->groveler->open(
  703. sis_drives.partition_guid_name(me->partition_index),
  704. sis_drives.partition_mount_name(me->partition_index),
  705. me->partition_index == log_drive->drive_index(),
  706. me->read_report_discard_threshold,
  707. me->min_file_size,
  708. me->min_file_age,
  709. me->allow_compressed_files,
  710. me->allow_encrypted_files,
  711. me->allow_hidden_files,
  712. me->allow_offline_files,
  713. me->allow_temporary_files,
  714. GrovelAllPaths,
  715. me->num_excluded_paths,
  716. me->excluded_paths,
  717. me->base_regrovel_interval,
  718. me->max_regrovel_interval);
  719. if (status == Grovel_ok)
  720. {
  721. TRACE_PRINTF(TC_partctrl, 2,
  722. (_T("\tPCrg -\topen() returned ok\n")));
  723. log_drive->partition_initialized(me->partition_index);
  724. eventlog.report_event(GROVMSG_GROVELER_STARTED, ERROR_SUCCESS,
  725. 1,sis_drives.partition_mount_name(me->partition_index));
  726. }
  727. else if (status == Grovel_new)
  728. {
  729. TRACE_PRINTF(TC_partctrl, 2,
  730. (_T("\tPCrg -\topen() returned new\n")));
  731. }
  732. else
  733. {
  734. ASSERT(status == Grovel_error);
  735. TRACE_PRINTF(TC_partctrl, 3,
  736. (_T("\tPCrg -\topen() returned error\n")));
  737. }
  738. me->restart_volume_scan = true;
  739. me->initialize_groveling(status);
  740. }
  741. void
  742. PartitionController::update_partition_info(
  743. void *context)
  744. {
  745. ASSERT(context != 0);
  746. unsigned int invokation_time = GET_TICK_COUNT();
  747. TRACE_PRINTF(TC_partctrl, 3, (_T("time: %d\n"), invokation_time));
  748. PartitionController *me = (PartitionController *)context;
  749. TRACE_PRINTF(TC_partctrl, 3,
  750. (_T("\tPCupi -\tupdating partition info for drive %s\n"),
  751. sis_drives.partition_mount_name(me->partition_index)));
  752. ULARGE_INTEGER my_free_bytes;
  753. ULARGE_INTEGER total_bytes;
  754. ULARGE_INTEGER free_bytes;
  755. int ok = GetDiskFreeSpaceEx(
  756. sis_drives.partition_guid_name(me->partition_index),
  757. &my_free_bytes, &total_bytes, &free_bytes);
  758. if (ok)
  759. {
  760. me->volume_total_bytes = double(__int64(total_bytes.QuadPart));
  761. me->volume_free_bytes = double(__int64(free_bytes.QuadPart));
  762. ASSERT(me->volume_total_bytes > 0.0);
  763. ASSERT(me->volume_free_bytes >= 0.0);
  764. TRACE_PRINTF(TC_partctrl, 4, (_T("\tPCupi -\tvolume total bytes = %f\n"),
  765. me->volume_total_bytes));
  766. TRACE_PRINTF(TC_partctrl, 4, (_T("\tPCupi -\tvolume free bytes = %f\n"),
  767. me->volume_free_bytes));
  768. }
  769. else
  770. {
  771. TRACE_PRINTF(TC_partctrl, 3, (_T("\tPCupi -\tGetDiskFreeSpaceEx() returned error.\n")));
  772. DWORD err = GetLastError();
  773. PRINT_DEBUG_MSG((_T("GROVELER: GetDiskFreeSpaceEx() failed with error %d\n"),
  774. err));
  775. }
  776. ASSERT(me->partition_info_update_interval > 0);
  777. event_timer.schedule(invokation_time + me->partition_info_update_interval,
  778. context, update_partition_info);
  779. }
  780. void
  781. PartitionController::initialize_groveling(
  782. GrovelStatus groveler_status)
  783. {
  784. ASSERT(this != 0);
  785. unsigned int invokation_time = GET_TICK_COUNT();
  786. TRACE_PRINTF(TC_partctrl, 3, (_T("time: %d\n"), invokation_time));
  787. TRACE_PRINTF(TC_partctrl, 3,
  788. (_T("\tPCig -\tinitializing groveling for drive %s\n"),
  789. sis_drives.partition_mount_name(partition_index)));
  790. if (groveler_status == Grovel_ok || groveler_status == Grovel_new)
  791. {
  792. TRACE_PRINTF(TC_partctrl, 3,
  793. (_T("\tPCig -\tgroveler_status indicates success\n")));
  794. groveler_dead = false;
  795. DWORD serial_number;
  796. int ok = GetVolumeInformation(
  797. sis_drives.partition_guid_name(partition_index),
  798. 0, 0, &serial_number, 0, 0, 0, 0);
  799. if (!ok)
  800. {
  801. DWORD err = GetLastError();
  802. TRACE_PRINTF(TC_partctrl, 3,
  803. (_T("\tPCig -\tGetVolumeInformation() returned error %d\n"),
  804. err));
  805. PRINT_DEBUG_MSG((_T("GROVELER: GetVolumeInformation() failed with error %d\n"),
  806. err));
  807. }
  808. else
  809. {
  810. TRACE_PRINTF(TC_partctrl, 5,
  811. (_T("\tPCig -\tGetVolumeInformation() returned ")
  812. _T("serial number %d\n"), serial_number));
  813. TRACE_PRINTF(TC_partctrl, 5,
  814. (_T("\tPCig -\trecorded serial number is %d\n"),
  815. *volume_serial_number));
  816. if (volume_serial_number == 0)
  817. {
  818. TRACE_PRINTF(TC_partctrl, 3,
  819. (_T("\tPCig -\tGetVolumeInformation() returned ")
  820. _T("serial number 0\n")));
  821. PRINT_DEBUG_MSG((_T("GROVELER: GetVolumeInformation() returned ")
  822. _T("volume serial number 0\n")));
  823. }
  824. }
  825. if (ok && int(serial_number) != *volume_serial_number)
  826. {
  827. TRACE_PRINTF(TC_partctrl, 5,
  828. (_T("\tPCig -\tresetting read time filters\n")));
  829. read_time_filter[RT_hash]->reset();
  830. read_time_filter[RT_compare]->reset();
  831. read_time_confidence_estimator.reset();
  832. *read_time_estimate[RT_hash] =
  833. read_time_filter[RT_hash]->retrieve_value();
  834. ASSERT(*read_time_estimate[RT_hash] == 0.0);
  835. *read_time_estimate[RT_compare] =
  836. read_time_filter[RT_compare]->retrieve_value();
  837. ASSERT(*read_time_estimate[RT_compare] == 0.0);
  838. *read_time_confidence = read_time_confidence_estimator.confidence();
  839. ASSERT(*read_time_confidence == 0.0);
  840. *volume_serial_number = serial_number;
  841. }
  842. extraction_interval = max_extraction_interval;
  843. free_space_ratio = 0.0;
  844. calculate_effective_max_grovel_interval();
  845. ASSERT(effective_max_grovel_interval > 0);
  846. ASSERT(effective_max_grovel_interval <= max_grovel_interval);
  847. grovel_interval = base_grovel_interval;
  848. remaining_grovel_interval = grovel_interval;
  849. ok_to_record_measurement = true;
  850. next_untrusted_measurement_time = invokation_time;
  851. restart_extraction_required = true;
  852. if (groveler_status == Grovel_new)
  853. {
  854. TRACE_PRINTF(TC_partctrl, 4,
  855. (_T("\tPCig -\tinitiating full volume scan\n")));
  856. initiate_full_volume_scan = true;
  857. performing_full_volume_scan = false;
  858. extended_restart_in_progress = true;
  859. }
  860. else
  861. {
  862. TRACE_PRINTF(TC_partctrl, 4,
  863. (_T("\tPCig -\tcontinuing full volume scan\n")));
  864. initiate_full_volume_scan = false;
  865. performing_full_volume_scan = true;
  866. extended_restart_in_progress = false;
  867. restart_groveling_interval = base_restart_groveling_interval;
  868. }
  869. TRACE_PRINTF(TC_partctrl, 5,
  870. (_T("\tPCig -\trestart groveling interval = %d\n"),
  871. restart_groveling_interval));
  872. }
  873. else
  874. {
  875. TRACE_PRINTF(TC_partctrl, 3,
  876. (_T("\tPCig -\tgroveler_status indicates error or disable\n")));
  877. ASSERT(groveler_status == Grovel_error
  878. || groveler_status == Grovel_disable);
  879. groveler_dead = true;
  880. if (groveler_status != Grovel_disable && error_retry_groveling)
  881. {
  882. TRACE_PRINTF(TC_partctrl, 5,
  883. (_T("\tPCig -\tscheduling restart groveling\n")));
  884. TRACE_PRINTF(TC_partctrl, 5,
  885. (_T("\tPCig -\trestart groveling interval = %d\n"),
  886. restart_groveling_interval));
  887. event_timer.schedule(invokation_time + restart_groveling_interval,
  888. (void *)this, restart_groveling);
  889. }
  890. restart_groveling_interval *= 2;
  891. if (restart_groveling_interval > max_restart_groveling_interval)
  892. {
  893. restart_groveling_interval = max_restart_groveling_interval;
  894. }
  895. TRACE_PRINTF(TC_partctrl, 5,
  896. (_T("\tPCig -\tnext restart groveling interval = %d\n"),
  897. restart_groveling_interval));
  898. }
  899. }
  900. bool
  901. PartitionController::control_groveling(
  902. DWORD grovel_duration,
  903. DWORD *count_of_files_hashed,
  904. DWORDLONG *bytes_of_files_hashed,
  905. DWORD *count_of_files_matching,
  906. DWORDLONG *bytes_of_files_matching,
  907. DWORD *count_of_files_compared,
  908. DWORDLONG *bytes_of_files_compared,
  909. DWORD *count_of_files_merged,
  910. DWORDLONG *bytes_of_files_merged,
  911. DWORD *count_of_files_enqueued,
  912. DWORD *count_of_files_dequeued,
  913. double cpu_load)
  914. {
  915. ASSERT(this != 0);
  916. ASSERT(grovel_duration > 0);
  917. ASSERT(count_of_files_hashed != 0);
  918. ASSERT(bytes_of_files_hashed != 0);
  919. ASSERT(count_of_files_matching != 0);
  920. ASSERT(bytes_of_files_matching != 0);
  921. ASSERT(count_of_files_compared != 0);
  922. ASSERT(bytes_of_files_compared != 0);
  923. ASSERT(count_of_files_merged != 0);
  924. ASSERT(bytes_of_files_merged != 0);
  925. ASSERT(count_of_files_enqueued != 0);
  926. ASSERT(count_of_files_dequeued != 0);
  927. ASSERT(cpu_load >= 0.0);
  928. ASSERT(cpu_load <= 1.0);
  929. ASSERT(!groveler_dead);
  930. unsigned int invokation_time = GET_TICK_COUNT();
  931. TRACE_PRINTF(TC_partctrl, 2,
  932. (_T("time: %d\n"), invokation_time));
  933. TRACE_PRINTF(TC_partctrl, 2, (_T("\tPCcg -\tgroveling on drive %s\n"),
  934. sis_drives.partition_mount_name(partition_index)));
  935. DWORD hash_read_ops;
  936. DWORD hash_read_time;
  937. DWORD compare_read_ops;
  938. DWORD compare_read_time;
  939. DWORD merge_time;
  940. GrovelStatus status = groveler->grovel(grovel_duration,
  941. &hash_read_ops, &hash_read_time,
  942. count_of_files_hashed, bytes_of_files_hashed,
  943. &compare_read_ops, &compare_read_time,
  944. count_of_files_compared, bytes_of_files_compared,
  945. count_of_files_matching, bytes_of_files_matching,
  946. &merge_time,
  947. count_of_files_merged, bytes_of_files_merged,
  948. count_of_files_enqueued, count_of_files_dequeued);
  949. unsigned int completion_time = GET_TICK_COUNT();
  950. if (status != Grovel_ok && status != Grovel_pending)
  951. {
  952. ASSERT(status == Grovel_error);
  953. *count_of_files_hashed = 0;
  954. *bytes_of_files_hashed = 0;
  955. *count_of_files_matching = 0;
  956. *bytes_of_files_matching = 0;
  957. *count_of_files_compared = 0;
  958. *bytes_of_files_compared = 0;
  959. *count_of_files_merged = 0;
  960. *bytes_of_files_merged = 0;
  961. *count_of_files_enqueued = 0;
  962. *count_of_files_dequeued = 0;
  963. TRACE_PRINTF(TC_partctrl, 1,
  964. (_T("\tPCcg -\tgrovel() returned error -- groveler dead\n")));
  965. eventlog.report_event(GROVMSG_GROVELER_DEAD, ERROR_SUCCESS,
  966. 1,sis_drives.partition_mount_name(partition_index));
  967. groveler_dead = true;
  968. if (error_retry_groveling)
  969. {
  970. restart_groveling_interval = base_restart_groveling_interval;
  971. event_timer.schedule(invokation_time + restart_groveling_interval,
  972. (void *)this, restart_groveling);
  973. return true;
  974. }
  975. else
  976. {
  977. return false;
  978. }
  979. }
  980. ASSERT(hash_read_ops > 0 || hash_read_time == 0);
  981. ASSERT(compare_read_ops > 0 || compare_read_time == 0);
  982. ASSERT(*bytes_of_files_hashed >= *count_of_files_hashed);
  983. ASSERT(*bytes_of_files_matching >= *count_of_files_matching);
  984. ASSERT(*bytes_of_files_compared >= *count_of_files_compared);
  985. ASSERT(*bytes_of_files_merged >= *count_of_files_merged);
  986. ASSERT(*count_of_files_hashed >= *count_of_files_matching);
  987. ASSERT(*bytes_of_files_hashed >= *bytes_of_files_matching);
  988. ASSERT(*count_of_files_compared >= *count_of_files_merged);
  989. ASSERT(*bytes_of_files_compared >= *bytes_of_files_merged);
  990. ASSERT(*count_of_files_dequeued >= *count_of_files_hashed);
  991. unsigned int grovel_time = completion_time - invokation_time;
  992. ASSERT(signed(grovel_time) >= 0);
  993. shared_data->increment_value(partition_index,
  994. SDF_grovel_time, grovel_time);
  995. shared_data->increment_value(partition_index,
  996. SDF_working_time, grovel_time);
  997. shared_data->increment_value(partition_index,
  998. SDF_files_hashed, *count_of_files_hashed);
  999. shared_data->increment_value(partition_index,
  1000. SDF_files_compared, *count_of_files_compared);
  1001. shared_data->increment_value(partition_index,
  1002. SDF_files_merged, *count_of_files_merged);
  1003. int files_in_queue = groveler->count_of_files_in_queue();
  1004. ASSERT(files_in_queue >= 0);
  1005. int files_to_compare = groveler->count_of_files_to_compare();
  1006. ASSERT(files_to_compare >= 0);
  1007. shared_data->set_value(partition_index, SDF_queue_length, files_in_queue);
  1008. TRACE_PRINTF(TC_partctrl, 4,
  1009. (_T("\tPCcg -\thash read ops = %d\n"), hash_read_ops));
  1010. TRACE_PRINTF(TC_partctrl, 4,
  1011. (_T("\tPCcg -\thash read time = %d\n"), hash_read_time));
  1012. TRACE_PRINTF(TC_partctrl, 4,
  1013. (_T("\tPCcg -\tcompare read ops = %d\n"), compare_read_ops));
  1014. TRACE_PRINTF(TC_partctrl, 4,
  1015. (_T("\tPCcg -\tcompare read time = %d\n"), compare_read_time));
  1016. shared_data->increment_value(partition_index,
  1017. SDF_hash_read_time, hash_read_time);
  1018. shared_data->increment_value(partition_index,
  1019. SDF_hash_read_ops, hash_read_ops);
  1020. shared_data->increment_value(partition_index,
  1021. SDF_compare_read_time, compare_read_time);
  1022. shared_data->increment_value(partition_index,
  1023. SDF_compare_read_ops, compare_read_ops);
  1024. update_peak_finder(RT_hash, hash_read_time, hash_read_ops);
  1025. update_peak_finder(RT_compare, compare_read_time, compare_read_ops);
  1026. shared_data->set_value(partition_index,
  1027. SDF_hash_read_estimate, __int64(*read_time_estimate[RT_hash]));
  1028. shared_data->set_value(partition_index,
  1029. SDF_compare_read_estimate, __int64(*read_time_estimate[RT_compare]));
  1030. int count_of_files_groveled =
  1031. *count_of_files_hashed + *count_of_files_compared;
  1032. ASSERT(mean_file_size != 0);
  1033. if (count_of_files_groveled > 0)
  1034. {
  1035. __int64 bytes_of_files_groveled =
  1036. *bytes_of_files_hashed + *bytes_of_files_compared;
  1037. double sample_mean_file_size =
  1038. double(bytes_of_files_groveled) / double(count_of_files_groveled);
  1039. ASSERT(sample_mean_file_size > 0.0);
  1040. file_size_filter.update_value(sample_mean_file_size,
  1041. count_of_files_groveled);
  1042. *mean_file_size = file_size_filter.retrieve_value();
  1043. ASSERT(*mean_file_size > 0.0);
  1044. }
  1045. ASSERT(dequeue_hash_ratio != 0);
  1046. ASSERT(*dequeue_hash_ratio >= 0.0);
  1047. ASSERT(*dequeue_hash_ratio <= 1.0);
  1048. double files_to_hash = *dequeue_hash_ratio * double(files_in_queue);
  1049. ASSERT(*mean_file_size >= 0.0);
  1050. double bytes_to_hash = *mean_file_size * files_to_hash;
  1051. double bytes_to_compare = *mean_file_size * double(files_to_compare);
  1052. double expected_bytes_to_free = *compare_match_ratio *
  1053. (bytes_to_compare + *hash_match_ratio * bytes_to_hash);
  1054. double expected_free_bytes = volume_free_bytes + expected_bytes_to_free;
  1055. free_space_ratio = 0;
  1056. if (expected_free_bytes > 0)
  1057. {
  1058. free_space_ratio = expected_bytes_to_free / expected_free_bytes;
  1059. }
  1060. ASSERT(free_space_ratio >= 0.0);
  1061. ASSERT(free_space_ratio <= 1.0);
  1062. calculate_effective_max_grovel_interval();
  1063. ASSERT(effective_max_grovel_interval > 0);
  1064. ASSERT(effective_max_grovel_interval <= max_grovel_interval);
  1065. double use_multiplier =
  1066. base_use_multiplier + use_multiplier_slope * free_space_ratio;
  1067. ASSERT(use_multiplier >= 0.0);
  1068. TRACE_PRINTF(TC_partctrl, 5,
  1069. (_T("\tPCcg -\tuse multiplier = %f\n"), use_multiplier));
  1070. double hash_comparison_time = use_multiplier * *read_time_estimate[RT_hash];
  1071. ASSERT(hash_comparison_time >= 0.0);
  1072. double compare_comparison_time =
  1073. use_multiplier * *read_time_estimate[RT_compare];
  1074. ASSERT(compare_comparison_time >= 0.0);
  1075. TRACE_PRINTF(TC_partctrl, 5,
  1076. (_T("\tPCcg -\thash comparison time = %f\n"), hash_comparison_time));
  1077. TRACE_PRINTF(TC_partctrl, 5,
  1078. (_T("\tPCcg -\tcompare comparison time = %f\n"),
  1079. compare_comparison_time));
  1080. TRACE_PRINTF(TC_partctrl, 5, (_T("\tPCcg -\tcpu load = %f\n"), cpu_load));
  1081. double cpu_load_threshold = base_cpu_load_threshold +
  1082. cpu_load_threshold_slope * free_space_ratio;
  1083. TRACE_PRINTF(TC_partctrl, 5,
  1084. (_T("\tPCcg -\tcpu load threshold = %f\n"), cpu_load_threshold));
  1085. ASSERT(cpu_load_threshold >= 0.0);
  1086. ASSERT(cpu_load_threshold <= 1.0);
  1087. if (cpu_load > cpu_load_threshold || read_mean_comparator.exceeds(
  1088. hash_comparison_time, compare_comparison_time))
  1089. {
  1090. TRACE_PRINTF(TC_partctrl, 3,
  1091. (_T("\tPCcg -\tread time exceeds acceptable bounds\n")));
  1092. TRACE_PRINTF(TC_partctrl, 3,
  1093. (_T("\t\tor CPU load exceeds threshold\n")));
  1094. ASSERT(grovel_interval > 0);
  1095. remaining_grovel_interval = grovel_interval;
  1096. read_mean_comparator.reset();
  1097. grovel_interval *= 2;
  1098. ok_to_record_measurement = false;
  1099. }
  1100. else if (read_mean_comparator.within(hash_comparison_time,
  1101. compare_comparison_time))
  1102. {
  1103. TRACE_PRINTF(TC_partctrl, 3,
  1104. (_T("\tPCcg -\tread time within acceptable bounds\n")));
  1105. ASSERT(base_grovel_interval > 0);
  1106. grovel_interval = base_grovel_interval;
  1107. ok_to_record_measurement = true;
  1108. }
  1109. if (grovel_interval > effective_max_grovel_interval)
  1110. {
  1111. ASSERT(effective_max_grovel_interval > 0);
  1112. grovel_interval = effective_max_grovel_interval;
  1113. }
  1114. TRACE_PRINTF(TC_partctrl, 4, (_T("\tPCcg -\tgrovel interval = %d\n"), grovel_interval));
  1115. TRACE_PRINTF(TC_partctrl, 4, (_T("\tPCcg -\tremaining grovel interval = %d\n"),
  1116. remaining_grovel_interval));
  1117. return true;
  1118. }
  1119. bool
  1120. PartitionController::control_volume_scan(
  1121. int scan_duration,
  1122. DWORD *count_of_files_enqueued)
  1123. {
  1124. ASSERT(this != 0);
  1125. ASSERT(scan_duration > 0);
  1126. ASSERT(count_of_files_enqueued != 0);
  1127. ASSERT(!groveler_dead);
  1128. unsigned int invokation_time = GET_TICK_COUNT();
  1129. TRACE_PRINTF(TC_partctrl, 2, (_T("time: %d\n"), invokation_time));
  1130. TRACE_PRINTF(TC_partctrl, 2,
  1131. (_T("\tPCcvs -\tscanning volume on drive %s\n"),
  1132. sis_drives.partition_mount_name(partition_index)));
  1133. DWORD time_consumed;
  1134. DWORD findfirst_count;
  1135. DWORD findnext_count;
  1136. GrovelStatus status = groveler->scan_volume(scan_duration,
  1137. restart_volume_scan, &time_consumed, &findfirst_count, &findnext_count,
  1138. count_of_files_enqueued);
  1139. unsigned int completion_time = GET_TICK_COUNT();
  1140. if (status == Grovel_ok || status == Grovel_pending)
  1141. {
  1142. if (extended_restart_in_progress)
  1143. {
  1144. log_drive->partition_initialized(partition_index);
  1145. eventlog.report_event(GROVMSG_GROVELER_STARTED, ERROR_SUCCESS,
  1146. 1,sis_drives.partition_mount_name(partition_index));
  1147. extended_restart_in_progress = false;
  1148. }
  1149. if (status == Grovel_ok)
  1150. {
  1151. TRACE_PRINTF(TC_partctrl, 1,
  1152. (_T("\tPCcvs -\tcompleted volume scan\n")));
  1153. performing_full_volume_scan = false;
  1154. }
  1155. }
  1156. else
  1157. {
  1158. ASSERT(status == Grovel_error);
  1159. *count_of_files_enqueued = 0;
  1160. TRACE_PRINTF(TC_partctrl, 1,
  1161. (_T("\tPCcvs -\tscan_volume() returned error -- groveler dead\n")));
  1162. if (!extended_restart_in_progress)
  1163. {
  1164. eventlog.report_event(GROVMSG_GROVELER_DEAD, ERROR_SUCCESS,
  1165. 1,sis_drives.partition_mount_name(partition_index));
  1166. }
  1167. groveler_dead = true;
  1168. if (error_retry_groveling)
  1169. {
  1170. if (!extended_restart_in_progress)
  1171. {
  1172. restart_groveling_interval = base_restart_groveling_interval;
  1173. }
  1174. event_timer.schedule(invokation_time + restart_groveling_interval,
  1175. (void *)this, restart_groveling);
  1176. if (extended_restart_in_progress)
  1177. {
  1178. restart_groveling_interval *= 2;
  1179. if (restart_groveling_interval > max_restart_groveling_interval)
  1180. {
  1181. restart_groveling_interval = max_restart_groveling_interval;
  1182. }
  1183. extended_restart_in_progress = false;
  1184. }
  1185. return true;
  1186. }
  1187. else
  1188. {
  1189. extended_restart_in_progress = false;
  1190. return false;
  1191. }
  1192. }
  1193. ASSERT(signed(time_consumed) >= 0);
  1194. ASSERT(signed(findfirst_count) >= 0);
  1195. ASSERT(signed(findnext_count) >= 0);
  1196. ASSERT(signed(*count_of_files_enqueued) >= 0);
  1197. unsigned int scan_time = completion_time - invokation_time;
  1198. ASSERT(signed(scan_time) >= 0);
  1199. shared_data->increment_value(partition_index, SDF_volscan_time, scan_time);
  1200. shared_data->increment_value(partition_index, SDF_working_time, scan_time);
  1201. shared_data->increment_value(partition_index,
  1202. SDF_files_scanned, findfirst_count + findnext_count);
  1203. int queue_length = groveler->count_of_files_in_queue();
  1204. ASSERT(queue_length >= 0);
  1205. shared_data->set_value(partition_index, SDF_queue_length, queue_length);
  1206. restart_volume_scan = false;
  1207. TRACE_PRINTF(TC_partctrl, 4,
  1208. (_T("\tPCcvs -\ttime consumed = %d\n"), time_consumed));
  1209. TRACE_PRINTF(TC_partctrl, 4,
  1210. (_T("\tPCcvs -\tfindfirst count = %d\n"), findfirst_count));
  1211. TRACE_PRINTF(TC_partctrl, 4,
  1212. (_T("\tPCcvs -\tfindnext count = %d\n"), findnext_count));
  1213. TRACE_PRINTF(TC_partctrl, 4,
  1214. (_T("\tPCcvs -\tcount of files enqueued = %d\n"),
  1215. *count_of_files_enqueued));
  1216. return true;
  1217. }
  1218. void
  1219. PartitionController::update_peak_finder(
  1220. ReadType read_type,
  1221. DWORD read_time,
  1222. DWORD read_ops)
  1223. {
  1224. ASSERT(this != 0);
  1225. unsigned int invokation_time = GET_TICK_COUNT();
  1226. TRACE_PRINTF(TC_partctrl, 3, (_T("time: %d\n"), invokation_time));
  1227. TRACE_PRINTF(TC_partctrl, 3,
  1228. (_T("\tPCupf -\tupdating peak finder for drive %s\n"),
  1229. sis_drives.partition_mount_name(partition_index)));
  1230. ASSERT(read_type == RT_hash || read_type == RT_compare);
  1231. ASSERT(signed(read_time) >= 0);
  1232. ASSERT(signed(read_ops) >= 0);
  1233. if (read_ops > 0)
  1234. {
  1235. double time_per_read = double(read_time)/double(read_ops);
  1236. ASSERT(time_per_read >= 0.0);
  1237. TRACE_PRINTF(TC_partctrl, 4, (_T("\tPCupf -\ttime per %s read = %f\n"),
  1238. (read_type == RT_hash ? _T("hash") : _T("compare")),
  1239. time_per_read));
  1240. read_mean_comparator.sample(read_type, time_per_read);
  1241. ASSERT(read_peak_finder[read_type] != 0);
  1242. ASSERT(read_time_filter[read_type] != 0);
  1243. ASSERT(read_time_estimate[read_type] != 0);
  1244. ASSERT(read_time_confidence != 0);
  1245. if (ok_to_record_measurement ||
  1246. signed(invokation_time - next_untrusted_measurement_time) >= 0)
  1247. {
  1248. TRACE_PRINTF(TC_partctrl, 2,
  1249. (_T("\tPCupf -\trecording %s measurement for drive %s\n"),
  1250. (read_type == RT_hash ? _T("hash") : _T("compare")),
  1251. sis_drives.partition_mount_name(partition_index)));
  1252. read_peak_finder[read_type]->sample(time_per_read, read_ops);
  1253. ASSERT(untrusted_measurement_interval > 0);
  1254. ok_to_record_measurement = true;
  1255. next_untrusted_measurement_time =
  1256. invokation_time + untrusted_measurement_interval;
  1257. TRACE_PRINTF(TC_partctrl, 5,
  1258. (_T("\tPCupf -\tnext untrusted measurement time = %d\n"),
  1259. next_untrusted_measurement_time));
  1260. }
  1261. if (read_peak_finder[read_type]->found())
  1262. {
  1263. double peak = read_peak_finder[read_type]->median();
  1264. TRACE_PRINTF(TC_partctrl, 1,
  1265. (_T("\tPCupf -\t%s read peak found: %f\n"),
  1266. (read_type == RT_hash ? _T("hash") : _T("compare")), peak));
  1267. if (peak > 0.0)
  1268. {
  1269. read_time_filter[read_type]->update_value(peak);
  1270. }
  1271. else
  1272. {
  1273. PRINT_DEBUG_MSG((_T("GROVELER: update_peak_finder() peak finder returned peak of zero\n")));
  1274. }
  1275. read_peak_finder[read_type]->reset();
  1276. *read_time_estimate[read_type] =
  1277. read_time_filter[read_type]->retrieve_value();
  1278. ASSERT(*read_time_estimate[read_type] > 0.0);
  1279. TRACE_PRINTF(TC_partctrl, 2,
  1280. (_T("\tPCupf -\t%s read time estimate = %f\n"),
  1281. (read_type == RT_hash ? _T("hash") : _T("compare")),
  1282. *read_time_estimate[read_type]));
  1283. double sample_peak_ratio = *read_time_estimate[read_type] / peak;
  1284. double sample_read_time_confidence =
  1285. (sample_peak_ratio + peak_finder_accuracy - 1.0) /
  1286. peak_finder_accuracy;
  1287. TRACE_PRINTF(TC_partctrl, 4,
  1288. (_T("\tPCupf -\tsample read time confidence = %f\n"),
  1289. sample_read_time_confidence));
  1290. read_time_confidence_estimator.update(read_type,
  1291. sample_read_time_confidence);
  1292. *read_time_confidence = read_time_confidence_estimator.confidence();
  1293. ASSERT(*read_time_confidence >= 0.0);
  1294. ASSERT(*read_time_confidence <= 1.0);
  1295. TRACE_PRINTF(TC_partctrl, 2,
  1296. (_T("\tPCupf -\tread time confidence = %f\n"),
  1297. *read_time_confidence));
  1298. calculate_effective_max_grovel_interval();
  1299. ASSERT(effective_max_grovel_interval > 0);
  1300. ASSERT(effective_max_grovel_interval <= max_grovel_interval);
  1301. }
  1302. }
  1303. }
  1304. void
  1305. PartitionController::calculate_effective_max_grovel_interval()
  1306. {
  1307. ASSERT(this != 0);
  1308. ASSERT(read_time_confidence != 0);
  1309. ASSERT(*read_time_confidence >= 0.0);
  1310. ASSERT(*read_time_confidence <= 1.0);
  1311. TRACE_PRINTF(TC_partctrl, 4,
  1312. (_T("\tPCcemgi -\tread time confidence = %f\n"),
  1313. *read_time_confidence));
  1314. TRACE_PRINTF(TC_partctrl, 5,
  1315. (_T("\tPCcemgi -\tfree space ratio = %f\n"), free_space_ratio));
  1316. double log_untrusted_measurement_interval = log_max_grovel_interval -
  1317. (1.0 - *read_time_confidence) * log_low_confidence_slope;
  1318. untrusted_measurement_interval =
  1319. int(exp(log_untrusted_measurement_interval));
  1320. ASSERT(untrusted_measurement_interval > 0);
  1321. TRACE_PRINTF(TC_partctrl, 5,
  1322. (_T("\tPCcemgi -\tuntrusted measurement interval = %d\n"),
  1323. untrusted_measurement_interval));
  1324. int low_disk_space_interval = max_grovel_interval -
  1325. int(free_space_ratio * low_disk_space_slope);
  1326. ASSERT(low_disk_space_interval > 0);
  1327. effective_max_grovel_interval =
  1328. __min(untrusted_measurement_interval, low_disk_space_interval);
  1329. ASSERT(effective_max_grovel_interval > 0);
  1330. ASSERT(effective_max_grovel_interval <= max_grovel_interval);
  1331. TRACE_PRINTF(TC_partctrl, 5,
  1332. (_T("\tPCcemgi -\teffective max grovel interval = %d\n"),
  1333. effective_max_grovel_interval));
  1334. }