]> pilppa.org Git - lib1wire.git/blob - src/StoreCache.cc
b444f32f90f7ed41228a24dc86fa26f1978d387b
[lib1wire.git] / src / StoreCache.cc
1 /*
2  * StoreCache.cc
3  *
4  *  Created on: Jan 6, 2011
5  *      Author: lamikr
6  */
7 #include <plp/log.h>
8
9 #include "Store.hh"
10 #include "StoreCache.hh"
11 #include "StoreDay.hh"
12 #include "DeviceConfig.hh"
13 #include "DeviceData.hh"
14 #include "W1Util.hh"
15
16 using namespace std;
17 using namespace plp;
18 using namespace w1;
19
20 StoreCache::StoreCache(string device_id_param,
21         Date *date_time_param): Store(device_id_param, date_time_param) {
22 }
23
24 StoreCache::~StoreCache() {
25 }
26
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) {
31         string  ret_val;
32         char    buffer[30];
33         string  bd_name;
34
35         bd_name = DeviceConfig::get_base_dir_name();
36         bd_name = W1Util::concat_paths(bd_name, CACHE_DIR_NAME);
37         bd_name = W1Util::concat_paths(bd_name, device_id_param);
38         bd_name = W1Util::concat_paths(bd_name, SUMMARY_PERIOD_NAMES_ARRAY[period_type_param]);
39         bd_name = W1Util::concat_paths(bd_name, CALCULATION_TYPE_NAMES_ARRAY[calc_type_param]);
40         if (period_type_param == PERIOD_YEARLY) {
41                 ret_val = bd_name;
42         }
43         else if (period_type_param == PERIOD_MONTHLY) {
44                 snprintf(buffer, 30, "%d", date_time_param->year);
45                 ret_val = bd_name + "/" + buffer;
46         }
47         else {
48                 snprintf(buffer, 30, "%d/%02d", date_time_param->year, date_time_param->month);
49                 ret_val = bd_name + "/" + buffer;
50         }
51         return ret_val;
52 }
53
54 string StoreCache::get_file_name(string device_id_param,
55                                 Date *date_time_param,
56                                 EnumSummaryPeriod period_type_param,
57                                 EnumSummaryCalculationType calc_type_param) {
58         string  ret_val;
59         string  fname;
60         char    buffer[30];
61
62         if (period_type_param == PERIOD_YEARLY) {
63                 snprintf(buffer, 30, "%d", date_time_param->year);
64         }
65         else if (period_type_param == PERIOD_MONTHLY) {
66                 snprintf(buffer, 30, "%d-%02d",
67                         date_time_param->year,
68                         date_time_param->month);
69         }
70         else {
71                 snprintf(buffer, 30, "%d-%02d-%02d",
72                         date_time_param->year,
73                         date_time_param->month,
74                         date_time_param->day);
75         }
76         fname   = buffer;
77         fname   = fname + DATAFILE_SUFFIX;
78         ret_val = get_dir_name(device_id_param, date_time_param, period_type_param, calc_type_param);
79         ret_val = W1Util::concat_paths(ret_val, fname);
80         return ret_val;
81 }
82
83 DataRange *StoreCache::get_mean(EnumSummaryPeriod period_type_param) {
84         int             row_count;
85         DataRange       *ret_val;
86         Data            *dta;
87         string          fname;
88
89         ret_val = NULL;
90         fname   = get_file_name(device_id,
91                                 date,
92                                 period_type_param,
93                                 MEAN);
94         if (store_data == NULL) {
95                 if (access(fname.c_str(), R_OK) == 0) {
96                         load(fname);
97                 }
98         }
99         if (store_data != NULL) {
100                 row_count       = store_data->get_count();
101                 if (row_count > 0) {
102                         ret_val = new DataRange();
103                         dta     = store_data->get(0);
104                         ret_val->add(dta);
105                         delete(dta);
106                 }
107         }
108         if (ret_val == NULL) {
109                 switch(period_type_param) {
110                         case PERIOD_YEARLY:
111                         case PERIOD_MONTHLY:
112                         {
113                                         Data            *cur_data;
114                                         Data            *res_data;
115                                         Date            *cur_date;
116                                         Date            *max_date;
117                                         int             ii;
118                                         int             cnt;
119                                         int             val_cnt;
120                                         DataRange       *dr;
121                                         Store           *store;
122
123                                         cur_date        = date->clone();
124                                         max_date        = date->clone();
125                                         if (period_type_param == PERIOD_YEARLY) {
126                                                 max_date->next_year();
127                                         }
128                                         else {
129                                                 max_date->next_month();
130                                         }
131                                         cur_data        = NULL;
132                                         res_data        = NULL;
133                                         cnt             = 0;
134                                         while(cur_date->before(max_date)) {
135                                                 if (period_type_param == PERIOD_YEARLY) {
136                                                         store   = new StoreCache(device_id, cur_date);
137                                                         dr      = store->get_mean(PERIOD_MONTHLY);
138                                                 }
139                                                 else {
140                                                         store   = new StoreDay(device_id, cur_date);
141                                                         dr      = store->get_mean(PERIOD_DAILY);
142                                                 }
143                                                 if (dr != NULL) {
144                                                         cur_data        = dr->get_first();
145                                                         if (cur_data != NULL) {
146                                                                 cnt++;
147                                                                 if (res_data == NULL) {
148                                                                         res_data        = cur_data;
149                                                                         val_cnt         = res_data->get_value_count();
150                                                                 }
151                                                                 else {
152                                                                         for (ii = 0; ii < val_cnt; ii++) {
153                                                                                 res_data->value_arr[ii] = res_data->value_arr[ii] + cur_data->value_arr[ii];
154                                                                         }
155                                                                         delete(cur_data);
156                                                                 }
157                                                         }
158                                                         delete(dr);
159                                                 }
160                                                 delete(store);
161                                                 if (period_type_param == PERIOD_YEARLY) {
162                                                         cur_date->next_month();
163                                                 }
164                                                 else {
165                                                         cur_date->next_day();
166                                                 }
167                                         }
168                                         if ((res_data != NULL) &&
169                                             (cnt > 0)) {
170                                                 for (ii = 0; ii < val_cnt; ii++) {
171                                                         res_data->value_arr[ii] = res_data->value_arr[ii] / cnt;
172                                                 }
173                                                 ret_val = new DataRange(res_data);
174                                                 save(fname, ret_val, 4);
175                                                 delete(res_data);
176                                         }
177                                         delete(cur_date);
178                                         delete(max_date);
179                                 }
180                                 break;
181                         case PERIOD_DAILY:
182                         case PERIOD_HOURLY:
183                         case PERIOD_MINUTELY:
184                         case PERIOD_SECONDLY: {
185                                         StoreDay        *store;
186
187                                         store   = new StoreDay(device_id, date);
188                                         ret_val = store->get_mean(period_type_param);
189                                         save(fname, ret_val, 4);
190                                         delete(store);
191                                 }
192                                 break;
193                 }
194         }
195         return ret_val;
196 }
197
198 DataRange *StoreCache::get_sum(EnumSummaryPeriod period_type_param) {
199         int             row_count;
200         DataRange       *ret_val;
201         Data            *dta;
202         string          fname;
203         Store           *store;
204
205         ret_val = NULL;
206         fname   = get_file_name(device_id,
207                                 date,
208                                 period_type_param,
209                                 SUM);
210         if (store_data == NULL) {
211                 if (access(fname.c_str(), R_OK) == 0) {
212                         load(fname);
213                 }
214         }
215         if (store_data != NULL) {
216                 row_count       = store_data->get_count();
217                 if (row_count > 0) {
218                         ret_val = new DataRange();
219                         dta     = store_data->get(0);
220                         ret_val->add(dta);
221                         delete(dta);
222                 }
223         }
224         if (ret_val == NULL) {
225                 switch(period_type_param) {
226                         case PERIOD_YEARLY:
227                         case PERIOD_MONTHLY: {
228                                         Data            *cur_data;
229                                         Data            *res_data;
230                                         Date            *cur_date;
231                                         Date            *max_date;
232                                         int             ii;
233                                         int             cnt;
234                                         int             val_cnt;
235                                         DataRange       *dr;
236
237                                         cur_date        = date->clone();
238                                         max_date        = date->clone();
239                                         if (period_type_param == PERIOD_YEARLY) {
240                                                 max_date->next_year();
241                                         }
242                                         else {
243                                                 max_date->next_month();
244                                         }
245                                         cur_data        = NULL;
246                                         res_data        = NULL;
247                                         cnt             = 0;
248                                         while(cur_date->before(max_date)) {
249                                                 if (period_type_param == PERIOD_YEARLY) {
250                                                         store   = new StoreCache(device_id, cur_date);
251                                                         dr      = store->get_sum(PERIOD_MONTHLY);
252                                                 }
253                                                 else {
254                                                         store   = new StoreDay(device_id, cur_date);
255                                                         dr      = store->get_sum(PERIOD_DAILY);
256                                                 }
257                                                 if (dr != NULL) {
258                                                         cur_data        = dr->get_first();
259                                                         if (cur_data != NULL) {
260                                                                 cnt++;
261                                                                 if (res_data == NULL) {
262                                                                         res_data        = cur_data;
263                                                                 }
264                                                                 else {
265                                                                         val_cnt = res_data->get_value_count();
266                                                                         for (ii = 0; ii < val_cnt; ii++) {
267                                                                                 res_data->value_arr[ii] = res_data->value_arr[ii] + cur_data->value_arr[ii];
268                                                                         }
269                                                                         delete(cur_data);
270                                                                 }
271                                                         }
272                                                         delete(dr);
273                                                 }
274                                                 delete(store);
275                                                 if (period_type_param == PERIOD_YEARLY) {
276                                                         cur_date->next_month();
277                                                 }
278                                                 else {
279                                                         cur_date->next_day();
280                                                 }
281                                         }
282                                         if ((res_data != NULL) &&
283                                             (cnt > 0)) {
284                                                 ret_val = new DataRange(res_data);
285                                                 save(fname, ret_val, 4);
286                                                 delete(res_data);
287                                         }
288                                         delete(cur_date);
289                                         delete(max_date);
290                                 }
291                                 break;
292                         case PERIOD_DAILY:
293                         case PERIOD_HOURLY:
294                         case PERIOD_MINUTELY:
295                         case PERIOD_SECONDLY:
296                                 store   = new StoreDay(device_id, date);
297                                 ret_val = store->get_sum(period_type_param);
298                                 save(fname, ret_val, 4);
299                                 delete(store);
300                                 break;
301                 }
302         }
303         return ret_val;
304 }
305
306 DataRange *StoreCache::get_delta(EnumSummaryPeriod period_type_param) {
307         int             row_count;
308         DataRange       *ret_val;
309         Data            *dta;
310         string          fname;
311         StoreDay        *store;
312
313         ret_val = NULL;
314         fname   = get_file_name(device_id,
315                                 date,
316                                 period_type_param,
317                                 DELTA);
318         if (store_data == NULL) {
319                 if (access(fname.c_str(), R_OK) == 0) {
320                         // read from cache file
321                         load(fname);
322                 }
323         }
324         if (store_data != NULL) {
325                 row_count       = store_data->get_count();
326                 if (row_count > 0) {
327                         ret_val = new DataRange();
328                         dta     = store_data->get(0);
329                         ret_val->add(dta);
330                         delete(dta);
331                 }
332         }
333         if (ret_val == NULL) {
334                 switch(period_type_param) {
335                         case PERIOD_YEARLY: {
336                                         Data    *first_data;
337                                         Data    *last_data;
338                                         int     ii;
339                                         int     cnt;
340
341                                         first_data      = get_year_oldest_data();
342                                         if (first_data != NULL) {
343                                                 last_data       = get_year_newest_data();
344                                                 if (last_data != NULL) {
345                                                         ret_val         = new DataRange();
346                                                         cnt             = last_data->get_value_count();
347                                                         for (ii = 0; ii < cnt; ii++) {
348                                                                 last_data->value_arr[ii]        = last_data->value_arr[ii] - first_data->value_arr[ii];
349                                                         }
350                                                         ret_val->add(last_data);
351                                                         delete(last_data);
352                                                 }
353                                                 delete(first_data);
354                                                 save(fname, ret_val, 4);
355                                         }
356                                         else {
357                                                 log_error("Could not read first or last data item from device %s for year: %d", device_id.c_str(), date->year);
358                                         }
359                                 }
360                                 break;
361                         case PERIOD_MONTHLY: {
362                                         Data    *first_data;
363                                         Data    *last_data;
364                                         Data    *cur_data;
365                                         Date    *cur_date;
366                                         Date    *limit_date;
367                                         int     ii;
368                                         int     cnt;
369
370                                         cur_date        = date->clone();
371                                         limit_date      = date->clone();
372                                         limit_date->next_month();
373                                         first_data      = NULL;
374                                         last_data       = NULL;
375                                         while(cur_date->before(limit_date)) {
376                                                 store   = new StoreDay(device_id, cur_date);
377                                                 if (first_data == NULL) {
378                                                         cur_data        = store->get_oldest_data();
379                                                         if (cur_data != NULL) {
380                                                                 first_data      = cur_data->clone();
381                                                                 last_data       = cur_data->clone();
382                                                                 delete(cur_data);
383                                                         }
384                                                 }
385                                                 cur_data        = store->get_newest_data();
386                                                 if (cur_data != NULL) {
387                                                         if (last_data != NULL) {
388                                                                 delete(last_data);
389                                                         }
390                                                         last_data       = cur_data;
391                                                 }
392                                                 delete(store);
393                                                 cur_date->next_day();
394                                         }
395                                         delete(cur_date);
396                                         delete(limit_date);
397                                         if (first_data != NULL) {
398                                                 if (last_data == NULL) {
399                                                         last_data       = first_data->clone();
400                                                 }
401                                                 cnt     = last_data->get_value_count();
402                                                 for (ii = 0; ii < cnt; ii++) {
403                                                         last_data->value_arr[ii]        = last_data->value_arr[ii] - first_data->value_arr[ii];
404                                                 }
405                                                 cur_date        = first_data->get_date().clone();
406                                                 last_data->set_date(cur_date);
407                                                 delete(cur_date);
408                                                 ret_val = new DataRange(last_data);
409                                                 delete(first_data);
410                                                 delete(last_data);
411                                                 save(fname, ret_val, 4);
412                                         }
413                                 }
414                                 break;
415                         case PERIOD_DAILY:
416                         case PERIOD_HOURLY:
417                         case PERIOD_MINUTELY:
418                         case PERIOD_SECONDLY:
419                                 store   = new StoreDay(device_id, date);
420                                 ret_val = store->get_delta(period_type_param);
421                                 save(fname, ret_val, 4);
422                                 delete(store);
423                                 break;
424                 }
425         }
426         return ret_val;
427 }
428
429 DataRange *StoreCache::get_max(EnumSummaryPeriod period_type_param) {
430         int             row_count;
431         DataRange       *ret_val;
432         Data            *dta;
433         string          fname;
434         Store           *store;
435
436         ret_val = NULL;
437         fname   = get_file_name(device_id,
438                                 date,
439                                 period_type_param,
440                                 MAX);
441         if (store_data == NULL) {
442                 if (access(fname.c_str(), R_OK) == 0) {
443                         load(fname);
444                 }
445         }
446         if (store_data != NULL) {
447                 row_count       = store_data->get_count();
448                 if (row_count > 0) {
449                         ret_val = new DataRange();
450                         dta     = store_data->get(0);
451                         ret_val->add(dta);
452                         delete(dta);
453                 }
454         }
455         if (ret_val == NULL) {
456                 switch(period_type_param) {
457                         case PERIOD_YEARLY:
458                         case PERIOD_MONTHLY: {
459                                         Data            *cur_data;
460                                         Data            *res_data;
461                                         Date            *cur_date;
462                                         Date            *max_date;
463                                         int             ii;
464                                         int             cnt;
465                                         int             val_cnt;
466                                         DataRange       *dr;
467
468                                         cur_date        = date->clone();
469                                         max_date        = date->clone();
470                                         if (period_type_param == PERIOD_YEARLY) {
471                                                 max_date->next_year();
472                                         }
473                                         else {
474                                                 max_date->next_month();
475                                         }
476                                         cur_data        = NULL;
477                                         res_data        = NULL;
478                                         cnt             = 0;
479                                         while(cur_date->before(max_date)) {
480                                                 if (period_type_param == PERIOD_YEARLY) {
481                                                         store   = new StoreCache(device_id, cur_date);
482                                                         dr      = store->get_max(PERIOD_MONTHLY);
483                                                 }
484                                                 else {
485                                                         store   = new StoreDay(device_id, cur_date);
486                                                         dr      = store->get_max(PERIOD_DAILY);
487                                                 }
488                                                 if (dr != NULL) {
489                                                         cur_data        = dr->get_first();
490                                                         if (cur_data != NULL) {
491                                                                 cnt++;
492                                                                 if (res_data == NULL) {
493                                                                         res_data        = cur_data;
494                                                                 }
495                                                                 else {
496                                                                         val_cnt = res_data->get_value_count();
497                                                                         int changed = 0;
498                                                                         for (ii = 0; ii < val_cnt; ii++) {
499                                                                                 if (cur_data->value_arr[ii] > res_data->value_arr[ii]) {
500                                                                                         res_data->value_arr[ii] = cur_data->value_arr[ii];
501                                                                                         changed = 1;
502                                                                                 }
503                                                                         }
504                                                                         if (changed == 1) {
505                                                                                 Date new_date;
506
507                                                                                 new_date        = cur_data->get_date();
508                                                                                 res_data->set_date(&new_date);
509                                                                         }
510                                                                         delete(cur_data);
511                                                                 }
512                                                         }
513                                                         delete(dr);
514                                                 }
515                                                 delete(store);
516                                                 if (period_type_param == PERIOD_YEARLY) {
517                                                         cur_date->next_month();
518                                                 }
519                                                 else {
520                                                         cur_date->next_day();
521                                                 }
522                                         }
523                                         if ((res_data != NULL) &&
524                                             (cnt > 0)) {
525                                                 ret_val = new DataRange(res_data);
526                                                 save(fname, ret_val, 4);
527                                                 delete(res_data);
528                                         }
529                                         delete(cur_date);
530                                         delete(max_date);
531                                 }
532                                 break;
533                         case PERIOD_DAILY:
534                         case PERIOD_HOURLY:
535                         case PERIOD_MINUTELY:
536                         case PERIOD_SECONDLY:
537                                 store   = new StoreDay(device_id, date);
538                                 ret_val = store->get_max(period_type_param);
539                                 save(fname, ret_val, 4);
540                                 delete(store);
541                                 break;
542                 }
543         }
544         return ret_val;
545 }
546
547 DataRange *StoreCache::get_min(EnumSummaryPeriod period_type_param) {
548         int             row_count;
549         DataRange       *ret_val;
550         Data            *dta;
551         string          fname;
552         Store           *store;
553
554         ret_val = NULL;
555         fname   = get_file_name(device_id,
556                                 date,
557                                 period_type_param,
558                                 MIN);
559         if (store_data == NULL) {
560                 if (access(fname.c_str(), R_OK) == 0) {
561                         load(fname);
562                 }
563         }
564         if (store_data != NULL) {
565                 row_count       = store_data->get_count();
566                 if (row_count > 0) {
567                         ret_val = new DataRange();
568                         dta     = store_data->get(0);
569                         ret_val->add(dta);
570                         delete(dta);
571                 }
572         }
573         if (ret_val == NULL) {
574                 switch(period_type_param) {
575                         case PERIOD_YEARLY:
576                         case PERIOD_MONTHLY: {
577                                         Data            *cur_data;
578                                         Data            *res_data;
579                                         Date            *cur_date;
580                                         Date            *max_date;
581                                         int             ii;
582                                         int             cnt;
583                                         int             val_cnt;
584                                         DataRange       *dr;
585
586                                         cur_date        = date->clone();
587                                         max_date        = date->clone();
588                                         if (period_type_param == PERIOD_YEARLY) {
589                                                 max_date->next_year();
590                                         }
591                                         else {
592                                                 max_date->next_month();
593                                         }
594                                         cur_data        = NULL;
595                                         res_data        = NULL;
596                                         cnt             = 0;
597                                         while(cur_date->before(max_date)) {
598                                                 if (period_type_param == PERIOD_YEARLY) {
599                                                         store   = new StoreCache(device_id, cur_date);
600                                                         dr      = store->get_min(PERIOD_MONTHLY);
601                                                 }
602                                                 else {
603                                                         store   = new StoreDay(device_id, cur_date);
604                                                         dr      = store->get_min(PERIOD_DAILY);
605                                                 }
606                                                 if (dr != NULL) {
607                                                         cur_data        = dr->get_first();
608                                                         if (cur_data != NULL) {
609                                                                 cnt++;
610                                                                 if (res_data == NULL) {
611                                                                         res_data        = cur_data;
612                                                                 }
613                                                                 else {
614                                                                         val_cnt = res_data->get_value_count();
615                                                                         int changed = 0;
616                                                                         for (ii = 0; ii < val_cnt; ii++) {
617                                                                                 if (cur_data->value_arr[ii] < res_data->value_arr[ii]) {
618                                                                                         res_data->value_arr[ii] = cur_data->value_arr[ii];
619                                                                                         changed = 1;
620                                                                                 }
621                                                                         }
622                                                                         if (changed == 1) {
623                                                                                 Date new_date;
624
625                                                                                 new_date        = cur_data->get_date();
626                                                                                 res_data->set_date(&new_date);
627                                                                         }
628                                                                         delete(cur_data);
629                                                                 }
630                                                         }
631                                                         delete(dr);
632                                                 }
633                                                 delete(store);
634                                                 if (period_type_param == PERIOD_YEARLY) {
635                                                         cur_date->next_month();
636                                                 }
637                                                 else {
638                                                         cur_date->next_day();
639                                                 }
640                                         }
641                                         if ((res_data != NULL) &&
642                                             (cnt > 0)) {
643                                                 ret_val = new DataRange(res_data);
644                                                 save(fname, ret_val, 4);
645                                                 delete(res_data);
646                                         }
647                                         delete(cur_date);
648                                         delete(max_date);
649                                 }
650                                 break;
651                         case PERIOD_DAILY:
652                         case PERIOD_HOURLY:
653                         case PERIOD_MINUTELY:
654                         case PERIOD_SECONDLY:
655                                 store   = new StoreDay(device_id, date);
656                                 ret_val = store->get_min(period_type_param);
657                                 save(fname, ret_val, 4);
658                                 delete(store);
659                                 break;
660                 }
661         }
662         return ret_val;
663 }
664
665 void StoreCache::save(std::string fname_param, plp::DataRange *datarange_param, int decimal_count_param) {
666         string          line;
667         Data            *data;
668         ofstream        *ostream;
669         int             ii;
670         int             cnt;
671
672         cnt     = datarange_param->get_count();
673         ostream =  NULL;
674         //log_info("[%s] cacheing %d data values.\n", device_id.c_str(), cnt);
675         ostream = W1Util::open_for_writing(fname_param.c_str());
676         if ((ostream != NULL) &&
677             (ostream->is_open() == true)) {
678                 // TODO: add mutex to protect string_list while it's read and emptied
679                 for(ii = 0; ii < cnt; ii++) {
680                         data    = datarange_param->get(ii);
681                         if (data != NULL) {
682                                 line    = data->to_string(decimal_count_param);
683                                 if (line.length() > 0) {
684                                         *ostream << line << endl;
685                                 }
686                                 delete(data);
687                         }
688                 }
689         }
690         else {
691                 log_error("[%s] File open for data save failed: %s\n", device_id.c_str(), fname_param.c_str());
692         }
693         if (ostream != NULL) {
694                 ostream->close();
695                 delete(ostream);
696         }
697 }
698
699 /**
700  * Find oldest data in certain year
701  */
702 Data *StoreCache::get_year_oldest_data() {
703         Data            *ret_val;
704         char            buffer[30];
705         DeviceData      *dta_finder;
706         string          str;
707
708         dta_finder      = new DeviceData(device_id);
709         snprintf(buffer, 30, "%d", date->year);
710         str.append(buffer);
711         ret_val         = dta_finder->find_oldest_data(str);
712         delete(dta_finder);
713         return ret_val;
714 }
715
716 /**
717  * Find newest data in certain year
718  */
719 Data *StoreCache::get_year_newest_data() {
720         Data            *ret_val;
721         char            buffer[30];
722         DeviceData      *dta_finder;
723         string          str;
724
725         dta_finder      = new DeviceData(device_id);
726         snprintf(buffer, 30, "%d", date->year);
727         str.append(buffer);
728         ret_val         = dta_finder->find_newest_data(str);
729         delete(dta_finder);
730         return ret_val;
731 }