4 * Created on: Jan 6, 2011
14 #include "StoreCache.hh"
15 #include "StoreDay.hh"
16 #include "DeviceConfig.hh"
17 #include "FileUtil.hh"
22 StoreCache::StoreCache(string device_id_param,
23 Date *date_time_param): Store(device_id_param, date_time_param) {
26 StoreCache::~StoreCache() {
29 string StoreCache::get_dir_name(string device_id_param,
30 Date *date_time_param,
31 EnumSummaryPeriod period_type_param,
32 EnumSummaryCalculationType calc_type_param) {
39 period_name = DataSummary::get_summary_period_name(period_type_param);
40 calc_type = DataSummary::get_summary_calculation_name(calc_type_param);
42 bd_name = DeviceConfig::get_base_dir_name();
43 bd_name = FileUtil::concat_paths(bd_name, CACHE_DIR_NAME);
44 bd_name = FileUtil::concat_paths(bd_name, device_id_param);
45 bd_name = FileUtil::concat_paths(bd_name, period_name);
46 bd_name = FileUtil::concat_paths(bd_name, calc_type);
47 if (period_type_param == PERIOD_YEARLY) {
50 else if (period_type_param == PERIOD_MONTHLY) {
51 snprintf(buffer, 30, "%d", date_time_param->year);
52 ret_val = bd_name + "/" + buffer;
55 snprintf(buffer, 30, "%d/%02d", date_time_param->year, date_time_param->month);
56 ret_val = bd_name + "/" + buffer;
61 string StoreCache::get_file_name(string device_id_param,
62 Date *date_time_param,
63 EnumSummaryPeriod period_type_param,
64 EnumSummaryCalculationType calc_type_param) {
69 if (period_type_param == PERIOD_YEARLY) {
70 snprintf(buffer, 30, "%d", date_time_param->year);
72 else if (period_type_param == PERIOD_MONTHLY) {
73 snprintf(buffer, 30, "%d-%02d",
74 date_time_param->year,
75 date_time_param->month);
78 snprintf(buffer, 30, "%d-%02d-%02d",
79 date_time_param->year,
80 date_time_param->month,
81 date_time_param->day);
84 fname = fname + DATAFILE_SUFFIX;
85 ret_val = get_dir_name(device_id_param, date_time_param, period_type_param, calc_type_param);
86 ret_val = FileUtil::concat_paths(ret_val, fname);
90 plp::Date *StoreCache::get_scanning_limit_date(EnumSummaryPeriod period_type_param) {
94 cur_data = get_latest_data(date, device_id, period_type_param);
95 if (cur_data != NULL) {
96 ret_val = cur_data->get_date().clone();
97 ret_val->next_second();
102 ret_val = date->clone();
103 if (period_type_param == PERIOD_YEARLY) {
104 ret_val->next_year();
107 ret_val->next_month();
113 DataRange *StoreCache::get_mean(EnumSummaryPeriod period_type_param) {
120 fname = get_file_name(device_id,
124 if (store_data == NULL) {
125 if (access(fname.c_str(), R_OK) == 0) {
129 if (store_data != NULL) {
130 row_count = store_data->get_count();
132 ret_val = new DataRange();
133 dta = store_data->get(0);
138 if (ret_val == NULL) {
139 switch(period_type_param) {
153 cur_date = date->clone();
154 max_date = get_scanning_limit_date(period_type_param);
160 while(cur_date->before(max_date)) {
161 if (period_type_param == PERIOD_YEARLY) {
162 store = new StoreCache(device_id, cur_date);
163 dr = store->get_mean(PERIOD_MONTHLY);
166 if (StoreDay::exist(device_id, cur_date, false)) {
167 store = new StoreDay(device_id, cur_date);
168 dr = store->get_mean(PERIOD_DAILY);
171 // data not found for that day, try to find next date containing data
172 StoreDay::get_next_date_with_data(device_id,
179 cur_data = dr->get_first();
180 if (cur_data != NULL) {
182 if (res_data == NULL) {
184 val_cnt = res_data->get_value_count();
187 for (ii = 0; ii < val_cnt; ii++) {
188 res_data->value_arr[ii] = res_data->value_arr[ii] + cur_data->value_arr[ii];
196 if (period_type_param == PERIOD_YEARLY) {
197 cur_date->next_month();
200 cur_date->next_day();
203 if ((res_data != NULL) &&
205 for (ii = 0; ii < val_cnt; ii++) {
206 res_data->value_arr[ii] = res_data->value_arr[ii] / cnt;
208 ret_val = new DataRange(res_data);
209 save(fname, ret_val, 4);
218 case PERIOD_MINUTELY:
219 case PERIOD_SECONDLY:
220 if (StoreDay::exist(device_id, date, false)) {
223 store = new StoreDay(device_id, date);
224 ret_val = store->get_mean(period_type_param);
225 if ((ret_val != NULL) &&
226 (period_type_param != PERIOD_MINUTELY) &&
227 (period_type_param != PERIOD_SECONDLY)) {
228 // no need cache second or minute data
229 save(fname, ret_val, 4);
239 DataRange *StoreCache::get_sum(EnumSummaryPeriod period_type_param) {
247 fname = get_file_name(device_id,
251 if (store_data == NULL) {
252 if (access(fname.c_str(), R_OK) == 0) {
256 if (store_data != NULL) {
257 row_count = store_data->get_count();
259 ret_val = new DataRange();
260 dta = store_data->get(0);
265 if (ret_val == NULL) {
266 switch(period_type_param) {
268 case PERIOD_MONTHLY: {
278 cur_date = date->clone();
279 max_date = get_scanning_limit_date(period_type_param);
283 while(cur_date->before(max_date)) {
286 if (period_type_param == PERIOD_YEARLY) {
287 store = new StoreCache(device_id, cur_date);
288 dr = store->get_sum(PERIOD_MONTHLY);
291 if (StoreDay::exist(device_id, cur_date, false)) {
292 store = new StoreDay(device_id, cur_date);
293 dr = store->get_sum(PERIOD_DAILY);
296 // data not found for that day, try to find next date containing data
297 StoreDay::get_next_date_with_data(device_id,
304 cur_data = dr->get_first();
305 if (cur_data != NULL) {
307 if (res_data == NULL) {
311 val_cnt = res_data->get_value_count();
312 for (ii = 0; ii < val_cnt; ii++) {
313 res_data->value_arr[ii] = res_data->value_arr[ii] + cur_data->value_arr[ii];
322 if (period_type_param == PERIOD_YEARLY) {
323 cur_date->next_month();
326 cur_date->next_day();
329 if ((res_data != NULL) &&
331 ret_val = new DataRange(res_data);
332 save(fname, ret_val, 4);
341 case PERIOD_MINUTELY:
342 case PERIOD_SECONDLY:
343 if (StoreDay::exist(device_id, date, false)) {
344 store = new StoreDay(device_id, date);
345 ret_val = store->get_sum(period_type_param);
346 if ((ret_val != NULL) &&
347 (period_type_param != PERIOD_MINUTELY) &&
348 (period_type_param != PERIOD_SECONDLY)) {
349 // no need cache second or minute data
350 save(fname, ret_val, 4);
360 DataRange *StoreCache::get_delta(EnumSummaryPeriod period_type_param) {
368 fname = get_file_name(device_id,
372 if (store_data == NULL) {
373 if (access(fname.c_str(), R_OK) == 0) {
374 // read from cache file
378 if (store_data != NULL) {
379 row_count = store_data->get_count();
381 ret_val = new DataRange();
382 dta = store_data->get(0);
387 if (ret_val == NULL) {
388 switch(period_type_param) {
389 case PERIOD_YEARLY: {
395 first_data = get_oldest_data(date, device_id, PERIOD_YEARLY);
396 if (first_data != NULL) {
397 last_data = get_latest_data(date, device_id, PERIOD_YEARLY);
398 if (last_data != NULL) {
399 ret_val = new DataRange();
400 cnt = last_data->get_value_count();
401 for (ii = 0; ii < cnt; ii++) {
402 last_data->value_arr[ii] = last_data->value_arr[ii] - first_data->value_arr[ii];
404 ret_val->add(last_data);
408 save(fname, ret_val, 4);
411 log_error("Could not read first or last data item from device %s for year: %d", device_id.c_str(), date->year);
415 case PERIOD_MONTHLY: {
424 cur_date = date->clone();
425 max_date = date->clone();
426 max_date->next_month();
429 while(cur_date->before(max_date)) {
430 if (StoreDay::exist(device_id,
433 store = new StoreDay(device_id, cur_date);
434 if (first_data == NULL) {
435 cur_data = store->get_oldest_data();
436 if (cur_data != NULL) {
437 first_data = cur_data->clone();
438 last_data = cur_data->clone();
442 cur_data = store->get_latest_data();
443 if (cur_data != NULL) {
444 if (last_data != NULL) {
447 last_data = cur_data;
450 cur_date->next_day();
453 // data not found for that day, try to find next date containing data
454 StoreDay::get_next_date_with_data(device_id,
461 if (first_data != NULL) {
462 if (last_data == NULL) {
463 last_data = first_data->clone();
465 cnt = last_data->get_value_count();
466 for (ii = 0; ii < cnt; ii++) {
467 last_data->value_arr[ii] = last_data->value_arr[ii] - first_data->value_arr[ii];
469 cur_date = first_data->get_date().clone();
470 last_data->set_date(cur_date);
472 ret_val = new DataRange(last_data);
475 save(fname, ret_val, 4);
481 case PERIOD_MINUTELY:
482 case PERIOD_SECONDLY:
483 if (StoreDay::exist(device_id, date, false)) {
484 store = new StoreDay(device_id, date);
485 ret_val = store->get_delta(period_type_param);
486 if ((period_type_param != PERIOD_MINUTELY) ||
487 (period_type_param != PERIOD_SECONDLY)) {
488 // no need cache second or minute data
489 save(fname, ret_val, 4);
499 DataRange *StoreCache::get_max(EnumSummaryPeriod period_type_param) {
507 fname = get_file_name(device_id,
511 if (store_data == NULL) {
512 if (access(fname.c_str(), R_OK) == 0) {
516 if (store_data != NULL) {
517 row_count = store_data->get_count();
519 ret_val = new DataRange();
520 dta = store_data->get(0);
525 if (ret_val == NULL) {
526 switch(period_type_param) {
528 case PERIOD_MONTHLY: {
538 cur_date = date->clone();
539 max_date = get_scanning_limit_date(period_type_param);
543 while(cur_date->before(max_date)) {
544 if (period_type_param == PERIOD_YEARLY) {
545 store = new StoreCache(device_id, cur_date);
546 dr = store->get_max(PERIOD_MONTHLY);
549 if (StoreDay::exist(device_id, cur_date, false)) {
550 store = new StoreDay(device_id, cur_date);
551 dr = store->get_max(PERIOD_DAILY);
554 StoreDay::get_next_date_with_data(device_id,
561 cur_data = dr->get_first();
562 if (cur_data != NULL) {
564 if (res_data == NULL) {
568 val_cnt = res_data->get_value_count();
570 for (ii = 0; ii < val_cnt; ii++) {
571 if (cur_data->value_arr[ii] > res_data->value_arr[ii]) {
572 res_data->value_arr[ii] = cur_data->value_arr[ii];
579 new_date = cur_data->get_date();
580 res_data->set_date(&new_date);
588 if (period_type_param == PERIOD_YEARLY) {
589 cur_date->next_month();
592 cur_date->next_day();
595 if ((res_data != NULL) &&
597 ret_val = new DataRange(res_data);
598 save(fname, ret_val, 4);
607 case PERIOD_MINUTELY:
608 case PERIOD_SECONDLY:
609 if (StoreDay::exist(device_id, date, false)) {
610 store = new StoreDay(device_id, date);
611 ret_val = store->get_max(period_type_param);
612 if ((period_type_param != PERIOD_MINUTELY) ||
613 (period_type_param != PERIOD_SECONDLY)) {
614 // no need cache second or minute data
615 save(fname, ret_val, 4);
625 DataRange *StoreCache::get_min(EnumSummaryPeriod period_type_param) {
633 fname = get_file_name(device_id,
637 if (store_data == NULL) {
638 if (access(fname.c_str(), R_OK) == 0) {
642 if (store_data != NULL) {
643 row_count = store_data->get_count();
645 ret_val = new DataRange();
646 dta = store_data->get(0);
651 if (ret_val == NULL) {
652 switch(period_type_param) {
654 case PERIOD_MONTHLY: {
664 cur_date = date->clone();
665 max_date = get_scanning_limit_date(period_type_param);
669 while(cur_date->before(max_date)) {
670 if (period_type_param == PERIOD_YEARLY) {
671 store = new StoreCache(device_id, cur_date);
672 dr = store->get_min(PERIOD_MONTHLY);
675 if (StoreDay::exist(device_id, cur_date, false)) {
676 store = new StoreDay(device_id, cur_date);
677 dr = store->get_min(PERIOD_DAILY);
680 StoreDay::get_next_date_with_data(device_id,
687 cur_data = dr->get_first();
688 if (cur_data != NULL) {
690 if (res_data == NULL) {
694 val_cnt = res_data->get_value_count();
696 for (ii = 0; ii < val_cnt; ii++) {
697 if (cur_data->value_arr[ii] < res_data->value_arr[ii]) {
698 res_data->value_arr[ii] = cur_data->value_arr[ii];
705 new_date = cur_data->get_date();
706 res_data->set_date(&new_date);
714 if (period_type_param == PERIOD_YEARLY) {
715 cur_date->next_month();
718 cur_date->next_day();
721 if ((res_data != NULL) &&
723 ret_val = new DataRange(res_data);
724 save(fname, ret_val, 4);
733 case PERIOD_MINUTELY:
734 case PERIOD_SECONDLY:
735 if (StoreDay::exist(device_id, date, false)) {
736 store = new StoreDay(device_id, date);
737 ret_val = store->get_min(period_type_param);
738 if ((period_type_param != PERIOD_MINUTELY) ||
739 (period_type_param != PERIOD_SECONDLY)) {
740 // no need cache second or minute data
741 save(fname, ret_val, 4);
751 void StoreCache::save(std::string fname_param, plp::DataRange *datarange_param, int decimal_count_param) {
758 cnt = datarange_param->get_count();
760 //log_info("[%s] cacheing %d data values.\n", device_id.c_str(), cnt);
761 ostream = FileUtil::open_for_writing(fname_param.c_str());
762 if ((ostream != NULL) &&
763 (ostream->is_open() == true)) {
764 // TODO: add mutex to protect string_list while it's read and emptied
765 for(ii = 0; ii < cnt; ii++) {
766 data = datarange_param->get(ii);
768 line = data->to_string(decimal_count_param);
769 if (line.length() > 0) {
770 *ostream << line << endl;
777 log_error("[%s] File open for data save failed: %s\n", device_id.c_str(), fname_param.c_str());
779 if (ostream != NULL) {
785 Data *StoreCache::get_oldest_data(Date *date_param,
786 string device_id_param,
787 EnumSummaryPeriod period_type_param) {
792 vector<string> mon_vcr;
793 vector<string> dta_vcr;
802 if (period_type_param == PERIOD_YEARLY) {
803 snprintf(buffer, 30, "%d", date_param->year);
804 year_name.append(buffer);
805 device_dir = DeviceConfig::get_base_dir_name();
806 device_dir = FileUtil::concat_paths(device_dir, device_id_param);
807 year_dr = FileUtil::concat_paths(device_dir, year_name);
808 mon_vcr = FileUtil::get_subdirectories(year_dr);
809 for (ii = 0; ii < mon_vcr.size(); ii++) {
810 mon_dr = mon_vcr.at(ii);
811 mon_dr = FileUtil::concat_paths(year_dr, mon_dr);
812 // scan data files from month dir
813 dta_vcr = FileUtil::get_data_files(mon_dr);
814 size = dta_vcr.size();
816 f_name = dta_vcr.at(0);
817 f_name = FileUtil::concat_paths(mon_dr, f_name);
818 store = new StoreDay(f_name);
819 ret_val = store->get_oldest_data();
825 else if (period_type_param == PERIOD_MONTHLY) {
827 snprintf(buffer, 30, "%d", date_param->year);
828 year_name.append(buffer);
829 device_dir = DeviceConfig::get_base_dir_name();
830 device_dir = FileUtil::concat_paths(device_dir, device_id_param);
831 year_dr = FileUtil::concat_paths(device_dir, year_name);
832 snprintf(buffer, 30, "%02d", date_param->month);
833 mon_dr.append(buffer);
834 mon_dr = FileUtil::concat_paths(year_dr, mon_dr);
835 // scan data files from month dir
836 dta_vcr = FileUtil::get_data_files(mon_dr);
837 size = dta_vcr.size();
839 f_name = dta_vcr.at(0);
840 f_name = FileUtil::concat_paths(mon_dr, f_name);
841 store = new StoreDay(f_name);
842 ret_val = store->get_oldest_data();
848 store = new StoreDay(device_id_param, date_param);
849 ret_val = store->get_oldest_data();
855 Data *StoreCache::get_latest_data(Date *date_param,
856 string device_id_param,
857 EnumSummaryPeriod period_type_param) {
860 vector<string> mon_vcr;
861 vector<string> dta_vcr;
872 if (period_type_param == PERIOD_YEARLY) {
873 snprintf(buffer, 30, "%d", date_param->year);
874 year_name.append(buffer);
875 device_dir = DeviceConfig::get_base_dir_name();
876 device_dir = FileUtil::concat_paths(device_dir, device_id_param);
877 year_dr = FileUtil::concat_paths(device_dir, year_name);
878 mon_vcr = FileUtil::get_subdirectories(year_dr);
879 for (ii = mon_vcr.size() - 1; ii >= 0; ii--) {
880 mon_dr = mon_vcr.at(ii);
881 mon_dr = FileUtil::concat_paths(year_dr, mon_dr);
882 // scan data files from month dir
883 dta_vcr = FileUtil::get_data_files(mon_dr);
884 size = dta_vcr.size();
886 f_name = dta_vcr.at(size - 1);
887 f_name = FileUtil::concat_paths(mon_dr, f_name);
888 store = new StoreDay(f_name);
889 ret_val = store->get_latest_data();
895 else if (period_type_param == PERIOD_MONTHLY) {
897 snprintf(buffer, 30, "%d", date_param->year);
898 year_name.append(buffer);
899 device_dir = DeviceConfig::get_base_dir_name();
900 device_dir = FileUtil::concat_paths(device_dir, device_id_param);
901 year_dr = FileUtil::concat_paths(device_dir, year_name);
902 snprintf(buffer, 30, "%02d", date_param->month);
903 mon_dr.append(buffer);
904 mon_dr = FileUtil::concat_paths(year_dr, mon_dr);
905 // scan data files from month dir
906 dta_vcr = FileUtil::get_data_files(mon_dr);
907 size = dta_vcr.size();
909 f_name = dta_vcr.at(size - 1);
910 f_name = FileUtil::concat_paths(mon_dr, f_name);
911 store = new StoreDay(f_name);
912 ret_val = store->get_latest_data();
918 store = new StoreDay(device_id_param, date_param);
919 ret_val = store->get_latest_data();