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);
159 while(cur_date->before(max_date)) {
162 if (period_type_param == PERIOD_YEARLY) {
163 store = new StoreCache(device_id, cur_date);
164 dr = store->get_mean(PERIOD_MONTHLY);
167 if (StoreDay::exist(device_id, cur_date, false)) {
168 store = new StoreDay(device_id, cur_date);
169 dr = store->get_mean(PERIOD_DAILY);
172 // data not found for that day, try to find next date containing data
173 StoreDay::get_next_date_with_data(device_id,
180 cur_data = dr->get_first();
181 if (cur_data != NULL) {
183 if (res_data == NULL) {
185 val_cnt = res_data->get_value_count();
188 for (ii = 0; ii < val_cnt; ii++) {
189 res_data->value_arr[ii] = res_data->value_arr[ii] + cur_data->value_arr[ii];
198 if (period_type_param == PERIOD_YEARLY) {
199 cur_date->next_month();
202 cur_date->next_day();
205 if ((res_data != NULL) &&
207 for (ii = 0; ii < val_cnt; ii++) {
208 res_data->value_arr[ii] = res_data->value_arr[ii] / cnt;
210 ret_val = new DataRange(res_data);
211 save(fname, ret_val, 4);
220 case PERIOD_MINUTELY:
221 case PERIOD_SECONDLY:
222 if (StoreDay::exist(device_id, date, false)) {
225 store = new StoreDay(device_id, date);
226 ret_val = store->get_mean(period_type_param);
227 if ((ret_val != NULL) &&
228 (period_type_param != PERIOD_MINUTELY) &&
229 (period_type_param != PERIOD_SECONDLY)) {
230 // no need cache second or minute data
231 save(fname, ret_val, 4);
241 DataRange *StoreCache::get_sum(EnumSummaryPeriod period_type_param) {
249 fname = get_file_name(device_id,
253 if (store_data == NULL) {
254 if (access(fname.c_str(), R_OK) == 0) {
258 if (store_data != NULL) {
259 row_count = store_data->get_count();
261 ret_val = new DataRange();
262 dta = store_data->get(0);
267 if (ret_val == NULL) {
268 switch(period_type_param) {
270 case PERIOD_MONTHLY: {
280 cur_date = date->clone();
281 max_date = get_scanning_limit_date(period_type_param);
285 while(cur_date->before(max_date)) {
288 if (period_type_param == PERIOD_YEARLY) {
289 store = new StoreCache(device_id, cur_date);
290 dr = store->get_sum(PERIOD_MONTHLY);
293 if (StoreDay::exist(device_id, cur_date, false)) {
294 store = new StoreDay(device_id, cur_date);
295 dr = store->get_sum(PERIOD_DAILY);
298 // data not found for that day, try to find next date containing data
299 StoreDay::get_next_date_with_data(device_id,
306 cur_data = dr->get_first();
307 if (cur_data != NULL) {
309 if (res_data == NULL) {
313 val_cnt = res_data->get_value_count();
314 for (ii = 0; ii < val_cnt; ii++) {
315 res_data->value_arr[ii] = res_data->value_arr[ii] + cur_data->value_arr[ii];
324 if (period_type_param == PERIOD_YEARLY) {
325 cur_date->next_month();
328 cur_date->next_day();
331 if ((res_data != NULL) &&
333 ret_val = new DataRange(res_data);
334 save(fname, ret_val, 4);
343 case PERIOD_MINUTELY:
344 case PERIOD_SECONDLY:
345 if (StoreDay::exist(device_id, date, false)) {
346 store = new StoreDay(device_id, date);
347 ret_val = store->get_sum(period_type_param);
348 if ((ret_val != NULL) &&
349 (period_type_param != PERIOD_MINUTELY) &&
350 (period_type_param != PERIOD_SECONDLY)) {
351 // no need cache second or minute data
352 save(fname, ret_val, 4);
362 DataRange *StoreCache::get_delta(EnumSummaryPeriod period_type_param) {
370 fname = get_file_name(device_id,
374 if (store_data == NULL) {
375 if (access(fname.c_str(), R_OK) == 0) {
376 // read from cache file
380 if (store_data != NULL) {
381 row_count = store_data->get_count();
383 ret_val = new DataRange();
384 dta = store_data->get(0);
389 if (ret_val == NULL) {
390 switch(period_type_param) {
391 case PERIOD_YEARLY: {
397 first_data = get_oldest_data(date, device_id, PERIOD_YEARLY);
398 if (first_data != NULL) {
399 last_data = get_latest_data(date, device_id, PERIOD_YEARLY);
400 if (last_data != NULL) {
401 ret_val = new DataRange();
402 cnt = last_data->get_value_count();
403 for (ii = 0; ii < cnt; ii++) {
404 last_data->value_arr[ii] = last_data->value_arr[ii] - first_data->value_arr[ii];
406 ret_val->add(last_data);
410 save(fname, ret_val, 4);
413 log_error("Could not read first or last data item from device %s for year: %d", device_id.c_str(), date->year);
417 case PERIOD_MONTHLY: {
426 cur_date = date->clone();
427 max_date = date->clone();
428 max_date->next_month();
431 while(cur_date->before(max_date)) {
432 if (StoreDay::exist(device_id,
435 store = new StoreDay(device_id, cur_date);
436 if (first_data == NULL) {
437 cur_data = store->get_oldest_data();
438 if (cur_data != NULL) {
439 first_data = cur_data->clone();
440 last_data = cur_data->clone();
444 cur_data = store->get_latest_data();
445 if (cur_data != NULL) {
446 if (last_data != NULL) {
449 last_data = cur_data;
452 cur_date->next_day();
455 // data not found for that day, try to find next date containing data
456 StoreDay::get_next_date_with_data(device_id,
463 if (first_data != NULL) {
464 if (last_data == NULL) {
465 last_data = first_data->clone();
467 cnt = last_data->get_value_count();
468 for (ii = 0; ii < cnt; ii++) {
469 last_data->value_arr[ii] = last_data->value_arr[ii] - first_data->value_arr[ii];
471 cur_date = first_data->get_date().clone();
472 last_data->set_date(cur_date);
474 ret_val = new DataRange(last_data);
477 save(fname, ret_val, 4);
483 case PERIOD_MINUTELY:
484 case PERIOD_SECONDLY:
485 if (StoreDay::exist(device_id, date, false)) {
486 store = new StoreDay(device_id, date);
487 ret_val = store->get_delta(period_type_param);
488 if ((period_type_param != PERIOD_MINUTELY) ||
489 (period_type_param != PERIOD_SECONDLY)) {
490 // no need cache second or minute data
491 save(fname, ret_val, 4);
501 DataRange *StoreCache::get_max(EnumSummaryPeriod period_type_param) {
509 fname = get_file_name(device_id,
513 if (store_data == NULL) {
514 if (access(fname.c_str(), R_OK) == 0) {
518 if (store_data != NULL) {
519 row_count = store_data->get_count();
521 ret_val = new DataRange();
522 dta = store_data->get(0);
527 if (ret_val == NULL) {
528 switch(period_type_param) {
530 case PERIOD_MONTHLY: {
540 cur_date = date->clone();
541 max_date = get_scanning_limit_date(period_type_param);
545 while(cur_date->before(max_date)) {
548 if (period_type_param == PERIOD_YEARLY) {
549 store = new StoreCache(device_id, cur_date);
550 dr = store->get_max(PERIOD_MONTHLY);
553 if (StoreDay::exist(device_id, cur_date, false)) {
554 store = new StoreDay(device_id, cur_date);
555 dr = store->get_max(PERIOD_DAILY);
558 StoreDay::get_next_date_with_data(device_id,
565 cur_data = dr->get_first();
566 if (cur_data != NULL) {
568 if (res_data == NULL) {
572 val_cnt = res_data->get_value_count();
574 for (ii = 0; ii < val_cnt; ii++) {
575 if (cur_data->value_arr[ii] > res_data->value_arr[ii]) {
576 res_data->value_arr[ii] = cur_data->value_arr[ii];
583 new_date = cur_data->get_date();
584 res_data->set_date(&new_date);
593 if (period_type_param == PERIOD_YEARLY) {
594 cur_date->next_month();
597 cur_date->next_day();
600 if ((res_data != NULL) &&
602 ret_val = new DataRange(res_data);
603 save(fname, ret_val, 4);
612 case PERIOD_MINUTELY:
613 case PERIOD_SECONDLY:
614 if (StoreDay::exist(device_id, date, false)) {
615 store = new StoreDay(device_id, date);
616 ret_val = store->get_max(period_type_param);
617 if ((period_type_param != PERIOD_MINUTELY) ||
618 (period_type_param != PERIOD_SECONDLY)) {
619 // no need cache second or minute data
620 save(fname, ret_val, 4);
630 DataRange *StoreCache::get_min(EnumSummaryPeriod period_type_param) {
638 fname = get_file_name(device_id,
642 if (store_data == NULL) {
643 if (access(fname.c_str(), R_OK) == 0) {
647 if (store_data != NULL) {
648 row_count = store_data->get_count();
650 ret_val = new DataRange();
651 dta = store_data->get(0);
656 if (ret_val == NULL) {
657 switch(period_type_param) {
659 case PERIOD_MONTHLY: {
669 cur_date = date->clone();
670 max_date = get_scanning_limit_date(period_type_param);
674 while(cur_date->before(max_date)) {
677 if (period_type_param == PERIOD_YEARLY) {
678 store = new StoreCache(device_id, cur_date);
679 dr = store->get_min(PERIOD_MONTHLY);
682 if (StoreDay::exist(device_id, cur_date, false)) {
683 store = new StoreDay(device_id, cur_date);
684 dr = store->get_min(PERIOD_DAILY);
687 StoreDay::get_next_date_with_data(device_id,
694 cur_data = dr->get_first();
695 if (cur_data != NULL) {
697 if (res_data == NULL) {
701 val_cnt = res_data->get_value_count();
703 for (ii = 0; ii < val_cnt; ii++) {
704 if (cur_data->value_arr[ii] < res_data->value_arr[ii]) {
705 res_data->value_arr[ii] = cur_data->value_arr[ii];
712 new_date = cur_data->get_date();
713 res_data->set_date(&new_date);
722 if (period_type_param == PERIOD_YEARLY) {
723 cur_date->next_month();
726 cur_date->next_day();
729 if ((res_data != NULL) &&
731 ret_val = new DataRange(res_data);
732 save(fname, ret_val, 4);
741 case PERIOD_MINUTELY:
742 case PERIOD_SECONDLY:
743 if (StoreDay::exist(device_id, date, false)) {
744 store = new StoreDay(device_id, date);
745 ret_val = store->get_min(period_type_param);
746 if ((period_type_param != PERIOD_MINUTELY) ||
747 (period_type_param != PERIOD_SECONDLY)) {
748 // no need cache second or minute data
749 save(fname, ret_val, 4);
759 void StoreCache::save(std::string fname_param, plp::DataRange *datarange_param, int decimal_count_param) {
766 cnt = datarange_param->get_count();
768 //log_info("[%s] cacheing %d data values.\n", device_id.c_str(), cnt);
769 ostream = FileUtil::open_for_writing(fname_param.c_str());
770 if ((ostream != NULL) &&
771 (ostream->is_open() == true)) {
772 // TODO: add mutex to protect string_list while it's read and emptied
773 for(ii = 0; ii < cnt; ii++) {
774 data = datarange_param->get(ii);
776 line = data->to_string(decimal_count_param);
777 if (line.length() > 0) {
778 *ostream << line << endl;
785 log_error("[%s] File open for data save failed: %s\n", device_id.c_str(), fname_param.c_str());
787 if (ostream != NULL) {
793 Data *StoreCache::get_oldest_data(Date *date_param,
794 string device_id_param,
795 EnumSummaryPeriod period_type_param) {
800 vector<string> mon_vcr;
801 vector<string> dta_vcr;
810 if (period_type_param == PERIOD_YEARLY) {
811 snprintf(buffer, 30, "%d", date_param->year);
812 year_name.append(buffer);
813 device_dir = DeviceConfig::get_base_dir_name();
814 device_dir = FileUtil::concat_paths(device_dir, device_id_param);
815 year_dr = FileUtil::concat_paths(device_dir, year_name);
816 mon_vcr = FileUtil::get_subdirectories(year_dr);
817 for (ii = 0; ii < mon_vcr.size(); ii++) {
818 mon_dr = mon_vcr.at(ii);
819 mon_dr = FileUtil::concat_paths(year_dr, mon_dr);
820 // scan data files from month dir
821 dta_vcr = FileUtil::get_data_files(mon_dr);
822 size = dta_vcr.size();
824 f_name = dta_vcr.at(0);
825 f_name = FileUtil::concat_paths(mon_dr, f_name);
826 store = new StoreDay(f_name);
827 ret_val = store->get_oldest_data();
833 else if (period_type_param == PERIOD_MONTHLY) {
835 snprintf(buffer, 30, "%d", date_param->year);
836 year_name.append(buffer);
837 device_dir = DeviceConfig::get_base_dir_name();
838 device_dir = FileUtil::concat_paths(device_dir, device_id_param);
839 year_dr = FileUtil::concat_paths(device_dir, year_name);
840 snprintf(buffer, 30, "%02d", date_param->month);
841 mon_dr.append(buffer);
842 mon_dr = FileUtil::concat_paths(year_dr, mon_dr);
843 // scan data files from month dir
844 dta_vcr = FileUtil::get_data_files(mon_dr);
845 size = dta_vcr.size();
847 f_name = dta_vcr.at(0);
848 f_name = FileUtil::concat_paths(mon_dr, f_name);
849 store = new StoreDay(f_name);
850 ret_val = store->get_oldest_data();
856 store = new StoreDay(device_id_param, date_param);
857 ret_val = store->get_oldest_data();
863 Data *StoreCache::get_latest_data(Date *date_param,
864 string device_id_param,
865 EnumSummaryPeriod period_type_param) {
868 vector<string> mon_vcr;
869 vector<string> dta_vcr;
880 if (period_type_param == PERIOD_YEARLY) {
881 snprintf(buffer, 30, "%d", date_param->year);
882 year_name.append(buffer);
883 device_dir = DeviceConfig::get_base_dir_name();
884 device_dir = FileUtil::concat_paths(device_dir, device_id_param);
885 year_dr = FileUtil::concat_paths(device_dir, year_name);
886 mon_vcr = FileUtil::get_subdirectories(year_dr);
887 for (ii = mon_vcr.size() - 1; ii >= 0; ii--) {
888 mon_dr = mon_vcr.at(ii);
889 mon_dr = FileUtil::concat_paths(year_dr, mon_dr);
890 // scan data files from month dir
891 dta_vcr = FileUtil::get_data_files(mon_dr);
892 size = dta_vcr.size();
894 f_name = dta_vcr.at(size - 1);
895 f_name = FileUtil::concat_paths(mon_dr, f_name);
896 store = new StoreDay(f_name);
897 ret_val = store->get_latest_data();
903 else if (period_type_param == PERIOD_MONTHLY) {
905 snprintf(buffer, 30, "%d", date_param->year);
906 year_name.append(buffer);
907 device_dir = DeviceConfig::get_base_dir_name();
908 device_dir = FileUtil::concat_paths(device_dir, device_id_param);
909 year_dr = FileUtil::concat_paths(device_dir, year_name);
910 snprintf(buffer, 30, "%02d", date_param->month);
911 mon_dr.append(buffer);
912 mon_dr = FileUtil::concat_paths(year_dr, mon_dr);
913 // scan data files from month dir
914 dta_vcr = FileUtil::get_data_files(mon_dr);
915 size = dta_vcr.size();
917 f_name = dta_vcr.at(size - 1);
918 f_name = FileUtil::concat_paths(mon_dr, f_name);
919 store = new StoreDay(f_name);
920 ret_val = store->get_latest_data();
926 store = new StoreDay(device_id_param, date_param);
927 ret_val = store->get_latest_data();