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.

1362 lines
48 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, 1,
  500. 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. _stprintf(size_string, _T("%d"), usn_log_size);
  517. eventlog.report_event(GROVMSG_SET_USN_LOG_SIZE, 2,
  518. sis_drives.partition_mount_name(me->partition_index),
  519. size_string);
  520. TRACE_PRINTF(TC_partctrl, 2,
  521. (_T("\tPCce -\tincreasing USN log size from %d to %d\n"),
  522. me->current_usn_log_size, usn_log_size));
  523. me->current_usn_log_size = usn_log_size;
  524. GrovelStatus status = me->groveler->set_usn_log_size(usn_log_size);
  525. if (status == Grovel_error)
  526. {
  527. TRACE_PRINTF(TC_partctrl, 1,
  528. (_T("\tPCce -\tset_usn_log_size() returned error\n")));
  529. TRACE_PRINTF(TC_partctrl, 1,
  530. (_T("\t\tsuspending control_extraction()\n")));
  531. eventlog.report_event(GROVMSG_LOG_EXTRACTOR_DEAD, 1,
  532. sis_drives.partition_mount_name(me->partition_index));
  533. me->log_extractor_dead = true;
  534. me->restart_extraction_interval =
  535. me->base_restart_extraction_interval;
  536. me->remaining_restart_extraction_interval =
  537. me->restart_extraction_interval;
  538. event_timer.schedule(
  539. completion_time + me->max_extraction_interval,
  540. context, restart_extraction);
  541. return;
  542. }
  543. }
  544. }
  545. }
  546. else if (status != Grovel_ok)
  547. {
  548. ASSERT(status == Grovel_error);
  549. TRACE_PRINTF(TC_partctrl, 1,
  550. (_T("\tPCce -\textract_log() returned error\n")));
  551. TRACE_PRINTF(TC_partctrl, 1,
  552. (_T("\t\tsuspending control_extraction()\n")));
  553. eventlog.report_event(GROVMSG_LOG_EXTRACTOR_DEAD, 1,
  554. sis_drives.partition_mount_name(me->partition_index));
  555. me->log_extractor_dead = true;
  556. me->restart_extraction_interval = me->base_restart_extraction_interval;
  557. me->remaining_restart_extraction_interval =
  558. me->restart_extraction_interval;
  559. event_timer.schedule(completion_time + me->max_extraction_interval,
  560. context, restart_extraction);
  561. return;
  562. }
  563. unsigned int extraction_time = completion_time - invokation_time;
  564. ASSERT(signed(extraction_time) >= 0);
  565. shared_data->increment_value(me->partition_index,
  566. SDF_extract_time, extraction_time);
  567. shared_data->increment_value(me->partition_index,
  568. SDF_working_time, extraction_time);
  569. int queue_length = me->groveler->count_of_files_in_queue();
  570. ASSERT(queue_length >= 0);
  571. shared_data->set_value(me->partition_index, SDF_queue_length, queue_length);
  572. TRACE_PRINTF(TC_partctrl, 4,
  573. (_T("\tPCce -\tnum entries extracted = %d\n"), num_entries_extracted));
  574. TRACE_PRINTF(TC_partctrl, 4,
  575. (_T("\tPCce -\tnum files enqueued = %d\n"), num_files_enqueued));
  576. ASSERT(signed(num_entries_extracted) >= 0);
  577. ASSERT(signed(num_bytes_extracted) >= 0);
  578. ASSERT(signed(num_bytes_skipped) >= 0);
  579. ASSERT(signed(num_files_enqueued) >= 0);
  580. ASSERT(signed(num_files_dequeued) >= 0);
  581. ASSERT(num_bytes_extracted >= num_entries_extracted);
  582. ASSERT(num_files_enqueued <= num_entries_extracted);
  583. ASSERT(status == Grovel_overrun || num_bytes_skipped == 0);
  584. me->first_extraction = false;
  585. if (num_entries_extracted < 1)
  586. {
  587. num_entries_extracted = 1;
  588. }
  589. ASSERT(me->extraction_interval > 0);
  590. ASSERT(me->target_entries_per_extraction > 0);
  591. int ideal_extraction_interval = me->extraction_interval *
  592. me->target_entries_per_extraction / num_entries_extracted + 1;
  593. ASSERT(ideal_extraction_interval > 0);
  594. TRACE_PRINTF(TC_partctrl, 5,
  595. (_T("\tPCce -\tideal extraction interval = %d\n"),
  596. ideal_extraction_interval));
  597. if (ideal_extraction_interval < me->extraction_interval)
  598. {
  599. me->extraction_interval = ideal_extraction_interval;
  600. }
  601. else
  602. {
  603. me->extraction_interval = int(sqrt(double(me->extraction_interval)
  604. * double(ideal_extraction_interval)));
  605. ASSERT(me->max_extraction_interval > 0);
  606. if (me->extraction_interval > me->max_extraction_interval)
  607. {
  608. me->extraction_interval = me->max_extraction_interval;
  609. }
  610. }
  611. TRACE_PRINTF(TC_partctrl, 5,
  612. (_T("\tPCce -\textraction interval = %d\n"), me->extraction_interval));
  613. ASSERT(me->extraction_interval > 0);
  614. ASSERT(me->extraction_interval <= me->max_extraction_interval);
  615. event_timer.schedule(invokation_time + me->extraction_interval,
  616. context, control_extraction);
  617. }
  618. void
  619. PartitionController::restart_extraction(
  620. void *context)
  621. {
  622. ASSERT(context != 0);
  623. unsigned int invokation_time = GET_TICK_COUNT();
  624. TRACE_PRINTF(TC_partctrl, 3, (_T("time: %d\n"), invokation_time));
  625. PartitionController *me = (PartitionController *)context;
  626. TRACE_PRINTF(TC_partctrl, 3,
  627. (_T("\tPCre -\tconsidering restart extraction on drive %s\n"),
  628. sis_drives.partition_mount_name(me->partition_index)));
  629. ASSERT(me->log_extractor_dead);
  630. me->remaining_restart_extraction_interval -=
  631. __min(me->remaining_restart_extraction_interval,
  632. me->max_extraction_interval);
  633. TRACE_PRINTF(TC_partctrl, 4, (_T("\tPCre -\tremaining restart extraction interval = %d\n"),
  634. me->remaining_restart_extraction_interval));
  635. if (!me->groveler_dead && me->remaining_restart_extraction_interval == 0)
  636. {
  637. TRACE_PRINTF(TC_partctrl, 2, (_T("time: %d\n"), invokation_time));
  638. TRACE_PRINTF(TC_partctrl, 2,
  639. (_T("\tPCre -\tattempting restart extraction on drive %s\n"),
  640. sis_drives.partition_mount_name(me->partition_index)));
  641. eventlog.report_event(GROVMSG_USN_LOG_RETRY, 1,
  642. sis_drives.partition_mount_name(me->partition_index));
  643. GrovelStatus status =
  644. me->groveler->set_usn_log_size(me->current_usn_log_size);
  645. if (status == Grovel_ok || status == Grovel_new)
  646. {
  647. TRACE_PRINTF(TC_partctrl, 2,
  648. (_T("\tPCre -\tset_usn_log_size() returned success\n")));
  649. _TCHAR size_string[32];
  650. _stprintf(size_string, _T("%d"), me->current_usn_log_size);
  651. eventlog.report_event(GROVMSG_INIT_USN_LOG, 2,
  652. sis_drives.partition_mount_name(me->partition_index),
  653. size_string);
  654. me->restart_extraction_required = false;
  655. me->log_extractor_dead = false;
  656. me->first_extraction = true;
  657. control_extraction(context);
  658. return;
  659. }
  660. else
  661. {
  662. TRACE_PRINTF(TC_partctrl, 3,
  663. (_T("\tPCre -\tset_usn_log_size() returned error\n")));
  664. ASSERT(status == Grovel_error);
  665. me->remaining_restart_extraction_interval =
  666. me->restart_extraction_interval;
  667. TRACE_PRINTF(TC_partctrl, 4,
  668. (_T("\tPCre -\tremaining restart extraction interval = %d\n"),
  669. me->remaining_restart_extraction_interval));
  670. me->restart_extraction_interval *= 2;
  671. if (me->restart_extraction_interval >
  672. me->max_restart_extraction_interval)
  673. {
  674. me->restart_extraction_interval =
  675. me->max_restart_extraction_interval;
  676. }
  677. TRACE_PRINTF(TC_partctrl, 4,
  678. (_T("\tPCre -\tnext restart extraction interval = %d\n"),
  679. me->restart_extraction_interval));
  680. }
  681. }
  682. event_timer.schedule(invokation_time + me->max_extraction_interval,
  683. context, restart_extraction);
  684. }
  685. void
  686. PartitionController::restart_groveling(
  687. void *context)
  688. {
  689. ASSERT(context != 0);
  690. unsigned int invokation_time = GET_TICK_COUNT();
  691. TRACE_PRINTF(TC_partctrl, 2, (_T("time: %d\n"), invokation_time));
  692. PartitionController *me = (PartitionController *)context;
  693. TRACE_PRINTF(TC_partctrl, 2,
  694. (_T("\tPCrg -\tattempting to restart groveler on drive %s\n"),
  695. sis_drives.partition_mount_name(me->partition_index)));
  696. ASSERT(me->groveler_dead);
  697. me->groveler->close();
  698. eventlog.report_event(GROVMSG_GROVELER_RETRY, 1,
  699. sis_drives.partition_mount_name(me->partition_index));
  700. GrovelStatus status = me->groveler->open(
  701. sis_drives.partition_guid_name(me->partition_index),
  702. sis_drives.partition_mount_name(me->partition_index),
  703. me->partition_index == log_drive->drive_index(),
  704. me->read_report_discard_threshold,
  705. me->min_file_size,
  706. me->min_file_age,
  707. me->allow_compressed_files,
  708. me->allow_encrypted_files,
  709. me->allow_hidden_files,
  710. me->allow_offline_files,
  711. me->allow_temporary_files,
  712. me->num_excluded_paths,
  713. me->excluded_paths,
  714. me->base_regrovel_interval,
  715. me->max_regrovel_interval);
  716. if (status == Grovel_ok)
  717. {
  718. TRACE_PRINTF(TC_partctrl, 2,
  719. (_T("\tPCrg -\topen() returned ok\n")));
  720. log_drive->partition_initialized(me->partition_index);
  721. eventlog.report_event(GROVMSG_GROVELER_STARTED, 1,
  722. sis_drives.partition_mount_name(me->partition_index));
  723. }
  724. else if (status == Grovel_new)
  725. {
  726. TRACE_PRINTF(TC_partctrl, 2,
  727. (_T("\tPCrg -\topen() returned new\n")));
  728. }
  729. else
  730. {
  731. ASSERT(status == Grovel_error);
  732. TRACE_PRINTF(TC_partctrl, 3,
  733. (_T("\tPCrg -\topen() returned error\n")));
  734. }
  735. me->restart_volume_scan = true;
  736. me->initialize_groveling(status);
  737. }
  738. void
  739. PartitionController::update_partition_info(
  740. void *context)
  741. {
  742. ASSERT(context != 0);
  743. unsigned int invokation_time = GET_TICK_COUNT();
  744. TRACE_PRINTF(TC_partctrl, 3, (_T("time: %d\n"), invokation_time));
  745. PartitionController *me = (PartitionController *)context;
  746. TRACE_PRINTF(TC_partctrl, 3,
  747. (_T("\tPCupi -\tupdating partition info for drive %s\n"),
  748. sis_drives.partition_mount_name(me->partition_index)));
  749. ULARGE_INTEGER my_free_bytes;
  750. ULARGE_INTEGER total_bytes;
  751. ULARGE_INTEGER free_bytes;
  752. int ok = GetDiskFreeSpaceEx(
  753. sis_drives.partition_guid_name(me->partition_index),
  754. &my_free_bytes, &total_bytes, &free_bytes);
  755. if (ok)
  756. {
  757. me->volume_total_bytes = double(__int64(total_bytes.QuadPart));
  758. me->volume_free_bytes = double(__int64(free_bytes.QuadPart));
  759. ASSERT(me->volume_total_bytes > 0.0);
  760. ASSERT(me->volume_free_bytes >= 0.0);
  761. TRACE_PRINTF(TC_partctrl, 4, (_T("\tPCupi -\tvolume total bytes = %f\n"),
  762. me->volume_total_bytes));
  763. TRACE_PRINTF(TC_partctrl, 4, (_T("\tPCupi -\tvolume free bytes = %f\n"),
  764. me->volume_free_bytes));
  765. }
  766. else
  767. {
  768. TRACE_PRINTF(TC_partctrl, 3, (_T("\tPCupi -\tGetDiskFreeSpaceEx() returned error.\n")));
  769. DWORD err = GetLastError();
  770. PRINT_DEBUG_MSG((_T("GROVELER: GetDiskFreeSpaceEx() failed with error %d\n"),
  771. err));
  772. }
  773. ASSERT(me->partition_info_update_interval > 0);
  774. event_timer.schedule(invokation_time + me->partition_info_update_interval,
  775. context, update_partition_info);
  776. }
  777. void
  778. PartitionController::initialize_groveling(
  779. GrovelStatus groveler_status)
  780. {
  781. ASSERT(this != 0);
  782. unsigned int invokation_time = GET_TICK_COUNT();
  783. TRACE_PRINTF(TC_partctrl, 3, (_T("time: %d\n"), invokation_time));
  784. TRACE_PRINTF(TC_partctrl, 3,
  785. (_T("\tPCig -\tinitializing groveling for drive %s\n"),
  786. sis_drives.partition_mount_name(partition_index)));
  787. if (groveler_status == Grovel_ok || groveler_status == Grovel_new)
  788. {
  789. TRACE_PRINTF(TC_partctrl, 3,
  790. (_T("\tPCig -\tgroveler_status indicates success\n")));
  791. groveler_dead = false;
  792. DWORD serial_number;
  793. int ok = GetVolumeInformation(
  794. sis_drives.partition_guid_name(partition_index),
  795. 0, 0, &serial_number, 0, 0, 0, 0);
  796. if (!ok)
  797. {
  798. DWORD err = GetLastError();
  799. TRACE_PRINTF(TC_partctrl, 3,
  800. (_T("\tPCig -\tGetVolumeInformation() returned error %d\n"),
  801. err));
  802. PRINT_DEBUG_MSG((_T("GROVELER: GetVolumeInformation() failed with error %d\n"),
  803. err));
  804. }
  805. else
  806. {
  807. TRACE_PRINTF(TC_partctrl, 5,
  808. (_T("\tPCig -\tGetVolumeInformation() returned ")
  809. _T("serial number %d\n"), serial_number));
  810. TRACE_PRINTF(TC_partctrl, 5,
  811. (_T("\tPCig -\trecorded serial number is %d\n"),
  812. *volume_serial_number));
  813. if (volume_serial_number == 0)
  814. {
  815. TRACE_PRINTF(TC_partctrl, 3,
  816. (_T("\tPCig -\tGetVolumeInformation() returned ")
  817. _T("serial number 0\n")));
  818. PRINT_DEBUG_MSG((_T("GROVELER: GetVolumeInformation() returned ")
  819. _T("volume serial number 0\n")));
  820. }
  821. }
  822. if (ok && int(serial_number) != *volume_serial_number)
  823. {
  824. TRACE_PRINTF(TC_partctrl, 5,
  825. (_T("\tPCig -\tresetting read time filters\n")));
  826. read_time_filter[RT_hash]->reset();
  827. read_time_filter[RT_compare]->reset();
  828. read_time_confidence_estimator.reset();
  829. *read_time_estimate[RT_hash] =
  830. read_time_filter[RT_hash]->retrieve_value();
  831. ASSERT(*read_time_estimate[RT_hash] == 0.0);
  832. *read_time_estimate[RT_compare] =
  833. read_time_filter[RT_compare]->retrieve_value();
  834. ASSERT(*read_time_estimate[RT_compare] == 0.0);
  835. *read_time_confidence = read_time_confidence_estimator.confidence();
  836. ASSERT(*read_time_confidence == 0.0);
  837. *volume_serial_number = serial_number;
  838. }
  839. extraction_interval = max_extraction_interval;
  840. free_space_ratio = 0.0;
  841. calculate_effective_max_grovel_interval();
  842. ASSERT(effective_max_grovel_interval > 0);
  843. ASSERT(effective_max_grovel_interval <= max_grovel_interval);
  844. grovel_interval = base_grovel_interval;
  845. remaining_grovel_interval = grovel_interval;
  846. ok_to_record_measurement = true;
  847. next_untrusted_measurement_time = invokation_time;
  848. restart_extraction_required = true;
  849. if (groveler_status == Grovel_new)
  850. {
  851. TRACE_PRINTF(TC_partctrl, 4,
  852. (_T("\tPCig -\tinitiating full volume scan\n")));
  853. initiate_full_volume_scan = true;
  854. performing_full_volume_scan = false;
  855. extended_restart_in_progress = true;
  856. }
  857. else
  858. {
  859. TRACE_PRINTF(TC_partctrl, 4,
  860. (_T("\tPCig -\tcontinuing full volume scan\n")));
  861. initiate_full_volume_scan = false;
  862. performing_full_volume_scan = true;
  863. extended_restart_in_progress = false;
  864. restart_groveling_interval = base_restart_groveling_interval;
  865. }
  866. TRACE_PRINTF(TC_partctrl, 5,
  867. (_T("\tPCig -\trestart groveling interval = %d\n"),
  868. restart_groveling_interval));
  869. }
  870. else
  871. {
  872. TRACE_PRINTF(TC_partctrl, 3,
  873. (_T("\tPCig -\tgroveler_status indicates error or disable\n")));
  874. ASSERT(groveler_status == Grovel_error
  875. || groveler_status == Grovel_disable);
  876. groveler_dead = true;
  877. if (groveler_status != Grovel_disable && error_retry_groveling)
  878. {
  879. TRACE_PRINTF(TC_partctrl, 5,
  880. (_T("\tPCig -\tscheduling restart groveling\n")));
  881. TRACE_PRINTF(TC_partctrl, 5,
  882. (_T("\tPCig -\trestart groveling interval = %d\n"),
  883. restart_groveling_interval));
  884. event_timer.schedule(invokation_time + restart_groveling_interval,
  885. (void *)this, restart_groveling);
  886. }
  887. restart_groveling_interval *= 2;
  888. if (restart_groveling_interval > max_restart_groveling_interval)
  889. {
  890. restart_groveling_interval = max_restart_groveling_interval;
  891. }
  892. TRACE_PRINTF(TC_partctrl, 5,
  893. (_T("\tPCig -\tnext restart groveling interval = %d\n"),
  894. restart_groveling_interval));
  895. }
  896. }
  897. bool
  898. PartitionController::control_groveling(
  899. DWORD grovel_duration,
  900. DWORD *count_of_files_hashed,
  901. DWORDLONG *bytes_of_files_hashed,
  902. DWORD *count_of_files_matching,
  903. DWORDLONG *bytes_of_files_matching,
  904. DWORD *count_of_files_compared,
  905. DWORDLONG *bytes_of_files_compared,
  906. DWORD *count_of_files_merged,
  907. DWORDLONG *bytes_of_files_merged,
  908. DWORD *count_of_files_enqueued,
  909. DWORD *count_of_files_dequeued,
  910. double cpu_load)
  911. {
  912. ASSERT(this != 0);
  913. ASSERT(grovel_duration > 0);
  914. ASSERT(count_of_files_hashed != 0);
  915. ASSERT(bytes_of_files_hashed != 0);
  916. ASSERT(count_of_files_matching != 0);
  917. ASSERT(bytes_of_files_matching != 0);
  918. ASSERT(count_of_files_compared != 0);
  919. ASSERT(bytes_of_files_compared != 0);
  920. ASSERT(count_of_files_merged != 0);
  921. ASSERT(bytes_of_files_merged != 0);
  922. ASSERT(count_of_files_enqueued != 0);
  923. ASSERT(count_of_files_dequeued != 0);
  924. ASSERT(cpu_load >= 0.0);
  925. ASSERT(cpu_load <= 1.0);
  926. ASSERT(!groveler_dead);
  927. unsigned int invokation_time = GET_TICK_COUNT();
  928. TRACE_PRINTF(TC_partctrl, 2,
  929. (_T("time: %d\n"), invokation_time));
  930. TRACE_PRINTF(TC_partctrl, 2, (_T("\tPCcg -\tgroveling on drive %s\n"),
  931. sis_drives.partition_mount_name(partition_index)));
  932. DWORD hash_read_ops;
  933. DWORD hash_read_time;
  934. DWORD compare_read_ops;
  935. DWORD compare_read_time;
  936. DWORD merge_time;
  937. GrovelStatus status = groveler->grovel(grovel_duration,
  938. &hash_read_ops, &hash_read_time,
  939. count_of_files_hashed, bytes_of_files_hashed,
  940. &compare_read_ops, &compare_read_time,
  941. count_of_files_compared, bytes_of_files_compared,
  942. count_of_files_matching, bytes_of_files_matching,
  943. &merge_time,
  944. count_of_files_merged, bytes_of_files_merged,
  945. count_of_files_enqueued, count_of_files_dequeued);
  946. unsigned int completion_time = GET_TICK_COUNT();
  947. if (status != Grovel_ok && status != Grovel_pending)
  948. {
  949. ASSERT(status == Grovel_error);
  950. *count_of_files_hashed = 0;
  951. *bytes_of_files_hashed = 0;
  952. *count_of_files_matching = 0;
  953. *bytes_of_files_matching = 0;
  954. *count_of_files_compared = 0;
  955. *bytes_of_files_compared = 0;
  956. *count_of_files_merged = 0;
  957. *bytes_of_files_merged = 0;
  958. *count_of_files_enqueued = 0;
  959. *count_of_files_dequeued = 0;
  960. TRACE_PRINTF(TC_partctrl, 1,
  961. (_T("\tPCcg -\tgrovel() returned error -- groveler dead\n")));
  962. eventlog.report_event(GROVMSG_GROVELER_DEAD, 1,
  963. sis_drives.partition_mount_name(partition_index));
  964. groveler_dead = true;
  965. if (error_retry_groveling)
  966. {
  967. restart_groveling_interval = base_restart_groveling_interval;
  968. event_timer.schedule(invokation_time + restart_groveling_interval,
  969. (void *)this, restart_groveling);
  970. return true;
  971. }
  972. else
  973. {
  974. return false;
  975. }
  976. }
  977. ASSERT(hash_read_ops > 0 || hash_read_time == 0);
  978. ASSERT(compare_read_ops > 0 || compare_read_time == 0);
  979. ASSERT(*bytes_of_files_hashed >= *count_of_files_hashed);
  980. ASSERT(*bytes_of_files_matching >= *count_of_files_matching);
  981. ASSERT(*bytes_of_files_compared >= *count_of_files_compared);
  982. ASSERT(*bytes_of_files_merged >= *count_of_files_merged);
  983. ASSERT(*count_of_files_hashed >= *count_of_files_matching);
  984. ASSERT(*bytes_of_files_hashed >= *bytes_of_files_matching);
  985. ASSERT(*count_of_files_compared >= *count_of_files_merged);
  986. ASSERT(*bytes_of_files_compared >= *bytes_of_files_merged);
  987. ASSERT(*count_of_files_dequeued >= *count_of_files_hashed);
  988. unsigned int grovel_time = completion_time - invokation_time;
  989. ASSERT(signed(grovel_time) >= 0);
  990. shared_data->increment_value(partition_index,
  991. SDF_grovel_time, grovel_time);
  992. shared_data->increment_value(partition_index,
  993. SDF_working_time, grovel_time);
  994. shared_data->increment_value(partition_index,
  995. SDF_files_hashed, *count_of_files_hashed);
  996. shared_data->increment_value(partition_index,
  997. SDF_files_compared, *count_of_files_compared);
  998. shared_data->increment_value(partition_index,
  999. SDF_files_merged, *count_of_files_merged);
  1000. int files_in_queue = groveler->count_of_files_in_queue();
  1001. ASSERT(files_in_queue >= 0);
  1002. int files_to_compare = groveler->count_of_files_to_compare();
  1003. ASSERT(files_to_compare >= 0);
  1004. shared_data->set_value(partition_index, SDF_queue_length, files_in_queue);
  1005. TRACE_PRINTF(TC_partctrl, 4,
  1006. (_T("\tPCcg -\thash read ops = %d\n"), hash_read_ops));
  1007. TRACE_PRINTF(TC_partctrl, 4,
  1008. (_T("\tPCcg -\thash read time = %d\n"), hash_read_time));
  1009. TRACE_PRINTF(TC_partctrl, 4,
  1010. (_T("\tPCcg -\tcompare read ops = %d\n"), compare_read_ops));
  1011. TRACE_PRINTF(TC_partctrl, 4,
  1012. (_T("\tPCcg -\tcompare read time = %d\n"), compare_read_time));
  1013. shared_data->increment_value(partition_index,
  1014. SDF_hash_read_time, hash_read_time);
  1015. shared_data->increment_value(partition_index,
  1016. SDF_hash_read_ops, hash_read_ops);
  1017. shared_data->increment_value(partition_index,
  1018. SDF_compare_read_time, compare_read_time);
  1019. shared_data->increment_value(partition_index,
  1020. SDF_compare_read_ops, compare_read_ops);
  1021. update_peak_finder(RT_hash, hash_read_time, hash_read_ops);
  1022. update_peak_finder(RT_compare, compare_read_time, compare_read_ops);
  1023. shared_data->set_value(partition_index,
  1024. SDF_hash_read_estimate, __int64(*read_time_estimate[RT_hash]));
  1025. shared_data->set_value(partition_index,
  1026. SDF_compare_read_estimate, __int64(*read_time_estimate[RT_compare]));
  1027. int count_of_files_groveled =
  1028. *count_of_files_hashed + *count_of_files_compared;
  1029. ASSERT(mean_file_size != 0);
  1030. if (count_of_files_groveled > 0)
  1031. {
  1032. __int64 bytes_of_files_groveled =
  1033. *bytes_of_files_hashed + *bytes_of_files_compared;
  1034. double sample_mean_file_size =
  1035. double(bytes_of_files_groveled) / double(count_of_files_groveled);
  1036. ASSERT(sample_mean_file_size > 0.0);
  1037. file_size_filter.update_value(sample_mean_file_size,
  1038. count_of_files_groveled);
  1039. *mean_file_size = file_size_filter.retrieve_value();
  1040. ASSERT(*mean_file_size > 0.0);
  1041. }
  1042. ASSERT(dequeue_hash_ratio != 0);
  1043. ASSERT(*dequeue_hash_ratio >= 0.0);
  1044. ASSERT(*dequeue_hash_ratio <= 1.0);
  1045. double files_to_hash = *dequeue_hash_ratio * double(files_in_queue);
  1046. ASSERT(*mean_file_size >= 0.0);
  1047. double bytes_to_hash = *mean_file_size * files_to_hash;
  1048. double bytes_to_compare = *mean_file_size * double(files_to_compare);
  1049. double expected_bytes_to_free = *compare_match_ratio *
  1050. (bytes_to_compare + *hash_match_ratio * bytes_to_hash);
  1051. double expected_free_bytes = volume_free_bytes + expected_bytes_to_free;
  1052. free_space_ratio = 0;
  1053. if (expected_free_bytes > 0)
  1054. {
  1055. free_space_ratio = expected_bytes_to_free / expected_free_bytes;
  1056. }
  1057. ASSERT(free_space_ratio >= 0.0);
  1058. ASSERT(free_space_ratio <= 1.0);
  1059. calculate_effective_max_grovel_interval();
  1060. ASSERT(effective_max_grovel_interval > 0);
  1061. ASSERT(effective_max_grovel_interval <= max_grovel_interval);
  1062. double use_multiplier =
  1063. base_use_multiplier + use_multiplier_slope * free_space_ratio;
  1064. ASSERT(use_multiplier >= 0.0);
  1065. TRACE_PRINTF(TC_partctrl, 5,
  1066. (_T("\tPCcg -\tuse multiplier = %f\n"), use_multiplier));
  1067. double hash_comparison_time = use_multiplier * *read_time_estimate[RT_hash];
  1068. ASSERT(hash_comparison_time >= 0.0);
  1069. double compare_comparison_time =
  1070. use_multiplier * *read_time_estimate[RT_compare];
  1071. ASSERT(compare_comparison_time >= 0.0);
  1072. TRACE_PRINTF(TC_partctrl, 5,
  1073. (_T("\tPCcg -\thash comparison time = %f\n"), hash_comparison_time));
  1074. TRACE_PRINTF(TC_partctrl, 5,
  1075. (_T("\tPCcg -\tcompare comparison time = %f\n"),
  1076. compare_comparison_time));
  1077. TRACE_PRINTF(TC_partctrl, 5, (_T("\tPCcg -\tcpu load = %f\n"), cpu_load));
  1078. double cpu_load_threshold = base_cpu_load_threshold +
  1079. cpu_load_threshold_slope * free_space_ratio;
  1080. TRACE_PRINTF(TC_partctrl, 5,
  1081. (_T("\tPCcg -\tcpu load threshold = %f\n"), cpu_load_threshold));
  1082. ASSERT(cpu_load_threshold >= 0.0);
  1083. ASSERT(cpu_load_threshold <= 1.0);
  1084. if (cpu_load > cpu_load_threshold || read_mean_comparator.exceeds(
  1085. hash_comparison_time, compare_comparison_time))
  1086. {
  1087. TRACE_PRINTF(TC_partctrl, 3,
  1088. (_T("\tPCcg -\tread time exceeds acceptable bounds\n")));
  1089. TRACE_PRINTF(TC_partctrl, 3,
  1090. (_T("\t\tor CPU load exceeds threshold\n")));
  1091. ASSERT(grovel_interval > 0);
  1092. remaining_grovel_interval = grovel_interval;
  1093. read_mean_comparator.reset();
  1094. grovel_interval *= 2;
  1095. ok_to_record_measurement = false;
  1096. }
  1097. else if (read_mean_comparator.within(hash_comparison_time,
  1098. compare_comparison_time))
  1099. {
  1100. TRACE_PRINTF(TC_partctrl, 3,
  1101. (_T("\tPCcg -\tread time within acceptable bounds\n")));
  1102. ASSERT(base_grovel_interval > 0);
  1103. grovel_interval = base_grovel_interval;
  1104. ok_to_record_measurement = true;
  1105. }
  1106. if (grovel_interval > effective_max_grovel_interval)
  1107. {
  1108. ASSERT(effective_max_grovel_interval > 0);
  1109. grovel_interval = effective_max_grovel_interval;
  1110. }
  1111. TRACE_PRINTF(TC_partctrl, 4, (_T("\tPCcg -\tgrovel interval = %d\n"), grovel_interval));
  1112. TRACE_PRINTF(TC_partctrl, 4, (_T("\tPCcg -\tremaining grovel interval = %d\n"),
  1113. remaining_grovel_interval));
  1114. return true;
  1115. }
  1116. bool
  1117. PartitionController::control_volume_scan(
  1118. int scan_duration,
  1119. DWORD *count_of_files_enqueued)
  1120. {
  1121. ASSERT(this != 0);
  1122. ASSERT(scan_duration > 0);
  1123. ASSERT(count_of_files_enqueued != 0);
  1124. ASSERT(!groveler_dead);
  1125. unsigned int invokation_time = GET_TICK_COUNT();
  1126. TRACE_PRINTF(TC_partctrl, 2, (_T("time: %d\n"), invokation_time));
  1127. TRACE_PRINTF(TC_partctrl, 2,
  1128. (_T("\tPCcvs -\tscanning volume on drive %s\n"),
  1129. sis_drives.partition_mount_name(partition_index)));
  1130. DWORD time_consumed;
  1131. DWORD findfirst_count;
  1132. DWORD findnext_count;
  1133. GrovelStatus status = groveler->scan_volume(scan_duration,
  1134. restart_volume_scan, &time_consumed, &findfirst_count, &findnext_count,
  1135. count_of_files_enqueued);
  1136. unsigned int completion_time = GET_TICK_COUNT();
  1137. if (status == Grovel_ok || status == Grovel_pending)
  1138. {
  1139. if (extended_restart_in_progress)
  1140. {
  1141. log_drive->partition_initialized(partition_index);
  1142. eventlog.report_event(GROVMSG_GROVELER_STARTED, 1,
  1143. sis_drives.partition_mount_name(partition_index));
  1144. extended_restart_in_progress = false;
  1145. }
  1146. if (status == Grovel_ok)
  1147. {
  1148. TRACE_PRINTF(TC_partctrl, 1,
  1149. (_T("\tPCcvs -\tcompleted volume scan\n")));
  1150. performing_full_volume_scan = false;
  1151. }
  1152. }
  1153. else
  1154. {
  1155. ASSERT(status == Grovel_error);
  1156. *count_of_files_enqueued = 0;
  1157. TRACE_PRINTF(TC_partctrl, 1,
  1158. (_T("\tPCcvs -\tscan_volume() returned error -- groveler dead\n")));
  1159. if (!extended_restart_in_progress)
  1160. {
  1161. eventlog.report_event(GROVMSG_GROVELER_DEAD, 1,
  1162. sis_drives.partition_mount_name(partition_index));
  1163. }
  1164. groveler_dead = true;
  1165. if (error_retry_groveling)
  1166. {
  1167. if (!extended_restart_in_progress)
  1168. {
  1169. restart_groveling_interval = base_restart_groveling_interval;
  1170. }
  1171. event_timer.schedule(invokation_time + restart_groveling_interval,
  1172. (void *)this, restart_groveling);
  1173. if (extended_restart_in_progress)
  1174. {
  1175. restart_groveling_interval *= 2;
  1176. if (restart_groveling_interval > max_restart_groveling_interval)
  1177. {
  1178. restart_groveling_interval = max_restart_groveling_interval;
  1179. }
  1180. extended_restart_in_progress = false;
  1181. }
  1182. return true;
  1183. }
  1184. else
  1185. {
  1186. extended_restart_in_progress = false;
  1187. return false;
  1188. }
  1189. }
  1190. ASSERT(signed(time_consumed) >= 0);
  1191. ASSERT(signed(findfirst_count) >= 0);
  1192. ASSERT(signed(findnext_count) >= 0);
  1193. ASSERT(signed(*count_of_files_enqueued) >= 0);
  1194. unsigned int scan_time = completion_time - invokation_time;
  1195. ASSERT(signed(scan_time) >= 0);
  1196. shared_data->increment_value(partition_index, SDF_volscan_time, scan_time);
  1197. shared_data->increment_value(partition_index, SDF_working_time, scan_time);
  1198. shared_data->increment_value(partition_index,
  1199. SDF_files_scanned, findfirst_count + findnext_count);
  1200. int queue_length = groveler->count_of_files_in_queue();
  1201. ASSERT(queue_length >= 0);
  1202. shared_data->set_value(partition_index, SDF_queue_length, queue_length);
  1203. restart_volume_scan = false;
  1204. TRACE_PRINTF(TC_partctrl, 4,
  1205. (_T("\tPCcvs -\ttime consumed = %d\n"), time_consumed));
  1206. TRACE_PRINTF(TC_partctrl, 4,
  1207. (_T("\tPCcvs -\tfindfirst count = %d\n"), findfirst_count));
  1208. TRACE_PRINTF(TC_partctrl, 4,
  1209. (_T("\tPCcvs -\tfindnext count = %d\n"), findnext_count));
  1210. TRACE_PRINTF(TC_partctrl, 4,
  1211. (_T("\tPCcvs -\tcount of files enqueued = %d\n"),
  1212. *count_of_files_enqueued));
  1213. return true;
  1214. }
  1215. void
  1216. PartitionController::update_peak_finder(
  1217. ReadType read_type,
  1218. DWORD read_time,
  1219. DWORD read_ops)
  1220. {
  1221. ASSERT(this != 0);
  1222. unsigned int invokation_time = GET_TICK_COUNT();
  1223. TRACE_PRINTF(TC_partctrl, 3, (_T("time: %d\n"), invokation_time));
  1224. TRACE_PRINTF(TC_partctrl, 3,
  1225. (_T("\tPCupf -\tupdating peak finder for drive %s\n"),
  1226. sis_drives.partition_mount_name(partition_index)));
  1227. ASSERT(read_type == RT_hash || read_type == RT_compare);
  1228. ASSERT(signed(read_time) >= 0);
  1229. ASSERT(signed(read_ops) >= 0);
  1230. if (read_ops > 0)
  1231. {
  1232. double time_per_read = double(read_time)/double(read_ops);
  1233. ASSERT(time_per_read >= 0.0);
  1234. TRACE_PRINTF(TC_partctrl, 4, (_T("\tPCupf -\ttime per %s read = %f\n"),
  1235. (read_type == RT_hash ? _T("hash") : _T("compare")),
  1236. time_per_read));
  1237. read_mean_comparator.sample(read_type, time_per_read);
  1238. ASSERT(read_peak_finder[read_type] != 0);
  1239. ASSERT(read_time_filter[read_type] != 0);
  1240. ASSERT(read_time_estimate[read_type] != 0);
  1241. ASSERT(read_time_confidence != 0);
  1242. if (ok_to_record_measurement ||
  1243. signed(invokation_time - next_untrusted_measurement_time) >= 0)
  1244. {
  1245. TRACE_PRINTF(TC_partctrl, 2,
  1246. (_T("\tPCupf -\trecording %s measurement for drive %s\n"),
  1247. (read_type == RT_hash ? _T("hash") : _T("compare")),
  1248. sis_drives.partition_mount_name(partition_index)));
  1249. read_peak_finder[read_type]->sample(time_per_read, read_ops);
  1250. ASSERT(untrusted_measurement_interval > 0);
  1251. ok_to_record_measurement = true;
  1252. next_untrusted_measurement_time =
  1253. invokation_time + untrusted_measurement_interval;
  1254. TRACE_PRINTF(TC_partctrl, 5,
  1255. (_T("\tPCupf -\tnext untrusted measurement time = %d\n"),
  1256. next_untrusted_measurement_time));
  1257. }
  1258. if (read_peak_finder[read_type]->found())
  1259. {
  1260. double peak = read_peak_finder[read_type]->median();
  1261. TRACE_PRINTF(TC_partctrl, 1,
  1262. (_T("\tPCupf -\t%s read peak found: %f\n"),
  1263. (read_type == RT_hash ? _T("hash") : _T("compare")), peak));
  1264. if (peak > 0.0)
  1265. {
  1266. read_time_filter[read_type]->update_value(peak);
  1267. }
  1268. else
  1269. {
  1270. PRINT_DEBUG_MSG((_T("GROVELER: update_peak_finder() peak finder returned peak of zero\n")));
  1271. }
  1272. read_peak_finder[read_type]->reset();
  1273. *read_time_estimate[read_type] =
  1274. read_time_filter[read_type]->retrieve_value();
  1275. ASSERT(*read_time_estimate[read_type] > 0.0);
  1276. TRACE_PRINTF(TC_partctrl, 2,
  1277. (_T("\tPCupf -\t%s read time estimate = %f\n"),
  1278. (read_type == RT_hash ? _T("hash") : _T("compare")),
  1279. *read_time_estimate[read_type]));
  1280. double sample_peak_ratio = *read_time_estimate[read_type] / peak;
  1281. double sample_read_time_confidence =
  1282. (sample_peak_ratio + peak_finder_accuracy - 1.0) /
  1283. peak_finder_accuracy;
  1284. TRACE_PRINTF(TC_partctrl, 4,
  1285. (_T("\tPCupf -\tsample read time confidence = %f\n"),
  1286. sample_read_time_confidence));
  1287. read_time_confidence_estimator.update(read_type,
  1288. sample_read_time_confidence);
  1289. *read_time_confidence = read_time_confidence_estimator.confidence();
  1290. ASSERT(*read_time_confidence >= 0.0);
  1291. ASSERT(*read_time_confidence <= 1.0);
  1292. TRACE_PRINTF(TC_partctrl, 2,
  1293. (_T("\tPCupf -\tread time confidence = %f\n"),
  1294. *read_time_confidence));
  1295. calculate_effective_max_grovel_interval();
  1296. ASSERT(effective_max_grovel_interval > 0);
  1297. ASSERT(effective_max_grovel_interval <= max_grovel_interval);
  1298. }
  1299. }
  1300. }
  1301. void
  1302. PartitionController::calculate_effective_max_grovel_interval()
  1303. {
  1304. ASSERT(this != 0);
  1305. ASSERT(read_time_confidence != 0);
  1306. ASSERT(*read_time_confidence >= 0.0);
  1307. ASSERT(*read_time_confidence <= 1.0);
  1308. TRACE_PRINTF(TC_partctrl, 4,
  1309. (_T("\tPCcemgi -\tread time confidence = %f\n"),
  1310. *read_time_confidence));
  1311. TRACE_PRINTF(TC_partctrl, 5,
  1312. (_T("\tPCcemgi -\tfree space ratio = %f\n"), free_space_ratio));
  1313. double log_untrusted_measurement_interval = log_max_grovel_interval -
  1314. (1.0 - *read_time_confidence) * log_low_confidence_slope;
  1315. untrusted_measurement_interval =
  1316. int(exp(log_untrusted_measurement_interval));
  1317. ASSERT(untrusted_measurement_interval > 0);
  1318. TRACE_PRINTF(TC_partctrl, 5,
  1319. (_T("\tPCcemgi -\tuntrusted measurement interval = %d\n"),
  1320. untrusted_measurement_interval));
  1321. int low_disk_space_interval = max_grovel_interval -
  1322. int(free_space_ratio * low_disk_space_slope);
  1323. ASSERT(low_disk_space_interval > 0);
  1324. effective_max_grovel_interval =
  1325. __min(untrusted_measurement_interval, low_disk_space_interval);
  1326. ASSERT(effective_max_grovel_interval > 0);
  1327. ASSERT(effective_max_grovel_interval <= max_grovel_interval);
  1328. TRACE_PRINTF(TC_partctrl, 5,
  1329. (_T("\tPCcemgi -\teffective max grovel interval = %d\n"),
  1330. effective_max_grovel_interval));
  1331. }