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)) {
284 if (period_type_param == PERIOD_YEARLY) {
285 store = new StoreCache(device_id, cur_date);
286 dr = store->get_sum(PERIOD_MONTHLY);
289 if (StoreDay::exist(device_id, cur_date, false)) {
290 store = new StoreDay(device_id, cur_date);
291 dr = store->get_sum(PERIOD_DAILY);
294 // data not found for that day, try to find next date containing data
295 StoreDay::get_next_date_with_data(device_id,
302 cur_data = dr->get_first();
303 if (cur_data != NULL) {
305 if (res_data == NULL) {
309 val_cnt = res_data->get_value_count();
310 for (ii = 0; ii < val_cnt; ii++) {
311 res_data->value_arr[ii] = res_data->value_arr[ii] + cur_data->value_arr[ii];
319 if (period_type_param == PERIOD_YEARLY) {
320 cur_date->next_month();
323 cur_date->next_day();
326 if ((res_data != NULL) &&
328 ret_val = new DataRange(res_data);
329 save(fname, ret_val, 4);
338 case PERIOD_MINUTELY:
339 case PERIOD_SECONDLY:
340 if (StoreDay::exist(device_id, date, false)) {
341 store = new StoreDay(device_id, date);
342 ret_val = store->get_sum(period_type_param);
343 if ((ret_val != NULL) &&
344 (period_type_param != PERIOD_MINUTELY) &&
345 (period_type_param != PERIOD_SECONDLY)) {
346 // no need cache second or minute data
347 save(fname, ret_val, 4);
357 DataRange *StoreCache::get_delta(EnumSummaryPeriod period_type_param) {
365 fname = get_file_name(device_id,
369 if (store_data == NULL) {
370 if (access(fname.c_str(), R_OK) == 0) {
371 // read from cache file
375 if (store_data != NULL) {
376 row_count = store_data->get_count();
378 ret_val = new DataRange();
379 dta = store_data->get(0);
384 if (ret_val == NULL) {
385 switch(period_type_param) {
386 case PERIOD_YEARLY: {
392 first_data = get_oldest_data(date, device_id, PERIOD_YEARLY);
393 if (first_data != NULL) {
394 last_data = get_latest_data(date, device_id, PERIOD_YEARLY);
395 if (last_data != NULL) {
396 ret_val = new DataRange();
397 cnt = last_data->get_value_count();
398 for (ii = 0; ii < cnt; ii++) {
399 last_data->value_arr[ii] = last_data->value_arr[ii] - first_data->value_arr[ii];
401 ret_val->add(last_data);
405 save(fname, ret_val, 4);
408 log_error("Could not read first or last data item from device %s for year: %d", device_id.c_str(), date->year);
412 case PERIOD_MONTHLY: {
421 cur_date = date->clone();
422 max_date = date->clone();
423 max_date->next_month();
426 while(cur_date->before(max_date)) {
427 if (StoreDay::exist(device_id,
430 store = new StoreDay(device_id, cur_date);
431 if (first_data == NULL) {
432 cur_data = store->get_oldest_data();
433 if (cur_data != NULL) {
434 first_data = cur_data->clone();
435 last_data = cur_data->clone();
439 cur_data = store->get_latest_data();
440 if (cur_data != NULL) {
441 if (last_data != NULL) {
444 last_data = cur_data;
447 cur_date->next_day();
450 // data not found for that day, try to find next date containing data
451 StoreDay::get_next_date_with_data(device_id,
458 if (first_data != NULL) {
459 if (last_data == NULL) {
460 last_data = first_data->clone();
462 cnt = last_data->get_value_count();
463 for (ii = 0; ii < cnt; ii++) {
464 last_data->value_arr[ii] = last_data->value_arr[ii] - first_data->value_arr[ii];
466 cur_date = first_data->get_date().clone();
467 last_data->set_date(cur_date);
469 ret_val = new DataRange(last_data);
472 save(fname, ret_val, 4);
478 case PERIOD_MINUTELY:
479 case PERIOD_SECONDLY:
480 if (StoreDay::exist(device_id, date, false)) {
481 store = new StoreDay(device_id, date);
482 ret_val = store->get_delta(period_type_param);
483 if ((period_type_param != PERIOD_MINUTELY) ||
484 (period_type_param != PERIOD_SECONDLY)) {
485 // no need cache second or minute data
486 save(fname, ret_val, 4);
496 DataRange *StoreCache::get_max(EnumSummaryPeriod period_type_param) {
504 fname = get_file_name(device_id,
508 if (store_data == NULL) {
509 if (access(fname.c_str(), R_OK) == 0) {
513 if (store_data != NULL) {
514 row_count = store_data->get_count();
516 ret_val = new DataRange();
517 dta = store_data->get(0);
522 if (ret_val == NULL) {
523 switch(period_type_param) {
525 case PERIOD_MONTHLY: {
535 cur_date = date->clone();
536 max_date = get_scanning_limit_date(period_type_param);
540 while(cur_date->before(max_date)) {
541 if (period_type_param == PERIOD_YEARLY) {
542 store = new StoreCache(device_id, cur_date);
543 dr = store->get_max(PERIOD_MONTHLY);
546 if (StoreDay::exist(device_id, cur_date, false)) {
547 store = new StoreDay(device_id, cur_date);
548 dr = store->get_max(PERIOD_DAILY);
551 StoreDay::get_next_date_with_data(device_id,
558 cur_data = dr->get_first();
559 if (cur_data != NULL) {
561 if (res_data == NULL) {
565 val_cnt = res_data->get_value_count();
567 for (ii = 0; ii < val_cnt; ii++) {
568 if (cur_data->value_arr[ii] > res_data->value_arr[ii]) {
569 res_data->value_arr[ii] = cur_data->value_arr[ii];
576 new_date = cur_data->get_date();
577 res_data->set_date(&new_date);
585 if (period_type_param == PERIOD_YEARLY) {
586 cur_date->next_month();
589 cur_date->next_day();
592 if ((res_data != NULL) &&
594 ret_val = new DataRange(res_data);
595 save(fname, ret_val, 4);
604 case PERIOD_MINUTELY:
605 case PERIOD_SECONDLY:
606 if (StoreDay::exist(device_id, date, false)) {
607 store = new StoreDay(device_id, date);
608 ret_val = store->get_max(period_type_param);
609 if ((period_type_param != PERIOD_MINUTELY) ||
610 (period_type_param != PERIOD_SECONDLY)) {
611 // no need cache second or minute data
612 save(fname, ret_val, 4);
622 DataRange *StoreCache::get_min(EnumSummaryPeriod period_type_param) {
630 fname = get_file_name(device_id,
634 if (store_data == NULL) {
635 if (access(fname.c_str(), R_OK) == 0) {
639 if (store_data != NULL) {
640 row_count = store_data->get_count();
642 ret_val = new DataRange();
643 dta = store_data->get(0);
648 if (ret_val == NULL) {
649 switch(period_type_param) {
651 case PERIOD_MONTHLY: {
661 cur_date = date->clone();
662 max_date = get_scanning_limit_date(period_type_param);
666 while(cur_date->before(max_date)) {
667 if (period_type_param == PERIOD_YEARLY) {
668 store = new StoreCache(device_id, cur_date);
669 dr = store->get_min(PERIOD_MONTHLY);
672 if (StoreDay::exist(device_id, cur_date, false)) {
673 store = new StoreDay(device_id, cur_date);
674 dr = store->get_min(PERIOD_DAILY);
677 StoreDay::get_next_date_with_data(device_id,
684 cur_data = dr->get_first();
685 if (cur_data != NULL) {
687 if (res_data == NULL) {
691 val_cnt = res_data->get_value_count();
693 for (ii = 0; ii < val_cnt; ii++) {
694 if (cur_data->value_arr[ii] < res_data->value_arr[ii]) {
695 res_data->value_arr[ii] = cur_data->value_arr[ii];
702 new_date = cur_data->get_date();
703 res_data->set_date(&new_date);
711 if (period_type_param == PERIOD_YEARLY) {
712 cur_date->next_month();
715 cur_date->next_day();
718 if ((res_data != NULL) &&
720 ret_val = new DataRange(res_data);
721 save(fname, ret_val, 4);
730 case PERIOD_MINUTELY:
731 case PERIOD_SECONDLY:
732 if (StoreDay::exist(device_id, date, false)) {
733 store = new StoreDay(device_id, date);
734 ret_val = store->get_min(period_type_param);
735 if ((period_type_param != PERIOD_MINUTELY) ||
736 (period_type_param != PERIOD_SECONDLY)) {
737 // no need cache second or minute data
738 save(fname, ret_val, 4);
748 void StoreCache::save(std::string fname_param, plp::DataRange *datarange_param, int decimal_count_param) {
755 cnt = datarange_param->get_count();
757 //log_info("[%s] cacheing %d data values.\n", device_id.c_str(), cnt);
758 ostream = FileUtil::open_for_writing(fname_param.c_str());
759 if ((ostream != NULL) &&
760 (ostream->is_open() == true)) {
761 // TODO: add mutex to protect string_list while it's read and emptied
762 for(ii = 0; ii < cnt; ii++) {
763 data = datarange_param->get(ii);
765 line = data->to_string(decimal_count_param);
766 if (line.length() > 0) {
767 *ostream << line << endl;
774 log_error("[%s] File open for data save failed: %s\n", device_id.c_str(), fname_param.c_str());
776 if (ostream != NULL) {
782 Data *StoreCache::get_oldest_data(Date *date_param,
783 string device_id_param,
784 EnumSummaryPeriod period_type_param) {
789 vector<string> mon_vcr;
790 vector<string> dta_vcr;
799 if (period_type_param == PERIOD_YEARLY) {
800 snprintf(buffer, 30, "%d", date_param->year);
801 year_name.append(buffer);
802 device_dir = DeviceConfig::get_base_dir_name();
803 device_dir = FileUtil::concat_paths(device_dir, device_id_param);
804 year_dr = FileUtil::concat_paths(device_dir, year_name);
805 mon_vcr = FileUtil::get_subdirectories(year_dr);
806 for (ii = 0; ii < mon_vcr.size(); ii++) {
807 mon_dr = mon_vcr.at(ii);
808 mon_dr = FileUtil::concat_paths(year_dr, mon_dr);
809 // scan data files from month dir
810 dta_vcr = FileUtil::get_data_files(mon_dr);
811 size = dta_vcr.size();
813 f_name = dta_vcr.at(0);
814 f_name = FileUtil::concat_paths(mon_dr, f_name);
815 store = new StoreDay(f_name);
816 ret_val = store->get_oldest_data();
822 else if (period_type_param == PERIOD_MONTHLY) {
824 snprintf(buffer, 30, "%d", date_param->year);
825 year_name.append(buffer);
826 device_dir = DeviceConfig::get_base_dir_name();
827 device_dir = FileUtil::concat_paths(device_dir, device_id_param);
828 year_dr = FileUtil::concat_paths(device_dir, year_name);
829 snprintf(buffer, 30, "%02d", date_param->month);
830 mon_dr.append(buffer);
831 mon_dr = FileUtil::concat_paths(year_dr, mon_dr);
832 // scan data files from month dir
833 dta_vcr = FileUtil::get_data_files(mon_dr);
834 size = dta_vcr.size();
836 f_name = dta_vcr.at(0);
837 f_name = FileUtil::concat_paths(mon_dr, f_name);
838 store = new StoreDay(f_name);
839 ret_val = store->get_oldest_data();
845 store = new StoreDay(device_id_param, date_param);
846 ret_val = store->get_oldest_data();
852 Data *StoreCache::get_latest_data(Date *date_param,
853 string device_id_param,
854 EnumSummaryPeriod period_type_param) {
857 vector<string> mon_vcr;
858 vector<string> dta_vcr;
869 if (period_type_param == PERIOD_YEARLY) {
870 snprintf(buffer, 30, "%d", date_param->year);
871 year_name.append(buffer);
872 device_dir = DeviceConfig::get_base_dir_name();
873 device_dir = FileUtil::concat_paths(device_dir, device_id_param);
874 year_dr = FileUtil::concat_paths(device_dir, year_name);
875 mon_vcr = FileUtil::get_subdirectories(year_dr);
876 for (ii = mon_vcr.size() - 1; ii >= 0; ii--) {
877 mon_dr = mon_vcr.at(ii);
878 mon_dr = FileUtil::concat_paths(year_dr, mon_dr);
879 // scan data files from month dir
880 dta_vcr = FileUtil::get_data_files(mon_dr);
881 size = dta_vcr.size();
883 f_name = dta_vcr.at(size - 1);
884 f_name = FileUtil::concat_paths(mon_dr, f_name);
885 store = new StoreDay(f_name);
886 ret_val = store->get_latest_data();
892 else if (period_type_param == PERIOD_MONTHLY) {
894 snprintf(buffer, 30, "%d", date_param->year);
895 year_name.append(buffer);
896 device_dir = DeviceConfig::get_base_dir_name();
897 device_dir = FileUtil::concat_paths(device_dir, device_id_param);
898 year_dr = FileUtil::concat_paths(device_dir, year_name);
899 snprintf(buffer, 30, "%02d", date_param->month);
900 mon_dr.append(buffer);
901 mon_dr = FileUtil::concat_paths(year_dr, mon_dr);
902 // scan data files from month dir
903 dta_vcr = FileUtil::get_data_files(mon_dr);
904 size = dta_vcr.size();
906 f_name = dta_vcr.at(size - 1);
907 f_name = FileUtil::concat_paths(mon_dr, f_name);
908 store = new StoreDay(f_name);
909 ret_val = store->get_latest_data();
915 store = new StoreDay(device_id_param, date_param);
916 ret_val = store->get_latest_data();