4 * Created on: Jan 6, 2011
12 #include "StoreCache.hh"
13 #include "StoreDay.hh"
14 #include "DeviceConfig.hh"
15 #include "FileUtil.hh"
20 StoreCache::StoreCache(string device_id_param,
21 Date *date_time_param): Store(device_id_param, date_time_param) {
24 StoreCache::~StoreCache() {
27 string StoreCache::get_dir_name(string device_id_param,
28 Date *date_time_param,
29 EnumSummaryPeriod period_type_param,
30 EnumSummaryCalculationType calc_type_param) {
37 period_name = DataSummary::get_summary_period_name(period_type_param);
38 calc_type = DataSummary::get_summary_calculation_name(calc_type_param);
40 bd_name = DeviceConfig::get_base_dir_name();
41 bd_name = FileUtil::concat_paths(bd_name, CACHE_DIR_NAME);
42 bd_name = FileUtil::concat_paths(bd_name, device_id_param);
43 bd_name = FileUtil::concat_paths(bd_name, period_name);
44 bd_name = FileUtil::concat_paths(bd_name, calc_type);
45 if (period_type_param == PERIOD_YEARLY) {
48 else if (period_type_param == PERIOD_MONTHLY) {
49 snprintf(buffer, 30, "%d", date_time_param->year);
50 ret_val = bd_name + "/" + buffer;
53 snprintf(buffer, 30, "%d/%02d", date_time_param->year, date_time_param->month);
54 ret_val = bd_name + "/" + buffer;
59 string StoreCache::get_file_name(string device_id_param,
60 Date *date_time_param,
61 EnumSummaryPeriod period_type_param,
62 EnumSummaryCalculationType calc_type_param) {
67 if (period_type_param == PERIOD_YEARLY) {
68 snprintf(buffer, 30, "%d", date_time_param->year);
70 else if (period_type_param == PERIOD_MONTHLY) {
71 snprintf(buffer, 30, "%d-%02d",
72 date_time_param->year,
73 date_time_param->month);
76 snprintf(buffer, 30, "%d-%02d-%02d",
77 date_time_param->year,
78 date_time_param->month,
79 date_time_param->day);
82 fname = fname + DATAFILE_SUFFIX;
83 ret_val = get_dir_name(device_id_param, date_time_param, period_type_param, calc_type_param);
84 ret_val = FileUtil::concat_paths(ret_val, fname);
88 plp::Date *StoreCache::get_scanning_limit_date(EnumSummaryPeriod period_type_param) {
92 cur_data = get_latest_data(date, device_id, period_type_param);
93 if (cur_data != NULL) {
94 ret_val = cur_data->get_date().clone();
95 ret_val->next_second();
100 ret_val = date->clone();
101 if (period_type_param == PERIOD_YEARLY) {
102 ret_val->next_year();
105 ret_val->next_month();
111 DataRange *StoreCache::get_mean(EnumSummaryPeriod period_type_param) {
118 fname = get_file_name(device_id,
122 if (store_data == NULL) {
123 if (access(fname.c_str(), R_OK) == 0) {
127 if (store_data != NULL) {
128 row_count = store_data->get_count();
130 ret_val = new DataRange();
131 dta = store_data->get(0);
136 if (ret_val == NULL) {
137 switch(period_type_param) {
151 cur_date = date->clone();
152 max_date = get_scanning_limit_date(period_type_param);
158 while(cur_date->before(max_date)) {
159 if (period_type_param == PERIOD_YEARLY) {
160 store = new StoreCache(device_id, cur_date);
161 dr = store->get_mean(PERIOD_MONTHLY);
164 if (StoreDay::exist(device_id, cur_date, false)) {
165 store = new StoreDay(device_id, cur_date);
166 dr = store->get_mean(PERIOD_DAILY);
169 // data not found for that day, try to find next date containing data
170 StoreDay::get_next_date_with_data(device_id,
177 cur_data = dr->get_first();
178 if (cur_data != NULL) {
180 if (res_data == NULL) {
182 val_cnt = res_data->get_value_count();
185 for (ii = 0; ii < val_cnt; ii++) {
186 res_data->value_arr[ii] = res_data->value_arr[ii] + cur_data->value_arr[ii];
194 if (period_type_param == PERIOD_YEARLY) {
195 cur_date->next_month();
198 cur_date->next_day();
201 if ((res_data != NULL) &&
203 for (ii = 0; ii < val_cnt; ii++) {
204 res_data->value_arr[ii] = res_data->value_arr[ii] / cnt;
206 ret_val = new DataRange(res_data);
207 save(fname, ret_val, 4);
216 case PERIOD_MINUTELY:
217 case PERIOD_SECONDLY:
218 if (StoreDay::exist(device_id, date, false)) {
221 store = new StoreDay(device_id, date);
222 ret_val = store->get_mean(period_type_param);
223 if ((ret_val != NULL) &&
224 (period_type_param != PERIOD_MINUTELY) &&
225 (period_type_param != PERIOD_SECONDLY)) {
226 // no need cache second or minute data
227 save(fname, ret_val, 4);
237 DataRange *StoreCache::get_sum(EnumSummaryPeriod period_type_param) {
245 fname = get_file_name(device_id,
249 if (store_data == NULL) {
250 if (access(fname.c_str(), R_OK) == 0) {
254 if (store_data != NULL) {
255 row_count = store_data->get_count();
257 ret_val = new DataRange();
258 dta = store_data->get(0);
263 if (ret_val == NULL) {
264 switch(period_type_param) {
266 case PERIOD_MONTHLY: {
276 cur_date = date->clone();
277 max_date = get_scanning_limit_date(period_type_param);
281 while(cur_date->before(max_date)) {
282 if (period_type_param == PERIOD_YEARLY) {
283 store = new StoreCache(device_id, cur_date);
284 dr = store->get_sum(PERIOD_MONTHLY);
287 if (StoreDay::exist(device_id, cur_date, false)) {
288 store = new StoreDay(device_id, cur_date);
289 dr = store->get_sum(PERIOD_DAILY);
292 // data not found for that day, try to find next date containing data
293 StoreDay::get_next_date_with_data(device_id,
300 cur_data = dr->get_first();
301 if (cur_data != NULL) {
303 if (res_data == NULL) {
307 val_cnt = res_data->get_value_count();
308 for (ii = 0; ii < val_cnt; ii++) {
309 res_data->value_arr[ii] = res_data->value_arr[ii] + cur_data->value_arr[ii];
317 if (period_type_param == PERIOD_YEARLY) {
318 cur_date->next_month();
321 cur_date->next_day();
324 if ((res_data != NULL) &&
326 ret_val = new DataRange(res_data);
327 save(fname, ret_val, 4);
336 case PERIOD_MINUTELY:
337 case PERIOD_SECONDLY:
338 if (StoreDay::exist(device_id, date, false)) {
339 store = new StoreDay(device_id, date);
340 ret_val = store->get_sum(period_type_param);
341 if ((ret_val != NULL) &&
342 (period_type_param != PERIOD_MINUTELY) &&
343 (period_type_param != PERIOD_SECONDLY)) {
344 // no need cache second or minute data
345 save(fname, ret_val, 4);
355 DataRange *StoreCache::get_delta(EnumSummaryPeriod period_type_param) {
363 fname = get_file_name(device_id,
367 if (store_data == NULL) {
368 if (access(fname.c_str(), R_OK) == 0) {
369 // read from cache file
373 if (store_data != NULL) {
374 row_count = store_data->get_count();
376 ret_val = new DataRange();
377 dta = store_data->get(0);
382 if (ret_val == NULL) {
383 switch(period_type_param) {
384 case PERIOD_YEARLY: {
390 first_data = get_oldest_data(date, device_id, PERIOD_YEARLY);
391 if (first_data != NULL) {
392 last_data = get_latest_data(date, device_id, PERIOD_YEARLY);
393 if (last_data != NULL) {
394 ret_val = new DataRange();
395 cnt = last_data->get_value_count();
396 for (ii = 0; ii < cnt; ii++) {
397 last_data->value_arr[ii] = last_data->value_arr[ii] - first_data->value_arr[ii];
399 ret_val->add(last_data);
403 save(fname, ret_val, 4);
406 log_error("Could not read first or last data item from device %s for year: %d", device_id.c_str(), date->year);
410 case PERIOD_MONTHLY: {
419 cur_date = date->clone();
420 max_date = date->clone();
421 max_date->next_month();
424 while(cur_date->before(max_date)) {
425 if (StoreDay::exist(device_id,
428 store = new StoreDay(device_id, cur_date);
429 if (first_data == NULL) {
430 cur_data = store->get_oldest_data();
431 if (cur_data != NULL) {
432 first_data = cur_data->clone();
433 last_data = cur_data->clone();
437 cur_data = store->get_latest_data();
438 if (cur_data != NULL) {
439 if (last_data != NULL) {
442 last_data = cur_data;
445 cur_date->next_day();
448 // data not found for that day, try to find next date containing data
449 StoreDay::get_next_date_with_data(device_id,
456 if (first_data != NULL) {
457 if (last_data == NULL) {
458 last_data = first_data->clone();
460 cnt = last_data->get_value_count();
461 for (ii = 0; ii < cnt; ii++) {
462 last_data->value_arr[ii] = last_data->value_arr[ii] - first_data->value_arr[ii];
464 cur_date = first_data->get_date().clone();
465 last_data->set_date(cur_date);
467 ret_val = new DataRange(last_data);
470 save(fname, ret_val, 4);
476 case PERIOD_MINUTELY:
477 case PERIOD_SECONDLY:
478 if (StoreDay::exist(device_id, date, false)) {
479 store = new StoreDay(device_id, date);
480 ret_val = store->get_delta(period_type_param);
481 if ((period_type_param != PERIOD_MINUTELY) ||
482 (period_type_param != PERIOD_SECONDLY)) {
483 // no need cache second or minute data
484 save(fname, ret_val, 4);
494 DataRange *StoreCache::get_max(EnumSummaryPeriod period_type_param) {
502 fname = get_file_name(device_id,
506 if (store_data == NULL) {
507 if (access(fname.c_str(), R_OK) == 0) {
511 if (store_data != NULL) {
512 row_count = store_data->get_count();
514 ret_val = new DataRange();
515 dta = store_data->get(0);
520 if (ret_val == NULL) {
521 switch(period_type_param) {
523 case PERIOD_MONTHLY: {
533 cur_date = date->clone();
534 max_date = get_scanning_limit_date(period_type_param);
538 while(cur_date->before(max_date)) {
539 if (period_type_param == PERIOD_YEARLY) {
540 store = new StoreCache(device_id, cur_date);
541 dr = store->get_max(PERIOD_MONTHLY);
544 if (StoreDay::exist(device_id, cur_date, false)) {
545 store = new StoreDay(device_id, cur_date);
546 dr = store->get_max(PERIOD_DAILY);
549 StoreDay::get_next_date_with_data(device_id,
556 cur_data = dr->get_first();
557 if (cur_data != NULL) {
559 if (res_data == NULL) {
563 val_cnt = res_data->get_value_count();
565 for (ii = 0; ii < val_cnt; ii++) {
566 if (cur_data->value_arr[ii] > res_data->value_arr[ii]) {
567 res_data->value_arr[ii] = cur_data->value_arr[ii];
574 new_date = cur_data->get_date();
575 res_data->set_date(&new_date);
583 if (period_type_param == PERIOD_YEARLY) {
584 cur_date->next_month();
587 cur_date->next_day();
590 if ((res_data != NULL) &&
592 ret_val = new DataRange(res_data);
593 save(fname, ret_val, 4);
602 case PERIOD_MINUTELY:
603 case PERIOD_SECONDLY:
604 if (StoreDay::exist(device_id, date, false)) {
605 store = new StoreDay(device_id, date);
606 ret_val = store->get_max(period_type_param);
607 if ((period_type_param != PERIOD_MINUTELY) ||
608 (period_type_param != PERIOD_SECONDLY)) {
609 // no need cache second or minute data
610 save(fname, ret_val, 4);
620 DataRange *StoreCache::get_min(EnumSummaryPeriod period_type_param) {
628 fname = get_file_name(device_id,
632 if (store_data == NULL) {
633 if (access(fname.c_str(), R_OK) == 0) {
637 if (store_data != NULL) {
638 row_count = store_data->get_count();
640 ret_val = new DataRange();
641 dta = store_data->get(0);
646 if (ret_val == NULL) {
647 switch(period_type_param) {
649 case PERIOD_MONTHLY: {
659 cur_date = date->clone();
660 max_date = get_scanning_limit_date(period_type_param);
664 while(cur_date->before(max_date)) {
665 if (period_type_param == PERIOD_YEARLY) {
666 store = new StoreCache(device_id, cur_date);
667 dr = store->get_min(PERIOD_MONTHLY);
670 if (StoreDay::exist(device_id, cur_date, false)) {
671 store = new StoreDay(device_id, cur_date);
672 dr = store->get_min(PERIOD_DAILY);
675 StoreDay::get_next_date_with_data(device_id,
682 cur_data = dr->get_first();
683 if (cur_data != NULL) {
685 if (res_data == NULL) {
689 val_cnt = res_data->get_value_count();
691 for (ii = 0; ii < val_cnt; ii++) {
692 if (cur_data->value_arr[ii] < res_data->value_arr[ii]) {
693 res_data->value_arr[ii] = cur_data->value_arr[ii];
700 new_date = cur_data->get_date();
701 res_data->set_date(&new_date);
709 if (period_type_param == PERIOD_YEARLY) {
710 cur_date->next_month();
713 cur_date->next_day();
716 if ((res_data != NULL) &&
718 ret_val = new DataRange(res_data);
719 save(fname, ret_val, 4);
728 case PERIOD_MINUTELY:
729 case PERIOD_SECONDLY:
730 if (StoreDay::exist(device_id, date, false)) {
731 store = new StoreDay(device_id, date);
732 ret_val = store->get_min(period_type_param);
733 if ((period_type_param != PERIOD_MINUTELY) ||
734 (period_type_param != PERIOD_SECONDLY)) {
735 // no need cache second or minute data
736 save(fname, ret_val, 4);
746 void StoreCache::save(std::string fname_param, plp::DataRange *datarange_param, int decimal_count_param) {
753 cnt = datarange_param->get_count();
755 //log_info("[%s] cacheing %d data values.\n", device_id.c_str(), cnt);
756 ostream = FileUtil::open_for_writing(fname_param.c_str());
757 if ((ostream != NULL) &&
758 (ostream->is_open() == true)) {
759 // TODO: add mutex to protect string_list while it's read and emptied
760 for(ii = 0; ii < cnt; ii++) {
761 data = datarange_param->get(ii);
763 line = data->to_string(decimal_count_param);
764 if (line.length() > 0) {
765 *ostream << line << endl;
772 log_error("[%s] File open for data save failed: %s\n", device_id.c_str(), fname_param.c_str());
774 if (ostream != NULL) {
780 Data *StoreCache::get_oldest_data(Date *date_param,
781 string device_id_param,
782 EnumSummaryPeriod period_type_param) {
787 vector<string> mon_vcr;
788 vector<string> dta_vcr;
797 if (period_type_param == PERIOD_YEARLY) {
798 snprintf(buffer, 30, "%d", date_param->year);
799 year_name.append(buffer);
800 device_dir = DeviceConfig::get_base_dir_name();
801 device_dir = FileUtil::concat_paths(device_dir, device_id_param);
802 year_dr = FileUtil::concat_paths(device_dir, year_name);
803 mon_vcr = FileUtil::get_subdirectories(year_dr);
804 for (ii = 0; ii < mon_vcr.size(); ii++) {
805 mon_dr = mon_vcr.at(ii);
806 mon_dr = FileUtil::concat_paths(year_dr, mon_dr);
807 // scan data files from month dir
808 dta_vcr = FileUtil::get_data_files(mon_dr);
809 size = dta_vcr.size();
811 f_name = dta_vcr.at(0);
812 f_name = FileUtil::concat_paths(mon_dr, f_name);
813 store = new StoreDay(f_name);
814 ret_val = store->get_oldest_data();
820 else if (period_type_param == PERIOD_MONTHLY) {
822 snprintf(buffer, 30, "%d", date_param->year);
823 year_name.append(buffer);
824 device_dir = DeviceConfig::get_base_dir_name();
825 device_dir = FileUtil::concat_paths(device_dir, device_id_param);
826 year_dr = FileUtil::concat_paths(device_dir, year_name);
827 snprintf(buffer, 30, "%02d", date_param->month);
828 mon_dr.append(buffer);
829 mon_dr = FileUtil::concat_paths(year_dr, mon_dr);
830 // scan data files from month dir
831 dta_vcr = FileUtil::get_data_files(mon_dr);
832 size = dta_vcr.size();
834 f_name = dta_vcr.at(0);
835 f_name = FileUtil::concat_paths(mon_dr, f_name);
836 store = new StoreDay(f_name);
837 ret_val = store->get_oldest_data();
843 store = new StoreDay(device_id_param, date_param);
844 ret_val = store->get_oldest_data();
850 Data *StoreCache::get_latest_data(Date *date_param,
851 string device_id_param,
852 EnumSummaryPeriod period_type_param) {
855 vector<string> mon_vcr;
856 vector<string> dta_vcr;
867 if (period_type_param == PERIOD_YEARLY) {
868 snprintf(buffer, 30, "%d", date_param->year);
869 year_name.append(buffer);
870 device_dir = DeviceConfig::get_base_dir_name();
871 device_dir = FileUtil::concat_paths(device_dir, device_id_param);
872 year_dr = FileUtil::concat_paths(device_dir, year_name);
873 mon_vcr = FileUtil::get_subdirectories(year_dr);
874 for (ii = mon_vcr.size() - 1; ii >= 0; ii--) {
875 mon_dr = mon_vcr.at(ii);
876 mon_dr = FileUtil::concat_paths(year_dr, mon_dr);
877 // scan data files from month dir
878 dta_vcr = FileUtil::get_data_files(mon_dr);
879 size = dta_vcr.size();
881 f_name = dta_vcr.at(size - 1);
882 f_name = FileUtil::concat_paths(mon_dr, f_name);
883 store = new StoreDay(f_name);
884 ret_val = store->get_latest_data();
890 else if (period_type_param == PERIOD_MONTHLY) {
892 snprintf(buffer, 30, "%d", date_param->year);
893 year_name.append(buffer);
894 device_dir = DeviceConfig::get_base_dir_name();
895 device_dir = FileUtil::concat_paths(device_dir, device_id_param);
896 year_dr = FileUtil::concat_paths(device_dir, year_name);
897 snprintf(buffer, 30, "%02d", date_param->month);
898 mon_dr.append(buffer);
899 mon_dr = FileUtil::concat_paths(year_dr, mon_dr);
900 // scan data files from month dir
901 dta_vcr = FileUtil::get_data_files(mon_dr);
902 size = dta_vcr.size();
904 f_name = dta_vcr.at(size - 1);
905 f_name = FileUtil::concat_paths(mon_dr, f_name);
906 store = new StoreDay(f_name);
907 ret_val = store->get_latest_data();
913 store = new StoreDay(device_id_param, date_param);
914 ret_val = store->get_latest_data();