MIDAS
Loading...
Searching...
No Matches
history.cxx
Go to the documentation of this file.
1/********************************************************************\
2
3 Name: HISTORY.C
4 Created by: Stefan Ritt
5
6 Contents: MIDAS history functions
7
8 $Id$
9
10\********************************************************************/
11
12#undef NDEBUG // midas required assert() to be always enabled
13
14#include <assert.h>
15#include <math.h> // sqrt()
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <assert.h>
20#include <map>
21
22#include "midas.h"
23#include "msystem.h"
24#include "mstrlcpy.h"
25#include "history.h"
26
35#if !defined(OS_VXWORKS)
36/********************************************************************\
37* *
38* History functions *
39* *
40\********************************************************************/
41
43#ifndef DOXYGEN_SHOULD_SKIP_THIS
44
45static std::vector<HISTORY*> _history;
46static std::string _hs_path_name;
47
49#endif /* DOXYGEN_SHOULD_SKIP_THIS */
50
51static bool xwrite(const std::string& fn, int fh, const void *buf, size_t count)
52{
53 ssize_t wr = write(fh, buf, count);
54
55 if (wr < 0) {
56 cm_msg(MERROR, "xwrite", "Error writing %d bytes to file \"%s\" errno %d (%s)", (int)count, fn.c_str(), errno, strerror(errno));
57 return false;
58 }
59
60 if ((size_t)wr != count) {
61 cm_msg(MERROR, "xwrite", "Error writing %d bytes to file \"%s\", short write %d bytes", (int)count, fn.c_str(), (int)wr);
62 return false;
63 }
64
65 return true;
66}
67
68// xread() return value:
69// 1 = ok
70// 0 = expected EOF, if eof_ok == true
71// -1 = error or short read or unexpected eof
72
73static int xread(const std::string& fn, int fh, void *buf, size_t count, bool eof_ok = false)
74{
75 ssize_t rd = read(fh, buf, count);
76
77 if (rd < 0) {
78 cm_msg(MERROR, "xread", "Error reading from file \"%s\" errno %d (%s)", fn.c_str(), errno, strerror(errno));
79 return -1;
80 }
81
82 if (rd == 0) {
83 if (eof_ok)
84 return 0;
85 cm_msg(MERROR, "xread", "Error: Unexpected end-of-file when reading file \"%s\"", fn.c_str());
86 return -1;
87 }
88
89 if ((size_t)rd != count) {
90 cm_msg(MERROR, "xread", "Error: Truncated read from file \"%s\", requested %d bytes, read %d bytes", fn.c_str(), (int)count, (int)rd);
91 return -1;
92 }
93
94 return 1;
95}
96
97static bool xseek(const std::string& fn, int fh, DWORD pos)
98{
99 off_t off = lseek(fh, pos, SEEK_SET);
100
101 if (off < 0) {
102 cm_msg(MERROR, "xseek", "Error in lseek(%llu, SEEK_SET) for file \"%s\", errno %d (%s)", (unsigned long long)pos, fn.c_str(), errno, strerror(errno));
103 return false;
104 }
105
106 return true;
107}
108
109static bool xseek_end(const std::string& fn, int fh)
110{
111 off_t off = lseek(fh, 0, SEEK_END);
112
113 if (off < 0) {
114 cm_msg(MERROR, "xseek_end", "Error in lseek(SEEK_END) to end-of-file for file \"%s\", errno %d (%s)", fn.c_str(), errno, strerror(errno));
115 return false;
116 }
117
118 return true;
119}
120
121static bool xseek_cur(const std::string& fn, int fh, int offset)
122{
123 off_t off = lseek(fh, offset, SEEK_CUR);
124
125 if (off < 0) {
126 cm_msg(MERROR, "xseek_cur", "Error in lseek(%d, SEEK_CUR) for file \"%s\", errno %d (%s)", offset, fn.c_str(), errno, strerror(errno));
127 return false;
128 }
129
130 return true;
131}
132
133static DWORD xcurpos(const std::string& fn, int fh)
134{
135 off_t off = lseek(fh, 0, SEEK_CUR);
136
137 if (off < 0) {
138 cm_msg(MERROR, "xcurpos", "Error in lseek(0, SEEK_CUR) for file \"%s\", errno %d (%s)", fn.c_str(), errno, strerror(errno));
139 return -1;
140 }
141
142 DWORD dw = off;
143
144 if (dw != off) {
145 cm_msg(MERROR, "xcurpos", "Error: lseek(0, SEEK_CUR) for file \"%s\" returned value %llu does not fir into a DWORD, maybe file is bigger than 2GiB or 4GiB", fn.c_str(), (unsigned long long)off);
146 return -1;
147 }
148
149 return dw;
150}
151
152static bool xtruncate(const std::string& fn, int fh, DWORD pos)
153{
154 off_t off = lseek(fh, pos, SEEK_SET);
155
156 if (off < 0) {
157 cm_msg(MERROR, "xtruncate", "Error in lseek(%llu) for file \"%s\", errno %d (%s)", (unsigned long long)pos, fn.c_str(), errno, strerror(errno));
158 return false;
159 }
160
161 int status = ftruncate(fh, pos);
162
163 if (status != 0) {
164 cm_msg(MERROR, "xtruncate", "Error setting file size of \"%s\" to %llu, errno %d (%s)", fn.c_str(), (unsigned long long)pos, errno, strerror(errno));
165 return false;
166 }
167
168 return true;
169}
170
171/********************************************************************/
178static INT hs_set_path(const char *path)
179{
180 assert(path);
181 assert(path[0] != 0);
182
183 _hs_path_name = path;
184
185 /* check for trailing directory seperator */
186 if (_hs_path_name.back() != DIR_SEPARATOR)
188
189 return HS_SUCCESS;
190}
191
193#ifndef DOXYGEN_SHOULD_SKIP_THIS
194
195/********************************************************************/
196
206static INT hs_open_file(time_t ltime, const char *suffix, INT mode, std::string *pfile_name, int *fh)
207{
208 struct tm tms;
209 time_t ttime;
210
211 /* generate new file name YYMMDD.xxx */
212 ss_tzset(); // required by localtime_r()
213 ttime = (time_t) ltime;
214 localtime_r(&ttime, &tms);
215
216 //sprintf(file_name, "%s%02d%02d%02d.%s", _hs_path_name, tms.tm_year % 100, tms.tm_mon + 1, tms.tm_mday, suffix);
217 std::string file_name;
219 char tmp[100];
220 sprintf(tmp, "%02d%02d%02d", tms.tm_year % 100, tms.tm_mon + 1, tms.tm_mday);
221 file_name += tmp;
222 file_name += ".";
223 file_name += suffix;
224
225 if (pfile_name)
226 *pfile_name = file_name;
227
228 /* open file, add O_BINARY flag for Windows NT */
229 *fh = open(file_name.c_str(), mode | O_BINARY, 0644);
230
231 //printf("hs_open_file: time %d, file \'%s\', fh %d\n", (int)ltime, file_name.c_str(), *fh);
232
233 return HS_SUCCESS;
234}
235
236/********************************************************************/
237static INT hs_gen_index(DWORD ltime)
238/********************************************************************\
239
240 Routine: hs_gen_index
241
242 Purpose: Regenerate index files ("idx" and "idf" files) for a given
243 history file ("hst"). Interal use only.
244
245 Input:
246 time_t ltime Date for which a history file should
247 be analyzed.
248
249 Output:
250 none
251
252 Function value:
253 HS_SUCCESS Successful completion
254 HS_FILE_ERROR Index files cannot be created
255
256\********************************************************************/
257{
258 char event_name[NAME_LENGTH];
259 int fh, fhd, fhi;
260 HIST_RECORD rec;
261 INDEX_RECORD irec;
262 DEF_RECORD def_rec;
263 int recovering = 0;
264 //time_t now = time(NULL);
265
266 cm_msg(MINFO, "hs_gen_index", "generating index files for time %d", (int) ltime);
267 printf("Recovering index files...\n");
268
269 if (ltime == 0)
270 ltime = (DWORD) time(NULL);
271
272 std::string fni;
273 std::string fnd;
274 std::string fn;
275
276 /* open new index file */
277 hs_open_file(ltime, "idx", O_RDWR | O_CREAT | O_TRUNC, &fni, &fhi);
278 hs_open_file(ltime, "idf", O_RDWR | O_CREAT | O_TRUNC, &fnd, &fhd);
279
280 if (fhd < 0 || fhi < 0) {
281 cm_msg(MERROR, "hs_gen_index", "cannot create index file");
282 return HS_FILE_ERROR;
283 }
284
285 /* open history file */
286 hs_open_file(ltime, "hst", O_RDONLY, &fn, &fh);
287 if (fh < 0)
288 return HS_FILE_ERROR;
289 xseek(fn, fh, 0);
290
291 /* loop over file records in .hst file */
292 do {
293 if (xread(fn, fh, (char *) &rec, sizeof(rec), true) <= 0) {
294 break;
295 }
296
297 /* check if record type is definition */
298 if (rec.record_type == RT_DEF) {
299 /* read name */
300 if (xread(fn, fh, event_name, sizeof(event_name)) < 0)
301 return HS_FILE_ERROR;
302
303 printf("Event definition %s, ID %d\n", event_name, rec.event_id);
304
305 /* write definition index record */
306 def_rec.event_id = rec.event_id;
307 memcpy(def_rec.event_name, event_name, sizeof(event_name));
308 DWORD pos = xcurpos(fn, fh);
309 if (pos == (DWORD)-1) return HS_FILE_ERROR;
310 def_rec.def_offset = pos - sizeof(event_name) - sizeof(rec);
311 xwrite(fnd, fhd, (char *) &def_rec, sizeof(def_rec));
312
313 //printf("data def at %d (age %d)\n", rec.time, now-rec.time);
314
315 /* skip tags */
316 xseek_cur(fn, fh, rec.data_size);
317 } else if (rec.record_type == RT_DATA && rec.data_size > 1 && rec.data_size < 1 * 1024 * 1024) {
318 /* write index record */
319 irec.event_id = rec.event_id;
320 irec.time = rec.time;
321 DWORD pos = xcurpos(fn, fh);
322 if (pos == (DWORD)-1) return HS_FILE_ERROR;
323 irec.offset = pos - sizeof(rec);
324 xwrite(fni, fhi, (char *) &irec, sizeof(irec));
325
326 //printf("data rec at %d (age %d)\n", rec.time, now-rec.time);
327
328 /* skip data */
329 xseek_cur(fn, fh, rec.data_size);
330 } else {
331 if (!recovering)
332 cm_msg(MERROR, "hs_gen_index", "broken history file for time %d, trying to recover", (int) ltime);
333
334 recovering = 1;
335 xseek_cur(fn, fh, 1 - (int)sizeof(rec));
336
337 continue;
338 }
339
340 } while (TRUE);
341
342 close(fh);
343 close(fhi);
344 close(fhd);
345
346 printf("...done.\n");
347
348 return HS_SUCCESS;
349}
350
351
352/********************************************************************/
353static INT hs_search_file(DWORD * ltime, INT direction)
354/********************************************************************\
355
356 Routine: hs_search_file
357
358 Purpose: Search an history file for a given date. If not found,
359 look for files after date (direction==1) or before date
360 (direction==-1) up to one year.
361
362 Input:
363 DWORD *ltime Date of history file
364 INT direction Search direction
365
366 Output:
367 DWORD *ltime Date of history file found
368
369 Function value:
370 HS_SUCCESS Successful completion
371 HS_FILE_ERROR No file found
372
373\********************************************************************/
374{
375 time_t lt;
376 int fh, fhd, fhi;
377 std::string fn;
378
379 ss_tzset(); // required by localtime_r()
380
381 if (*ltime == 0)
382 *ltime = ss_time();
383
384 lt = (time_t) * ltime;
385 do {
386 /* try to open history file for date "lt" */
387 hs_open_file(lt, "hst", O_RDONLY, &fn, &fh);
388
389 /* if not found, look for next day */
390 if (fh < 0)
391 lt += direction * 3600 * 24;
392
393 /* stop if more than a year before starting point or in the future */
394 } while (fh < 0 && (INT) * ltime - (INT) lt < 3600 * 24 * 365 && lt <= (time_t) ss_time());
395
396 if (fh < 0)
397 return HS_FILE_ERROR;
398
399 if (lt != (time_t) *ltime) {
400 /* if switched to new day, set start_time to 0:00 */
401 struct tm tms;
402 localtime_r(&lt, &tms);
403 tms.tm_hour = tms.tm_min = tms.tm_sec = 0;
404 *ltime = (DWORD) ss_mktime(&tms);
405 }
406
407 /* check if index files are there */
408 hs_open_file(*ltime, "idf", O_RDONLY, NULL, &fhd);
409 hs_open_file(*ltime, "idx", O_RDONLY, NULL, &fhi);
410
411 if (fh > 0)
412 close(fh);
413 if (fhd > 0)
414 close(fhd);
415 if (fhi > 0)
416 close(fhi);
417
418 /* generate them if not */
419 if (fhd < 0 || fhi < 0)
420 hs_gen_index(*ltime);
421
422 return HS_SUCCESS;
423}
424
425
426/********************************************************************/
427static INT hs_define_event(DWORD event_id, const char *name, const TAG * tag, DWORD size)
428/********************************************************************\
429
430 Routine: hs_define_event
431
432 Purpose: Define a new event for which a history should be recorded.
433 This routine must be called before any call to
434 hs_write_event. It also should be called if the definition
435 of the event has changed.
436
437 The event definition is written directly to the history
438 file. If the definition is identical to a previous
439 definition, it is not written to the file.
440
441
442 Input:
443 DWORD event_id ID for this event. Must be unique.
444 char name Name of this event
445 TAG tag Tag list containing names and types of
446 variables in this event.
447 DWORD size Size of tag array
448
449 Output:
450 <none>
451
452 Function value:
453 HS_SUCCESS Successful completion
454 HS_NO_MEMEORY Out of memory
455 HS_FILE_ERROR Cannot open history file
456
457\********************************************************************/
458{
459 {
460 HIST_RECORD rec, prev_rec;
461 DEF_RECORD def_rec;
462 time_t ltime;
463 char str[256], event_name[NAME_LENGTH], *buffer;
464 int fh, fhi, fhd;
465 std::string fn, fni, fnd;
466 INT n, status, semaphore;
467
468 //printf("hs_define_event: event_id %d, name [%s]\n", event_id, name);
469
470 /* request semaphore */
471 cm_get_experiment_semaphore(NULL, NULL, &semaphore, NULL);
472 status = ss_semaphore_wait_for(semaphore, 5 * 1000);
473 if (status != SS_SUCCESS)
474 return SUCCESS; /* someone else blocked the history system */
475
476 /* allocate new space for the new history descriptor */
477 /* check if history already open */
478 int index = -1;
479 for (unsigned i = 0; i < _history.size(); i++)
480 if (_history[i]->event_id == event_id) {
481 index = i;
482 break;
483 }
484
485 /* if not found, create new one */
486 if (index < 0) {
487 index = _history.size();
488 _history.push_back(new HISTORY);
489 }
490
491 /* assemble definition record header */
492 rec.record_type = RT_DEF;
493 rec.event_id = event_id;
494 rec.time = (DWORD) time(NULL);
495 rec.data_size = size;
496 mstrlcpy(event_name, name, NAME_LENGTH);
497
498 /* if history structure not set up, do so now */
499 if (!_history[index]->hist_fh) {
500 /* open history file */
501 hs_open_file(rec.time, "hst", O_CREAT | O_RDWR, &fn, &fh);
502 if (fh < 0) {
503 ss_semaphore_release(semaphore);
504 return HS_FILE_ERROR;
505 }
506
507 /* open index files */
508 hs_open_file(rec.time, "idf", O_CREAT | O_RDWR, &fnd, &fhd);
509 hs_open_file(rec.time, "idx", O_CREAT | O_RDWR, &fni, &fhi);
510 xseek_end(fn, fh);
511 xseek_end(fni, fhi);
512 xseek_end(fnd, fhd);
513
514 DWORD fh_pos = xcurpos(fn, fh);
515 DWORD fhd_pos = xcurpos(fnd, fhd);
516
517 if (fh_pos == (DWORD)-1) return HS_FILE_ERROR;
518 if (fhd_pos == (DWORD)-1) return HS_FILE_ERROR;
519
520 /* regenerate index if missing */
521 if (fh_pos > 0 && fhd_pos == 0) {
522 close(fh);
523 close(fhi);
524 close(fhd);
525 hs_gen_index(rec.time);
526 hs_open_file(rec.time, "hst", O_RDWR, &fn, &fh);
527 hs_open_file(rec.time, "idx", O_RDWR, &fni, &fhi);
528 hs_open_file(rec.time, "idf", O_RDWR, &fnd, &fhd);
529 xseek_end(fn, fh);
530 xseek_end(fni, fhi);
531 xseek_end(fnd, fhd);
532 }
533
534 ltime = (time_t) rec.time;
535 struct tm tmb;
536 localtime_r(&ltime, &tmb);
537 tmb.tm_hour = tmb.tm_min = tmb.tm_sec = 0;
538
539 DWORD pos = xcurpos(fn, fh);
540 if (pos == (DWORD)-1) return HS_FILE_ERROR;
541
542 /* setup history structure */
543 _history[index]->hist_fn = fn;
544 _history[index]->index_fn = fni;
545 _history[index]->def_fn = fnd;
546 _history[index]->hist_fh = fh;
547 _history[index]->index_fh = fhi;
548 _history[index]->def_fh = fhd;
549 _history[index]->def_offset = pos;
550 _history[index]->event_id = event_id;
551 _history[index]->event_name = event_name;
552 _history[index]->base_time = (DWORD) ss_mktime(&tmb);
553 _history[index]->n_tag = size / sizeof(TAG);
554 _history[index]->tag = (TAG *) M_MALLOC(size);
555 memcpy(_history[index]->tag, tag, size);
556
557 /* search previous definition */
558 fhd_pos = xcurpos(fnd, fhd);
559 if (fhd_pos == (DWORD)-1) return HS_FILE_ERROR;
560 n = fhd_pos / sizeof(def_rec);
561 def_rec.event_id = 0;
562 for (int i = n - 1; i >= 0; i--) {
563 if (!xseek(fnd, fhd, i * sizeof(def_rec))) return HS_FILE_ERROR;
564 if (xread(fnd, fhd, (char *) &def_rec, sizeof(def_rec)) < 0) return HS_FILE_ERROR;
565 if (def_rec.event_id == event_id)
566 break;
567 }
568 xseek_end(fnd, fhd);
569
570 /* if definition found, compare it with new one */
571 if (def_rec.event_id == event_id) {
572 buffer = (char *) M_MALLOC(size);
573 memset(buffer, 0, size);
574
575 xseek(fn, fh, def_rec.def_offset);
576 xread(fn, fh, (char *) &prev_rec, sizeof(prev_rec));
577 xread(fn, fh, str, NAME_LENGTH);
578 xread(fn, fh, buffer, size);
579 xseek_end(fn, fh);
580
581 if (prev_rec.data_size != size || strcmp(str, event_name) != 0 || memcmp(buffer, tag, size) != 0) {
582 /* write definition to history file */
583 xwrite(fn, fh, (char *) &rec, sizeof(rec));
584 xwrite(fn, fh, event_name, NAME_LENGTH);
585 xwrite(fn, fh, (char *) tag, size);
586
587 /* write index record */
588 def_rec.event_id = event_id;
589 memcpy(def_rec.event_name, event_name, sizeof(event_name));
590 def_rec.def_offset = _history[index]->def_offset;
591 xwrite(fnd, fhd, (char *) &def_rec, sizeof(def_rec));
592 } else
593 /* definition identical, just remember old offset */
594 _history[index]->def_offset = def_rec.def_offset;
595
596 M_FREE(buffer);
597 } else {
598 /* write definition to history file */
599 xwrite(fn, fh, (char *) &rec, sizeof(rec));
600 xwrite(fn, fh, event_name, NAME_LENGTH);
601 xwrite(fn, fh, (char *) tag, size);
602
603 /* write definition index record */
604 def_rec.event_id = event_id;
605 memcpy(def_rec.event_name, event_name, sizeof(event_name));
606 def_rec.def_offset = _history[index]->def_offset;
607 xwrite(fn, fhd, (char *) &def_rec, sizeof(def_rec));
608 }
609 } else {
610 fn = _history[index]->hist_fn;
611 fnd = _history[index]->def_fn;
612 fh = _history[index]->hist_fh;
613 fhd = _history[index]->def_fh;
614
615 /* compare definition with previous definition */
616 buffer = (char *) M_MALLOC(size);
617 memset(buffer, 0, size);
618
619 xseek(fn, fh, _history[index]->def_offset);
620 xread(fn, fh, (char *) &prev_rec, sizeof(prev_rec));
621 xread(fn, fh, str, NAME_LENGTH);
622 xread(fn, fh, buffer, size);
623
624 xseek_end(fn, fh);
625 xseek_end(fnd, fhd);
626
627 if (prev_rec.data_size != size || strcmp(str, event_name) != 0 || memcmp(buffer, tag, size) != 0) {
628 /* save new definition offset */
629 DWORD pos = xcurpos(fn, fh);
630 if (pos == (DWORD)-1) return HS_FILE_ERROR;
631 _history[index]->def_offset = pos;
632
633 /* write definition to history file */
634 xwrite(fn, fh, (char *) &rec, sizeof(rec));
635 xwrite(fn, fh, event_name, NAME_LENGTH);
636 xwrite(fn, fh, (char *) tag, size);
637
638 /* write index record */
639 def_rec.event_id = event_id;
640 memcpy(def_rec.event_name, event_name, sizeof(event_name));
641 def_rec.def_offset = _history[index]->def_offset;
642 xwrite(fnd, fhd, (char *) &def_rec, sizeof(def_rec));
643 }
644
645 M_FREE(buffer);
646 }
647
648 ss_semaphore_release(semaphore);
649 }
650
651 return HS_SUCCESS;
652}
653
654
655/********************************************************************/
656static INT hs_write_event(DWORD event_id, const void *data, DWORD size)
657/********************************************************************\
658
659 Routine: hs_write_event
660
661 Purpose: Write an event to a history file.
662
663 Input:
664 DWORD event_id Event ID
665 void *data Data buffer containing event
666 DWORD size Data buffer size in bytes
667
668 Output:
669 none
670 future hs_write_event
671
672 Function value:
673 HS_SUCCESS Successful completion
674 HS_NO_MEMEORY Out of memory
675 HS_FILE_ERROR Cannot write to history file
676 HS_UNDEFINED_EVENT Event was not defined via hs_define_event
677
678\********************************************************************/
679{
680 HIST_RECORD rec, drec;
681 DEF_RECORD def_rec;
682 INDEX_RECORD irec;
683 int fh, fhi, fhd;
684 DWORD last_pos_data, last_pos_index;
685 std::string fn, fni, fnd;
686 INT semaphore;
687 int status;
688 struct tm tmb, tmr;
689 time_t ltime;
690
691 /* request semaphore */
692 cm_get_experiment_semaphore(NULL, NULL, &semaphore, NULL);
693 status = ss_semaphore_wait_for(semaphore, 5 * 1000);
694 if (status != SS_SUCCESS) {
695 cm_msg(MERROR, "hs_write_event", "semaphore timeout");
696 return SUCCESS; /* someone else blocked the history system */
697 }
698
699 /* find index to history structure */
700 int index = -1;
701 for (unsigned i = 0; i < _history.size(); i++)
702 if (_history[i]->event_id == event_id) {
703 index = i;
704 break;
705 }
706 if (index < 0) {
707 ss_semaphore_release(semaphore);
708 return HS_UNDEFINED_EVENT;
709 }
710
711 /* assemble record header */
712 rec.record_type = RT_DATA;
713 rec.event_id = _history[index]->event_id;
714 rec.time = (DWORD) time(NULL);
715 rec.def_offset = _history[index]->def_offset;
716 rec.data_size = size;
717
718 irec.event_id = _history[index]->event_id;
719 irec.time = rec.time;
720
721 /* check if new day */
722 ltime = (time_t) rec.time;
723 localtime_r(&ltime, &tmr); // somebody must call tzset() before this.
724 ltime = (time_t) _history[index]->base_time;
725 localtime_r(&ltime, &tmb); // somebody must call tzset() before this.
726
727 if (tmr.tm_yday != tmb.tm_yday) {
728 /* close current history file */
729 close(_history[index]->hist_fh);
730 close(_history[index]->def_fh);
731 close(_history[index]->index_fh);
732
733 /* open new history file */
734 hs_open_file(rec.time, "hst", O_CREAT | O_RDWR, &fn, &fh);
735 if (fh < 0) {
736 ss_semaphore_release(semaphore);
737 return HS_FILE_ERROR;
738 }
739
740 /* open new index file */
741 hs_open_file(rec.time, "idx", O_CREAT | O_RDWR, &fni, &fhi);
742 if (fhi < 0) {
743 ss_semaphore_release(semaphore);
744 return HS_FILE_ERROR;
745 }
746
747 /* open new definition index file */
748 hs_open_file(rec.time, "idf", O_CREAT | O_RDWR, &fnd, &fhd);
749 if (fhd < 0) {
750 ss_semaphore_release(semaphore);
751 return HS_FILE_ERROR;
752 }
753
754 xseek_end(fn, fh);
755 xseek_end(fni, fhi);
756 xseek_end(fnd, fhd);
757
758 /* remember new file handles */
759 _history[index]->hist_fn = fn;
760 _history[index]->index_fn = fni;
761 _history[index]->def_fn = fnd;
762
763 _history[index]->hist_fh = fh;
764 _history[index]->index_fh = fhi;
765 _history[index]->def_fh = fhd;
766
767 _history[index]->def_offset = xcurpos(fn, fh);
768 rec.def_offset = _history[index]->def_offset;
769
770 tmr.tm_hour = tmr.tm_min = tmr.tm_sec = 0;
771 _history[index]->base_time = (DWORD) ss_mktime(&tmr);
772
773 /* write definition from _history structure */
774 drec.record_type = RT_DEF;
775 drec.event_id = _history[index]->event_id;
776 drec.time = rec.time;
777 drec.data_size = _history[index]->n_tag * sizeof(TAG);
778
779 xwrite(fn, fh, (char *) &drec, sizeof(drec));
780 xwrite(fn, fh, _history[index]->event_name.c_str(), NAME_LENGTH);
781 xwrite(fn, fh, (char *) _history[index]->tag, drec.data_size);
782
783 /* write definition index record */
784 def_rec.event_id = _history[index]->event_id;
785 memcpy(def_rec.event_name, _history[index]->event_name.c_str(), sizeof(def_rec.event_name));
786 def_rec.def_offset = _history[index]->def_offset;
787 xwrite(fnd, fhd, (char *) &def_rec, sizeof(def_rec));
788 }
789
790 /* go to end of file */
791 xseek_end(_history[index]->hist_fn, _history[index]->hist_fh);
792 last_pos_data = irec.offset = xcurpos(_history[index]->hist_fn, _history[index]->hist_fh);
793
794 /* write record header */
795 xwrite(_history[index]->hist_fn, _history[index]->hist_fh, (char *) &rec, sizeof(rec));
796
797 /* write data */
798 if (!xwrite(_history[index]->hist_fn, _history[index]->hist_fh, (char *) data, size)) {
799 /* disk maybe full? Do a roll-back! */
800 xtruncate(_history[index]->hist_fn, _history[index]->hist_fh, last_pos_data);
801 ss_semaphore_release(semaphore);
802 return HS_FILE_ERROR;
803 }
804
805 /* write index record */
806 xseek_end(_history[index]->index_fn, _history[index]->index_fh);
807 last_pos_index = xcurpos(_history[index]->index_fn, _history[index]->index_fh);
808 int size_of_irec = sizeof(irec);
809 if (!xwrite(_history[index]->index_fn, _history[index]->index_fh, (char *) &irec, size_of_irec)) {
810 /* disk maybe full? Do a roll-back! */
811 xtruncate(_history[index]->hist_fn, _history[index]->hist_fh, last_pos_data);
812 xtruncate(_history[index]->index_fn, _history[index]->index_fh, last_pos_index);
813 ss_semaphore_release(semaphore);
814 return HS_FILE_ERROR;
815 }
816
817 ss_semaphore_release(semaphore);
818 return HS_SUCCESS;
819}
820
821
822/********************************************************************/
823static INT hs_enum_events(DWORD ltime, char *event_name, DWORD * name_size, INT event_id[], DWORD * id_size)
824/********************************************************************\
825
826 Routine: hs_enum_events
827
828 Purpose: Enumerate events for a given date
829
830 Input:
831 DWORD ltime Date at which events should be enumerated
832
833 Output:
834 char *event_name Array containing event names
835 DWORD *name_size Size of name array
836 char *event_id Array containing event IDs
837 DWORD *id_size Size of ID array
838
839 Function value:
840 HS_SUCCESS Successful completion
841 HS_NO_MEMEORY Out of memory
842 HS_FILE_ERROR Cannot open history file
843
844\********************************************************************/
845{
846 int fh, fhd;
847 std::string fn, fnd;
848 INT status, i, n;
849 DEF_RECORD def_rec;
850
851 /* search latest history file */
852 status = hs_search_file(&ltime, -1);
853 if (status != HS_SUCCESS) {
854 cm_msg(MERROR, "hs_enum_events", "cannot find recent history file");
855 return HS_FILE_ERROR;
856 }
857
858 /* open history and definition files */
859 hs_open_file(ltime, "hst", O_RDONLY, &fn, &fh);
860 hs_open_file(ltime, "idf", O_RDONLY, &fnd, &fhd);
861 if (fh < 0 || fhd < 0) {
862 cm_msg(MERROR, "hs_enum_events", "cannot open index files");
863 return HS_FILE_ERROR;
864 }
865 xseek(fnd, fhd, 0);
866
867 /* loop over definition index file */
868 n = 0;
869 do {
870 /* read event definition */
871 if (xread(fnd, fhd, (char *) &def_rec, sizeof(def_rec), true) <= 0)
872 break;
873
874 /* look for existing entry for this event id */
875 for (i = 0; i < n; i++)
876 if (event_id[i] == (INT) def_rec.event_id) {
877 strcpy(event_name + i * NAME_LENGTH, def_rec.event_name);
878 break;
879 }
880
881 /* new entry found */
882 if (i == n) {
883 if (((i * NAME_LENGTH) > ((INT) * name_size)) || ((i * sizeof(INT)) > (*id_size))) {
884 cm_msg(MERROR, "hs_enum_events", "index buffer too small");
885 close(fh);
886 close(fhd);
887 return HS_NO_MEMORY;
888 }
889
890 /* copy definition record */
891 strcpy(event_name + i * NAME_LENGTH, def_rec.event_name);
892 event_id[i] = def_rec.event_id;
893 n++;
894 }
895 } while (TRUE);
896
897 close(fh);
898 close(fhd);
899 *name_size = n * NAME_LENGTH;
900 *id_size = n * sizeof(INT);
901
902 return HS_SUCCESS;
903}
904
905
906/********************************************************************/
908/********************************************************************\
909
910 Routine: hs_count_events
911
912 Purpose: Count number of different events for a given date
913
914 Input:
915 DWORD ltime Date at which events should be counted
916
917 Output:
918 DWORD *count Number of different events found
919
920 Function value:
921 HS_SUCCESS Successful completion
922 HS_FILE_ERROR Cannot open history file
923
924\********************************************************************/
925{
926 int fh, fhd;
927 std::string fn, fnd;
928 INT status, i, n;
929 DWORD *id;
930 DEF_RECORD def_rec;
931
932 /* search latest history file */
933 status = hs_search_file(&ltime, -1);
934 if (status != HS_SUCCESS) {
935 cm_msg(MERROR, "hs_count_events", "cannot find recent history file");
936 return HS_FILE_ERROR;
937 }
938
939 /* open history and definition files */
940 hs_open_file(ltime, "hst", O_RDONLY, &fn, &fh);
941 hs_open_file(ltime, "idf", O_RDONLY, &fnd, &fhd);
942 if (fh < 0 || fhd < 0) {
943 cm_msg(MERROR, "hs_count_events", "cannot open index files");
944 return HS_FILE_ERROR;
945 }
946
947 /* allocate event id array */
948 xseek_end(fnd, fhd);
949 DWORD pos_fhd = xcurpos(fnd, fhd);
950 if (pos_fhd == (DWORD)-1) return HS_FILE_ERROR;
951 id = (DWORD *) M_MALLOC(pos_fhd/sizeof(def_rec) * sizeof(DWORD));
952 xseek(fnd, fhd, 0);
953
954 /* loop over index file */
955 n = 0;
956 do {
957 /* read definition index record */
958 if (xread(fnd, fhd, (char *) &def_rec, sizeof(def_rec), true) <= 0)
959 break;
960
961 /* look for existing entries */
962 for (i = 0; i < n; i++)
963 if (id[i] == def_rec.event_id)
964 break;
965
966 /* new entry found */
967 if (i == n) {
968 id[i] = def_rec.event_id;
969 n++;
970 }
971 } while (TRUE);
972
973
974 M_FREE(id);
975 close(fh);
976 close(fhd);
977 *count = n;
978
979 return HS_SUCCESS;
980}
981
982
983/********************************************************************/
984static INT hs_get_event_id(DWORD ltime, const char *name, DWORD * id)
985/********************************************************************\
986
987 Routine: hs_get_event_id
988
989 Purpose: Return event ID for a given name. If event cannot be found
990 in current definition file, go back in time until found
991
992 Input:
993 DWORD ltime Date at which event ID should be looked for
994
995 Output:
996 DWORD *id Event ID
997
998 Function value:
999 HS_SUCCESS Successful completion
1000 HS_FILE_ERROR Cannot open history file
1001 HS_UNDEFINED_EVENT Event "name" not found
1002
1003\********************************************************************/
1004{
1005 int fh, fhd;
1006 std::string fn, fnd;
1007 INT status;
1008 DWORD lt;
1009 DEF_RECORD def_rec;
1010
1011 /* search latest history file */
1012 if (ltime == 0)
1013 ltime = (DWORD) time(NULL);
1014
1015 lt = ltime;
1016
1017 do {
1018 status = hs_search_file(&lt, -1);
1019 if (status != HS_SUCCESS) {
1020 cm_msg(MERROR, "hs_count_events", "cannot find recent history file");
1021 return HS_FILE_ERROR;
1022 }
1023
1024 /* open history and definition files */
1025 hs_open_file(lt, "hst", O_RDONLY, &fn, &fh);
1026 hs_open_file(lt, "idf", O_RDONLY, &fnd, &fhd);
1027 if (fh < 0 || fhd < 0) {
1028 cm_msg(MERROR, "hs_count_events", "cannot open index files");
1029 return HS_FILE_ERROR;
1030 }
1031
1032 /* loop over index file */
1033 *id = 0;
1034 do {
1035 /* read definition index record */
1036 if (xread(fnd, fhd, (char *) &def_rec, sizeof(def_rec), true) <= 0)
1037 break;
1038
1039 if (strcmp(name, def_rec.event_name) == 0) {
1040 *id = def_rec.event_id;
1041 close(fh);
1042 close(fhd);
1043 return HS_SUCCESS;
1044 }
1045 } while (TRUE);
1046
1047 close(fh);
1048 close(fhd);
1049
1050 /* not found -> go back one day */
1051 lt -= 3600 * 24;
1052
1053 } while (lt > ltime - 3600 * 24 * 365 * 10); /* maximum 10 years */
1054
1055 return HS_UNDEFINED_EVENT;
1056}
1057
1058
1059/********************************************************************/
1061/********************************************************************\
1062
1063 Routine: hs_count_vars
1064
1065 Purpose: Count number of variables for a given date and event id
1066
1067 Input:
1068 DWORD ltime Date at which tags should be counted
1069
1070 Output:
1071 DWORD *count Number of tags
1072
1073 Function value:
1074 HS_SUCCESS Successful completion
1075 HS_FILE_ERROR Cannot open history file
1076
1077\********************************************************************/
1078{
1079 int fh, fhd;
1080 std::string fn, fnd;
1081 INT i, n, status;
1082 DEF_RECORD def_rec;
1083 HIST_RECORD rec;
1084
1085 /* search latest history file */
1086 status = hs_search_file(&ltime, -1);
1087 if (status != HS_SUCCESS) {
1088 cm_msg(MERROR, "hs_count_tags", "cannot find recent history file");
1089 return HS_FILE_ERROR;
1090 }
1091
1092 /* open history and definition files */
1093 hs_open_file(ltime, "hst", O_RDONLY, &fn, &fh);
1094 hs_open_file(ltime, "idf", O_RDONLY, &fnd, &fhd);
1095 if (fh < 0 || fhd < 0) {
1096 cm_msg(MERROR, "hs_count_tags", "cannot open index files");
1097 return HS_FILE_ERROR;
1098 }
1099
1100 /* search last definition */
1101 xseek_end(fnd, fhd);
1102 n = xcurpos(fnd, fhd) / sizeof(def_rec);
1103 def_rec.event_id = 0;
1104 for (i = n - 1; i >= 0; i--) {
1105 if (!xseek(fnd, fhd, i * sizeof(def_rec))) return HS_FILE_ERROR;
1106 if (xread(fnd, fhd, (char *) &def_rec, sizeof(def_rec)) < 0) return HS_FILE_ERROR;
1107 if (def_rec.event_id == event_id)
1108 break;
1109 }
1110 if (def_rec.event_id != event_id) {
1111 cm_msg(MERROR, "hs_count_tags", "event %d not found in index file", event_id);
1112 return HS_FILE_ERROR;
1113 }
1114
1115 /* read definition */
1116 xseek(fn, fh, def_rec.def_offset);
1117 xread(fn, fh, (char *) &rec, sizeof(rec));
1118 *count = rec.data_size / sizeof(TAG);
1119
1120 close(fh);
1121 close(fhd);
1122
1123 return HS_SUCCESS;
1124}
1125
1126
1127/********************************************************************/
1128static INT hs_enum_vars(DWORD ltime, DWORD event_id, char *var_name, DWORD * size, DWORD * var_n, DWORD * n_size)
1129/********************************************************************\
1130
1131 Routine: hs_enum_vars
1132
1133 Purpose: Enumerate variable tags for a given date and event id
1134
1135 Input:
1136 DWORD ltime Date at which tags should be enumerated
1137 DWORD event_id Event ID
1138
1139 Output:
1140 char *var_name Array containing variable names
1141 DWORD *size Size of name array
1142 DWORD *var_n Array size of variable
1143 DWORD *n_size Size of n array
1144
1145 Function value:
1146 HS_SUCCESS Successful completion
1147 HS_NO_MEMEORY Out of memory
1148 HS_FILE_ERROR Cannot open history file
1149
1150\********************************************************************/
1151{
1152 char str[256];
1153 int fh, fhd;
1154 std::string fn, fnd;
1155 INT i, n, status;
1156 DEF_RECORD def_rec;
1157 HIST_RECORD rec;
1158 TAG *tag;
1159
1160 /* search latest history file */
1161 status = hs_search_file(&ltime, -1);
1162 if (status != HS_SUCCESS) {
1163 cm_msg(MERROR, "hs_enum_vars", "cannot find recent history file");
1164 return HS_FILE_ERROR;
1165 }
1166
1167 /* open history and definition files */
1168 hs_open_file(ltime, "hst", O_RDONLY, &fn, &fh);
1169 hs_open_file(ltime, "idf", O_RDONLY, &fnd, &fhd);
1170 if (fh < 0 || fhd < 0) {
1171 cm_msg(MERROR, "hs_enum_vars", "cannot open index files");
1172 return HS_FILE_ERROR;
1173 }
1174
1175 /* search last definition */
1176 xseek_end(fnd, fhd);
1177 n = xcurpos(fnd, fhd) / sizeof(def_rec);
1178 def_rec.event_id = 0;
1179 for (i = n - 1; i >= 0; i--) {
1180 if (!xseek(fnd, fhd, i * sizeof(def_rec))) return HS_FILE_ERROR;
1181 if (xread(fnd, fhd, (char *) &def_rec, sizeof(def_rec)) < 0) return HS_FILE_ERROR;
1182 if (def_rec.event_id == event_id)
1183 break;
1184 }
1185 if (def_rec.event_id != event_id) {
1186 cm_msg(MERROR, "hs_enum_vars", "event %d not found in index file", event_id);
1187 return HS_FILE_ERROR;
1188 }
1189
1190 /* read definition header */
1191 xseek(fn, fh, def_rec.def_offset);
1192 xread(fn, fh, (char *) &rec, sizeof(rec));
1193 xread(fn, fh, str, NAME_LENGTH);
1194
1195 /* read event definition */
1196 n = rec.data_size / sizeof(TAG);
1197 tag = (TAG *) M_MALLOC(rec.data_size);
1198 xread(fn, fh, (char *) tag, rec.data_size);
1199
1200 if (n * NAME_LENGTH > (INT) * size || n * sizeof(DWORD) > *n_size) {
1201
1202 /* store partial definition */
1203 for (i = 0; i < (INT) * size / NAME_LENGTH; i++) {
1204 strcpy(var_name + i * NAME_LENGTH, tag[i].name);
1205 var_n[i] = tag[i].n_data;
1206 }
1207
1208 cm_msg(MERROR, "hs_enum_vars", "tag buffer too small");
1209 M_FREE(tag);
1210 close(fh);
1211 close(fhd);
1212 return HS_NO_MEMORY;
1213 }
1214
1215 /* store full definition */
1216 for (i = 0; i < n; i++) {
1217 strcpy(var_name + i * NAME_LENGTH, tag[i].name);
1218 var_n[i] = tag[i].n_data;
1219 }
1220 *size = n * NAME_LENGTH;
1221 *n_size = n * sizeof(DWORD);
1222
1223 M_FREE(tag);
1224 close(fh);
1225 close(fhd);
1226
1227 return HS_SUCCESS;
1228}
1229
1230
1231/********************************************************************/
1232static INT hs_get_var(DWORD ltime, DWORD event_id, const char *var_name, DWORD * type, INT * n_data)
1233/********************************************************************\
1234
1235 Routine: hs_get_var
1236
1237 Purpose: Get definition for certain variable
1238
1239 Input:
1240 DWORD ltime Date at which variable definition should
1241 be returned
1242 DWORD event_id Event ID
1243 char *var_name Name of variable
1244
1245 Output:
1246 INT *type Type of variable
1247 INT *n_data Number of items in variable
1248
1249 Function value:
1250 HS_SUCCESS Successful completion
1251 HS_NO_MEMEORY Out of memory
1252 HS_FILE_ERROR Cannot open history file
1253
1254\********************************************************************/
1255{
1256 char str[256];
1257 int fh, fhd;
1258 std::string fn, fnd;
1259 INT i, n, status;
1260 DEF_RECORD def_rec;
1261 HIST_RECORD rec;
1262 TAG *tag;
1263
1264 /* search latest history file */
1265 status = hs_search_file(&ltime, -1);
1266 if (status != HS_SUCCESS) {
1267 cm_msg(MERROR, "hs_get_var", "cannot find recent history file");
1268 return HS_FILE_ERROR;
1269 }
1270
1271 /* open history and definition files */
1272 hs_open_file(ltime, "hst", O_RDONLY, &fn, &fh);
1273 hs_open_file(ltime, "idf", O_RDONLY, &fnd, &fhd);
1274 if (fh < 0 || fhd < 0) {
1275 cm_msg(MERROR, "hs_get_var", "cannot open index files");
1276 return HS_FILE_ERROR;
1277 }
1278
1279 /* search last definition */
1280 xseek_end(fnd, fhd);
1281 n = xcurpos(fnd, fhd) / sizeof(def_rec);
1282 def_rec.event_id = 0;
1283 for (i = n - 1; i >= 0; i--) {
1284 if (!xseek(fnd, fhd, i * sizeof(def_rec))) return HS_FILE_ERROR;
1285 if (xread(fnd, fhd, (char *) &def_rec, sizeof(def_rec)) < 0) return HS_FILE_ERROR;
1286 if (def_rec.event_id == event_id)
1287 break;
1288 }
1289 if (def_rec.event_id != event_id) {
1290 cm_msg(MERROR, "hs_get_var", "event %d not found in index file", event_id);
1291 return HS_FILE_ERROR;
1292 }
1293
1294 /* read definition header */
1295 xseek(fn, fh, def_rec.def_offset);
1296 xread(fn, fh, (char *) &rec, sizeof(rec));
1297 xread(fn, fh, str, NAME_LENGTH);
1298
1299 /* read event definition */
1300 n = rec.data_size / sizeof(TAG);
1301 tag = (TAG *) M_MALLOC(rec.data_size);
1302 xread(fn, fh, (char *) tag, rec.data_size);
1303
1304 /* search variable */
1305 for (i = 0; i < n; i++)
1306 if (strcmp(tag[i].name, var_name) == 0)
1307 break;
1308
1309 close(fh);
1310 close(fhd);
1311
1312 if (i < n) {
1313 *type = tag[i].type;
1314 *n_data = tag[i].n_data;
1315 } else {
1316 *type = *n_data = 0;
1317 cm_msg(MERROR, "hs_get_var", "variable %s not found", var_name);
1318 M_FREE(tag);
1319 return HS_UNDEFINED_VAR;
1320 }
1321
1322 M_FREE(tag);
1323 return HS_SUCCESS;
1324}
1325
1326
1327/********************************************************************/
1328static INT hs_get_tags(DWORD ltime, DWORD event_id, char event_name[NAME_LENGTH], int* n_tags, TAG** tags)
1329/********************************************************************\
1330
1331 Routine: hs_get_tags
1332
1333 Purpose: Get tags for event id
1334
1335 Input:
1336 DWORD ltime Date at which variable definition should
1337 be returned
1338 DWORD event_id Event ID
1339
1340 Output:
1341 char event_name[NAME_LENGTH] Event name from history file
1342 INT *n_tags Number of tags
1343 TAG **tags Pointer to array of tags (should be free()ed by the caller)
1344
1345 Function value:
1346 HS_SUCCESS Successful completion
1347 HS_NO_MEMEORY Out of memory
1348 HS_FILE_ERROR Cannot open history file
1349
1350\********************************************************************/
1351{
1352 int fh, fhd;
1353 std::string fn, fnd;
1354 INT i, n, status;
1355 DEF_RECORD def_rec;
1356 HIST_RECORD rec;
1357
1358 *n_tags = 0;
1359 *tags = NULL;
1360
1361 if (rpc_is_remote())
1362 assert(!"RPC not implemented");
1363
1364 /* search latest history file */
1365 status = hs_search_file(&ltime, -1);
1366 if (status != HS_SUCCESS) {
1367 cm_msg(MERROR, "hs_get_tags", "cannot find recent history file, hs_search_file() status %d", status);
1368 return HS_FILE_ERROR;
1369 }
1370
1371 /* open history and definition files */
1372 hs_open_file(ltime, "hst", O_RDONLY, &fn, &fh);
1373 hs_open_file(ltime, "idf", O_RDONLY, &fnd, &fhd);
1374 if (fh < 0 || fhd < 0) {
1375 cm_msg(MERROR, "hs_get_tags", "cannot open index files for time %d", ltime);
1376 if (fh>0)
1377 close(fh);
1378 if (fhd>0)
1379 close(fhd);
1380 return HS_FILE_ERROR;
1381 }
1382
1383 /* search last definition */
1384 xseek_end(fnd, fhd);
1385 n = xcurpos(fnd, fhd) / sizeof(def_rec);
1386 def_rec.event_id = 0;
1387 for (i = n - 1; i >= 0; i--) {
1388 if (!xseek(fnd, fhd, i * sizeof(def_rec))) return HS_FILE_ERROR;
1389 if (xread(fnd, fhd, (char *) &def_rec, sizeof(def_rec)) < 0) return HS_FILE_ERROR;
1390 //printf("reading index file found event_id %d, looking for %d\n", def_rec.event_id, event_id);
1391 if (def_rec.event_id == event_id)
1392 break;
1393 }
1394
1395 if (def_rec.event_id != event_id) {
1396 //cm_msg(MERROR, "hs_get_tags", "event %d not found in index file", event_id);
1397 close(fh);
1398 close(fhd);
1399 return HS_UNDEFINED_EVENT;
1400 }
1401
1402 /* read definition header */
1403 if (!xseek(fn, fh, def_rec.def_offset)) return HS_FILE_ERROR;
1404 if (xread(fn, fh, (char *) &rec, sizeof(rec)) < 0) return HS_FILE_ERROR;
1405 if (xread(fn, fh, event_name, NAME_LENGTH) < 0) return HS_FILE_ERROR;
1406
1407 /* read event definition */
1408 *n_tags = rec.data_size / sizeof(TAG);
1409
1410 *tags = (TAG*) malloc(rec.data_size);
1411
1412 if (xread(fn, fh, (char *) (*tags), rec.data_size) < 0) return HS_FILE_ERROR;
1413
1414 close(fh);
1415 close(fhd);
1416
1417 return HS_SUCCESS;
1418}
1419
1420double hs_to_double(int tid, const void* ybuffer)
1421{
1422 int j = 0;
1423 /* convert data to float */
1424 switch (tid) {
1425 default:
1426 return 0;
1427 case TID_BYTE:
1428 return *(((BYTE *) ybuffer) + j);
1429 case TID_SBYTE:
1430 return *(((char *) ybuffer) + j);
1431 case TID_CHAR:
1432 return *(((char *) ybuffer) + j);
1433 case TID_WORD:
1434 return *(((WORD *) ybuffer) + j);
1435 case TID_SHORT:
1436 return *(((short *) ybuffer) + j);
1437 case TID_DWORD:
1438 return *(((DWORD *) ybuffer) + j);
1439 case TID_INT:
1440 return *(((INT *) ybuffer) + j);
1441 case TID_BOOL:
1442 return *(((BOOL *) ybuffer) + j);
1443 case TID_FLOAT:
1444 return *(((float *) ybuffer) + j);
1445 case TID_DOUBLE:
1446 return *(((double *) ybuffer) + j);
1447 }
1448 /* NOT REACHED */
1449}
1450
1451static INT hs_read(DWORD event_id, DWORD start_time, DWORD end_time, DWORD interval, const char *tag_name, DWORD var_index, DWORD * time_buffer, DWORD * tbsize, void *data_buffer, DWORD * dbsize, DWORD * data_type, DWORD * data_n, MidasHistoryBufferInterface* buffer)
1452/********************************************************************\
1453
1454 Routine: hs_read
1455
1456 Purpose: Read history for a variable at a certain time interval
1457
1458 Input:
1459 DWORD event_id Event ID
1460 DWORD start_time Starting Date/Time
1461 DWORD end_time End Date/Time
1462 DWORD interval Minimum time in seconds between reported
1463 events. Can be used to skip events
1464 char *tag_name Variable name inside event
1465 DWORD var_index Index if variable is array
1466
1467 Output:
1468 DWORD *time_buffer Buffer containing times for each value
1469 DWORD *tbsize Size of time buffer
1470 void *data_buffer Buffer containing variable values
1471 DWORD *dbsize Data buffer size
1472 DWORD *type Type of variable (one of TID_xxx)
1473 DWORD *n Number of time/value pairs found
1474 in specified interval and placed into
1475 time_buffer and data_buffer
1476
1477
1478 Function value:
1479 HS_SUCCESS Successful completion
1480 HS_NO_MEMEORY Out of memory
1481 HS_FILE_ERROR Cannot open history file
1482 HS_WRONG_INDEX var_index exceeds array size of variable
1483 HS_UNDEFINED_VAR Variable "tag_name" not found in event
1484 HS_TRUNCATED Buffer too small, data has been truncated
1485
1486\********************************************************************/
1487{
1488 DWORD prev_time, last_irec_time;
1489 int fh, fhd, fhi, cp = 0;
1490 std::string fn, fnd, fni;
1491 int delta;
1492 int status;
1493 int cache_size;
1494 INDEX_RECORD irec, *pirec;
1495 HIST_RECORD rec, drec;
1496 INT old_def_offset;
1497 TAG *tag;
1498 char str[NAME_LENGTH];
1499 char *cache = NULL;
1500 time_t ltime;
1501
1502 int tag_index = -1;
1503 int var_type = -1;
1504 unsigned var_size = 0;
1505 unsigned var_offset = 0;
1506
1507 int ieof = 0;
1508
1509 //printf("hs_read event %d, time %d:%d, tagname: \'%s\', varindex: %d\n", event_id, start_time, end_time, tag_name, var_index);
1510
1511 ss_tzset(); // required by localtime_r()
1512
1513 /* if not time given, use present to one hour in past */
1514 if (start_time == 0)
1515 start_time = (DWORD) time(NULL) - 3600;
1516 if (end_time == 0)
1517 end_time = (DWORD) time(NULL);
1518
1519 if (data_n)
1520 *data_n = 0;
1521 prev_time = 0;
1522 last_irec_time = start_time;
1523
1524 /* search history file for start_time */
1525 status = hs_search_file(&start_time, 1);
1526 if (status != HS_SUCCESS) {
1527 //cm_msg(MERROR, "hs_read", "cannot find recent history file");
1528 if (data_n)
1529 *data_n = 0;
1530 if (tbsize)
1531 *tbsize = 0;
1532 if (dbsize)
1533 *dbsize = 0;
1534 return HS_FILE_ERROR;
1535 }
1536
1537 /* open history and definition files */
1538 hs_open_file(start_time, "hst", O_RDONLY, &fn, &fh);
1539 hs_open_file(start_time, "idf", O_RDONLY, &fnd, &fhd);
1540 hs_open_file(start_time, "idx", O_RDONLY, &fni, &fhi);
1541 if (fh < 0 || fhd < 0 || fhi < 0) {
1542 cm_msg(MERROR, "hs_read", "cannot open index files");
1543 if (tbsize)
1544 *tbsize = 0;
1545 if (dbsize)
1546 *dbsize = 0;
1547 if (data_n)
1548 *data_n = 0;
1549 if (fh > 0)
1550 close(fh);
1551 if (fhd > 0)
1552 close(fhd);
1553 if (fhi > 0)
1554 close(fhi);
1555 return HS_FILE_ERROR;
1556 }
1557
1558 /* try to read index file into cache */
1559 xseek_end(fni, fhi);
1560 cache_size = xcurpos(fni, fhi);
1561
1562 if (cache_size == 0) {
1563 goto nextday;
1564 }
1565
1566 if (cache_size > 0) {
1567 cache = (char *) M_MALLOC(cache_size);
1568 if (cache) {
1569 xseek(fni, fhi, 0);
1570 if (xread(fni, fhi, cache, cache_size) < 0) {
1571 M_FREE(cache);
1572 if (fh > 0)
1573 close(fh);
1574 if (fhd > 0)
1575 close(fhd);
1576 if (fhi > 0)
1577 close(fhi);
1578 return HS_FILE_ERROR;
1579 }
1580 }
1581
1582 /* search record closest to start time */
1583 if (cache == NULL) {
1584 xseek_end(fni, fhi);
1585 delta = (xcurpos(fni, fhi) / sizeof(irec)) / 2;
1586 xseek(fni, fhi, delta * sizeof(irec));
1587 do {
1588 delta = (int) (abs(delta) / 2.0 + 0.5);
1589 if (xread(fni, fhi, (char *) &irec, sizeof(irec)) < 0)
1590 return HS_FILE_ERROR;
1591 if (irec.time > start_time)
1592 delta = -delta;
1593
1594 xseek_cur(fni, fhi, (delta - 1) * sizeof(irec));
1595 } while (abs(delta) > 1 && irec.time != start_time);
1596 if (xread(fni, fhi, (char *) &irec, sizeof(irec)) < 0)
1597 return HS_FILE_ERROR;
1598 if (irec.time > start_time)
1599 delta = -abs(delta);
1600
1601 int i = xcurpos(fni, fhi) + (delta - 1) * sizeof(irec);
1602 if (i <= 0)
1603 xseek(fni, fhi, 0);
1604 else
1605 xseek_cur(fni, fhi, (delta - 1) * sizeof(irec));
1606 if (xread(fni, fhi, (char *) &irec, sizeof(irec)) < 0)
1607 return HS_FILE_ERROR;
1608 } else {
1609 delta = (cache_size / sizeof(irec)) / 2;
1610 cp = delta * sizeof(irec);
1611 do {
1612 delta = (int) (abs(delta) / 2.0 + 0.5);
1613 pirec = (INDEX_RECORD *) (cache + cp);
1614
1615 //printf("pirec %p, cache %p, cp %d\n", pirec, cache, cp);
1616
1617 if (pirec->time > start_time)
1618 delta = -delta;
1619
1620 cp = cp + delta * sizeof(irec);
1621
1622 if (cp < 0)
1623 cp = 0;
1624 if (cp >= cache_size)
1625 cp = cache_size - sizeof(irec);
1626 } while (abs(delta) > 1 && pirec->time != start_time);
1627 pirec = (INDEX_RECORD *) (cache + cp);
1628 if (pirec->time > start_time)
1629 delta = -abs(delta);
1630
1631 if (cp <= delta * (int) sizeof(irec))
1632 cp = 0;
1633 else
1634 cp = cp + delta * sizeof(irec);
1635
1636 if (cp >= cache_size)
1637 cp = cache_size - sizeof(irec);
1638 if (cp < 0)
1639 cp = 0;
1640
1641 memcpy(&irec, (INDEX_RECORD *) (cache + cp), sizeof(irec));
1642 cp += sizeof(irec);
1643 }
1644 } else { /* file size > 0 */
1645
1646 cache = NULL;
1647 irec.time = start_time;
1648 }
1649
1650 /* read records, skip wrong IDs */
1651 old_def_offset = -1;
1652 last_irec_time = start_time - 24 * 60 * 60;
1653 do {
1654 //printf("time %d -> %d\n", last_irec_time, irec.time);
1655
1656 if (irec.time < last_irec_time) {
1657 cm_msg(MERROR, "hs_read", "corrupted history data: time does not increase: %d -> %d", last_irec_time, irec.time);
1658 //*tbsize = *dbsize = *n = 0;
1659 if (fh > 0)
1660 close(fh);
1661 if (fhd > 0)
1662 close(fhd);
1663 if (fhi > 0)
1664 close(fhi);
1665 hs_gen_index(last_irec_time);
1666 return HS_SUCCESS;
1667 }
1668 last_irec_time = irec.time;
1669 if (irec.event_id == event_id && irec.time <= end_time && irec.time >= start_time) {
1670 /* check if record time more than "interval" seconds after previous time */
1671 if (irec.time >= prev_time + interval) {
1672 prev_time = irec.time;
1673 xseek(fn, fh, irec.offset);
1674 if (xread(fn, fh, (char *) &rec, sizeof(rec)) < 0) {
1675 cm_msg(MERROR, "hs_read", "corrupted history data at time %d", (int) irec.time);
1676 //*tbsize = *dbsize = *n = 0;
1677 if (fh > 0)
1678 close(fh);
1679 if (fhd > 0)
1680 close(fhd);
1681 if (fhi > 0)
1682 close(fhi);
1683 hs_gen_index(last_irec_time);
1684 return HS_SUCCESS;
1685 }
1686
1687 /* if definition changed, read new definition */
1688 if ((INT) rec.def_offset != old_def_offset) {
1689 xseek(fn, fh, rec.def_offset);
1690 xread(fn, fh, (char *) &drec, sizeof(drec));
1691 xread(fn, fh, str, NAME_LENGTH);
1692
1693 tag = (TAG *) M_MALLOC(drec.data_size);
1694 if (tag == NULL) {
1695 if (data_n)
1696 *data_n = 0;
1697 if (tbsize)
1698 *tbsize = 0;
1699 if (dbsize)
1700 *dbsize = 0;
1701 if (cache)
1702 M_FREE(cache);
1703 if (fh > 0)
1704 close(fh);
1705 if (fhd > 0)
1706 close(fhd);
1707 if (fhi > 0)
1708 close(fhi);
1709 return HS_NO_MEMORY;
1710 }
1711 xread(fn, fh, (char *) tag, drec.data_size);
1712
1713 /* find index of tag_name in new definition */
1714 for (DWORD i = 0; i < drec.data_size / sizeof(TAG); i++)
1715 if (equal_ustring(tag[i].name, tag_name)) {
1716 tag_index = i;
1717 break;
1718 }
1719
1720 /*
1721 if ((DWORD) i == drec.data_size/sizeof(TAG))
1722 {
1723 *n = *tbsize = *dbsize = 0;
1724 if (cache)
1725 M_FREE(cache);
1726
1727 return HS_UNDEFINED_VAR;
1728 }
1729 */
1730
1731 if (tag_index >= 0 && var_index >= tag[tag_index].n_data) {
1732 if (data_n)
1733 *data_n = 0;
1734 if (tbsize)
1735 *tbsize = 0;
1736 if (dbsize)
1737 *dbsize = 0;
1738 if (cache)
1739 M_FREE(cache);
1740 M_FREE(tag);
1741 if (fh > 0)
1742 close(fh);
1743 if (fhd > 0)
1744 close(fhd);
1745 if (fhi > 0)
1746 close(fhi);
1747 return HS_WRONG_INDEX;
1748 }
1749
1750 /* calculate offset for variable */
1751 if (tag_index >= 0) {
1752 var_type = tag[tag_index].type;
1753
1754 if (data_type)
1755 *data_type = var_type;
1756
1757 /* loop over all previous variables */
1758 var_offset = 0;
1759 for (int i=0; i<tag_index; i++)
1760 var_offset += rpc_tid_size(tag[i].type) * tag[i].n_data;
1761
1762 /* strings have size n_data */
1763 if (tag[tag_index].type == TID_STRING)
1764 var_size = tag[tag_index].n_data;
1765 else
1766 var_size = rpc_tid_size(tag[tag_index].type);
1767
1768 var_offset += var_size * var_index;
1769 }
1770
1771 M_FREE(tag);
1772 old_def_offset = rec.def_offset;
1773 xseek(fn, fh, irec.offset + sizeof(rec));
1774 }
1775
1776 if (buffer) {
1777 /* copy time from header */
1778 DWORD t = irec.time;
1779 char buf[16]; // biggest data is 8-byte "double"
1780 assert(var_size <= sizeof(buf));
1781 xseek_cur(fn, fh, var_offset);
1782 xread(fn, fh, buf, var_size);
1783 buffer->Add(t, hs_to_double(var_type, buf));
1784 } else if (tag_index >= 0 && data_n) {
1785 /* check if data fits in buffers */
1786 if ((*data_n) * sizeof(DWORD) >= *tbsize || (*data_n) * var_size >= *dbsize) {
1787 *dbsize = (*data_n) * var_size;
1788 *tbsize = (*data_n) * sizeof(DWORD);
1789 if (cache)
1790 M_FREE(cache);
1791 if (fh > 0)
1792 close(fh);
1793 if (fhd > 0)
1794 close(fhd);
1795 if (fhi > 0)
1796 close(fhi);
1797 return HS_TRUNCATED;
1798 }
1799
1800 /* copy time from header */
1801 time_buffer[*data_n] = irec.time;
1802
1803 /* copy data from record */
1804 xseek_cur(fn, fh, var_offset);
1805 xread(fn, fh, (char *) data_buffer + (*data_n) * var_size, var_size);
1806
1807 /* increment counter */
1808 (*data_n)++;
1809 }
1810 }
1811 }
1812
1813 /* read next index record */
1814 if (cache) {
1815 if (cp >= cache_size) {
1816 ieof = -1;
1817 M_FREE(cache);
1818 cache = NULL;
1819 } else {
1820
1821 try_again:
1822
1823 ieof = sizeof(irec);
1824
1825 memcpy(&irec, cache + cp, sizeof(irec));
1826 cp += sizeof(irec);
1827
1828 /* if history file is broken ... */
1829 if (irec.time < last_irec_time || irec.time > last_irec_time + 24 * 60 * 60) {
1830 //if (irec.time < last_irec_time) {
1831 //printf("time %d -> %d, cache_size %d, cp %d\n", last_irec_time, irec.time, cache_size, cp);
1832
1833 //printf("Seeking next record...\n");
1834
1835 while (cp < cache_size) {
1836 DWORD *evidp = (DWORD *) (cache + cp);
1837 if (*evidp == event_id) {
1838 //printf("Found at cp %d\n", cp);
1839 goto try_again;
1840 }
1841
1842 cp++;
1843 }
1844
1845 ieof = -1;
1846 }
1847 }
1848 } else {
1849 ieof = xread(fni, fhi, (char *) &irec, sizeof(irec), true);
1850 }
1851
1852 /* end of file: search next history file */
1853 if (ieof <= 0) {
1854 nextday:
1855
1856 if (fh > 0)
1857 close(fh);
1858 if (fhd > 0)
1859 close(fhd);
1860 if (fhi > 0)
1861 close(fhi);
1862 fh = fhd = fhi = 0;
1863
1864 /* advance one day */
1865 ltime = (time_t) last_irec_time;
1866 struct tm tms;
1867 localtime_r(&ltime, &tms);
1868 tms.tm_hour = tms.tm_min = tms.tm_sec = 0;
1869 last_irec_time = (DWORD) ss_mktime(&tms);
1870
1871 last_irec_time += 3600 * 24;
1872
1873 if (last_irec_time > end_time)
1874 break;
1875
1876 /* search next file */
1877 status = hs_search_file(&last_irec_time, 1);
1878 if (status != HS_SUCCESS)
1879 break;
1880
1881 /* open history and definition files */
1882 hs_open_file(last_irec_time, "hst", O_RDONLY, &fn, &fh);
1883 hs_open_file(last_irec_time, "idf", O_RDONLY, &fnd, &fhd);
1884 hs_open_file(last_irec_time, "idx", O_RDONLY, &fni, &fhi);
1885 if (fh < 0 || fhd < 0 || fhi < 0) {
1886 cm_msg(MERROR, "hs_read", "cannot open index files");
1887 break;
1888 }
1889
1890 /* try to read index file into cache */
1891 xseek_end(fni, fhi);
1892 cache_size = xcurpos(fni, fhi);
1893
1894 if (cache_size == 0) {
1895 goto nextday;
1896 }
1897
1898 xseek(fni, fhi, 0);
1899 cache = (char *) M_MALLOC(cache_size); // FIXME: is this a memory leak?
1900 if (cache) {
1901 if (xread(fni, fhi, cache, cache_size) < 0) {
1902 break;
1903 }
1904 /* read first record */
1905 cp = 0;
1906 memcpy(&irec, cache, sizeof(irec));
1907 } else {
1908 /* read first record */
1909 if (xread(fni, fhi, (char *) &irec, sizeof(irec)) < 0) {
1910 break;
1911 }
1912 }
1913
1914 /* old definition becomes invalid */
1915 old_def_offset = -1;
1916 }
1917 //if (event_id==4 && irec.event_id == event_id)
1918 // printf("time %d end %d\n", irec.time, end_time);
1919 } while (irec.time < end_time);
1920
1921 if (cache)
1922 M_FREE(cache);
1923 if (fh)
1924 close(fh);
1925 if (fhd)
1926 close(fhd);
1927 if (fhi)
1928 close(fhi);
1929
1930 if (dbsize && data_n)
1931 *dbsize = *data_n * var_size;
1932 if (tbsize && data_n)
1933 *tbsize = *data_n * sizeof(DWORD);
1934
1935 return HS_SUCCESS;
1936}
1937
1939#endif /* DOXYGEN_SHOULD_SKIP_THIS */
1940
1941/********************************************************************/
1953/********************************************************************/
1954static INT hs_dump(DWORD event_id, DWORD start_time, DWORD end_time, DWORD interval, BOOL binary_time)
1955{
1956 DWORD prev_time, last_irec_time;
1957 time_t ltime;
1958 int fh, fhd, fhi;
1959 std::string fn, fnd, fni;
1960 INT i, j, delta, status, n_tag = 0, old_n_tag = 0;
1961 INDEX_RECORD irec;
1962 HIST_RECORD rec, drec;
1963 INT old_def_offset, offset;
1964 TAG *tag = NULL, *old_tag = NULL;
1965 char data_buffer[10000];
1966
1967 ss_tzset(); // required by localtime_r()
1968
1969 /* if not time given, use present to one hour in past */
1970 if (start_time == 0)
1971 start_time = (DWORD) time(NULL) - 3600;
1972 if (end_time == 0)
1973 end_time = (DWORD) time(NULL);
1974
1975 /* search history file for start_time */
1976 status = hs_search_file(&start_time, 1);
1977 if (status != HS_SUCCESS) {
1978 cm_msg(MERROR, "hs_dump", "cannot find recent history file");
1979 return HS_FILE_ERROR;
1980 }
1981
1982 /* open history and definition files */
1983 hs_open_file(start_time, "hst", O_RDONLY, &fn, &fh);
1984 hs_open_file(start_time, "idf", O_RDONLY, &fnd, &fhd);
1985 hs_open_file(start_time, "idx", O_RDONLY, &fni, &fhi);
1986 if (fh < 0 || fhd < 0 || fhi < 0) {
1987 cm_msg(MERROR, "hs_dump", "cannot open index files");
1988 return HS_FILE_ERROR;
1989 }
1990
1991 /* search record closest to start time */
1992 xseek_end(fni, fhi);
1993 delta = (xcurpos(fni, fhi) / sizeof(irec)) / 2;
1994 xseek(fni, fhi, delta * sizeof(irec));
1995 do {
1996 delta = (int) (abs(delta) / 2.0 + 0.5);
1997 xread(fni, fhi, (char *) &irec, sizeof(irec));
1998 if (irec.time > start_time)
1999 delta = -delta;
2000
2001 xseek_cur(fni, fhi, (delta - 1) * sizeof(irec));
2002 } while (abs(delta) > 1 && irec.time != start_time);
2003 xread(fni, fhi, (char *) &irec, sizeof(irec));
2004 if (irec.time > start_time)
2005 delta = -abs(delta);
2006
2007 i = xcurpos(fni, fhi) + (delta - 1) * sizeof(irec);
2008 if (i <= 0)
2009 xseek(fni, fhi, 0);
2010 else
2011 xseek_cur(fni, fhi, (delta - 1) * sizeof(irec));
2012 xread(fni, fhi, (char *) &irec, sizeof(irec));
2013
2014 /* read records, skip wrong IDs */
2015 old_def_offset = -1;
2016 prev_time = 0;
2017 last_irec_time = 0;
2018 do {
2019 if (irec.time < last_irec_time) {
2020 cm_msg(MERROR, "hs_dump", "corrupted history data: time does not increase: %d -> %d", last_irec_time, irec.time);
2021 hs_gen_index(last_irec_time);
2022 return HS_FILE_ERROR;
2023 }
2024 last_irec_time = irec.time;
2025 if (irec.event_id == event_id && irec.time <= end_time && irec.time >= start_time) {
2026 if (irec.time >= prev_time + interval) {
2027 prev_time = irec.time;
2028 xseek(fn, fh, irec.offset);
2029 xread(fn, fh, (char *) &rec, sizeof(rec));
2030
2031 /* if definition changed, read new definition */
2032 if ((INT) rec.def_offset != old_def_offset) {
2033 char buf_name_length[NAME_LENGTH];
2034 xseek(fn, fh, rec.def_offset);
2035 xread(fn, fh, (char *) &drec, sizeof(drec));
2036 xread(fn, fh, buf_name_length, NAME_LENGTH);
2037
2038 if (tag == NULL)
2039 tag = (TAG *) M_MALLOC(drec.data_size);
2040 else
2041 tag = (TAG *) realloc(tag, drec.data_size);
2042 if (tag == NULL)
2043 return HS_NO_MEMORY;
2044 xread(fn, fh, (char *) tag, drec.data_size);
2045 n_tag = drec.data_size / sizeof(TAG);
2046
2047 /* print tag names if definition has changed */
2048 if (old_tag == NULL || old_n_tag != n_tag || memcmp(old_tag, tag, drec.data_size) != 0) {
2049 printf("Date\t");
2050 for (i = 0; i < n_tag; i++) {
2051 if (tag[i].n_data == 1 || tag[i].type == TID_STRING)
2052 printf("%s\t", tag[i].name);
2053 else
2054 for (j = 0; j < (INT) tag[i].n_data; j++)
2055 printf("%s%d\t", tag[i].name, j);
2056 }
2057 printf("\n");
2058
2059 if (old_tag == NULL)
2060 old_tag = (TAG *) M_MALLOC(drec.data_size);
2061 else
2062 old_tag = (TAG *) realloc(old_tag, drec.data_size);
2063 memcpy(old_tag, tag, drec.data_size);
2064 old_n_tag = n_tag;
2065 }
2066
2067 old_def_offset = rec.def_offset;
2068 xseek(fn, fh, irec.offset + sizeof(rec));
2069 }
2070
2071 /* print time from header */
2072 if (binary_time)
2073 printf("%d ", irec.time);
2074 else {
2075 ltime = (time_t) irec.time;
2076 char ctimebuf[32];
2077 ctime_r(&ltime, ctimebuf);
2078 char str[256];
2079 mstrlcpy(str, ctimebuf + 4, sizeof(str));
2080 str[20] = '\t';
2081 printf("%s", str);
2082 }
2083
2084 /* read data */
2085 xread(fn, fh, data_buffer, rec.data_size);
2086
2087 /* interprete data from tag definition */
2088 offset = 0;
2089 for (i = 0; i < n_tag; i++) {
2090 /* strings have a length of n_data */
2091 if (tag[i].type == TID_STRING) {
2092 printf("%s\t", data_buffer + offset);
2093 offset += tag[i].n_data;
2094 } else if (tag[i].n_data == 1) {
2095 /* non-array data */
2096 std::string data_str = db_sprintf(data_buffer + offset, rpc_tid_size(tag[i].type), 0, tag[i].type);
2097 printf("%s\t", data_str.c_str());
2098 offset += rpc_tid_size(tag[i].type);
2099 } else
2100 /* loop over array data */
2101 for (j = 0; j < (INT) tag[i].n_data; j++) {
2102 std::string data_str = db_sprintf(data_buffer + offset, rpc_tid_size(tag[i].type), 0, tag[i].type);
2103 printf("%s\t", data_str.c_str());
2104 offset += rpc_tid_size(tag[i].type);
2105 }
2106 }
2107 printf("\n");
2108 }
2109 }
2110
2111 /* read next index record */
2112 i = xread(fni, fhi, (char *) &irec, sizeof(irec), true);
2113
2114 /* end of file: search next history file */
2115 if (i <= 0) {
2116 close(fh);
2117 close(fhd);
2118 close(fhi);
2119
2120 /* advance one day */
2121 ltime = (time_t) last_irec_time;
2122 struct tm tms;
2123 localtime_r(&ltime, &tms);
2124 tms.tm_hour = tms.tm_min = tms.tm_sec = 0;
2125 last_irec_time = (DWORD) ss_mktime(&tms);
2126
2127 last_irec_time += 3600 * 24;
2128 if (last_irec_time > end_time)
2129 break;
2130
2131 /* search next file */
2132 status = hs_search_file((DWORD *) & last_irec_time, 1);
2133 if (status != HS_SUCCESS)
2134 break;
2135
2136 /* open history and definition files */
2137 hs_open_file(last_irec_time, "hst", O_RDONLY, &fn, &fh);
2138 hs_open_file(last_irec_time, "idf", O_RDONLY, &fnd, &fhd);
2139 hs_open_file(last_irec_time, "idx", O_RDONLY, &fni, &fhi);
2140 if (fh < 0 || fhd < 0 || fhi < 0) {
2141 cm_msg(MERROR, "hs_dump", "cannot open index files");
2142 break;
2143 }
2144
2145 /* read first record */
2146 i = xread(fni, fhi, (char *) &irec, sizeof(irec), true);
2147 if (i <= 0)
2148 break;
2149
2150 /* old definition becomes invalid */
2151 old_def_offset = -1;
2152 }
2153 } while (irec.time < end_time);
2154
2155 M_FREE(tag);
2156 M_FREE(old_tag);
2157 close(fh);
2158 close(fhd);
2159 close(fhi);
2160
2161 return HS_SUCCESS;
2162}
2163
2165#ifndef DOXYGEN_SHOULD_SKIP_THIS
2166
2167#endif /* OS_VXWORKS hs section */
2168
2170#endif /* DOXYGEN_SHOULD_SKIP_THIS */
2171
2172#if 0
2173char* sort_names(char* names)
2174{
2175 int i, p;
2176 int len = 0;
2177 int num = 0;
2178 char* arr_names;
2179 struct poor_mans_list sorted;
2180
2181 for (i=0, p=0; names[p]!=0; i++) {
2182 const char*pp = names+p;
2183 int pplen = strlen(pp);
2184 //printf("%d [%s] %d\n", i, pp, pplen);
2185 if (pplen > len)
2186 len = pplen;
2187 p += strlen(names+p) + 1;
2188 }
2189
2190 num = i;
2191
2192 len+=1; // space for string terminator '\0'
2193
2194 arr_names = (char*)malloc(len*num);
2195
2196 for (i=0, p=0; names[p]!=0; i++) {
2197 const char*pp = names+p;
2198 mstrlcpy(arr_names+i*len, pp, len);
2199 p += strlen(names+p) + 1;
2200 }
2201
2202 free(names);
2203
2204 qsort(arr_names, num, len, sort_tags);
2205
2206 list_init(&sorted);
2207
2208 for (i=0; i<num; i++)
2209 list_add(&sorted, arr_names+i*len);
2210
2211 return sorted.names;
2212}
2213#endif
2214
2215/*------------------------------------------------------------------*/
2216
2218{
2219public:
2222
2223 std::vector<std::string> fEventsCache;
2224 std::map<std::string, std::vector<TAG> > fTagsCache;
2225 std::map<std::string, int > fEvidCache;
2226
2227public:
2229 {
2230 fDebug = 0;
2231 }
2232
2234 {
2235 // empty
2236 }
2237
2238 /*------------------------------------------------------------------*/
2239
2240 int hs_connect(const char* path)
2241 {
2243
2244 /* delete obsolete odb entries */
2245
2246 db_delete(fDB, 0, "/History/ListSource");
2247
2248 ::hs_set_path(path);
2249
2250 if (fDebug)
2251 printf("hs_connect: path [%s]\n", path);
2252
2253 return HS_SUCCESS;
2254 }
2255
2256 /*------------------------------------------------------------------*/
2257
2259 {
2261 return HS_SUCCESS;
2262 }
2263
2264 /*------------------------------------------------------------------*/
2265
2267 {
2268 return debug;
2269 }
2270
2271 /*------------------------------------------------------------------*/
2272
2274 {
2275 if (fDebug)
2276 printf("hs_clear_cache!\n");
2277
2278 fEventsCache.clear();
2279 fTagsCache.clear();
2280 fEvidCache.clear();
2281 return HS_SUCCESS;
2282 }
2283
2284 /*------------------------------------------------------------------*/
2285
2286 int FindEventId(const char* event_name)
2287 {
2288 HNDLE hKeyRoot;
2289 int status;
2290 char name[256];
2291 mstrlcpy(name, event_name, sizeof(name));
2292 char *s = strchr(name, '/');
2293 if (s)
2294 *s = ':';
2295
2296 //printf("Looking for event id for \'%s\'\n", name);
2297
2298 status = db_find_key(fDB, 0, "/History/Events", &hKeyRoot);
2299 if (status == DB_SUCCESS) {
2300 for (int i = 0;; i++) {
2301 HNDLE hKey;
2302 KEY key;
2303
2304 status = db_enum_key(fDB, hKeyRoot, i, &hKey);
2305 if (status != DB_SUCCESS)
2306 break;
2307
2309 assert(status == DB_SUCCESS);
2310
2311 //printf("key \'%s\'\n", key.name);
2312
2313 int evid = (WORD) strtol(key.name, NULL, 0);
2314 if (evid == 0)
2315 continue;
2316
2317 char tmp[NAME_LENGTH+NAME_LENGTH+2];
2318 int size = sizeof(tmp);
2319 status = db_get_data(fDB, hKey, tmp, &size, TID_STRING);
2320 assert(status == DB_SUCCESS);
2321
2322 //printf("got %d \'%s\' looking for \'%s\'\n", evid, tmp, name);
2323
2324 if (equal_ustring(name, tmp))
2325 return evid;
2326 }
2327 }
2328
2329 return -1;
2330 }
2331
2332 /*------------------------------------------------------------------*/
2333
2334 int AllocateEventId(const char* event_name)
2335 {
2336 int status;
2337 char name[256];
2338 mstrlcpy(name, event_name, sizeof(name));
2339 char *s = strchr(name, '/');
2340 if (s)
2341 *s = ':';
2342
2343 // special event id for run transitions
2344 if (strcmp(name, "Run transitions")==0) {
2345 status = db_set_value(fDB, 0, "/History/Events/0", name, strlen(name)+1, 1, TID_STRING);
2346 assert(status == DB_SUCCESS);
2347 return 0;
2348 }
2349
2350 if (1) {
2351 std::string tmp = msprintf("/Equipment/%s/Common/Event ID", name);
2352
2353 WORD evid = 0;
2354 int size = sizeof(evid);
2355 status = db_get_value(fDB, 0, tmp.c_str(), &evid, &size, TID_WORD, FALSE);
2356 if (status == DB_SUCCESS) {
2357
2358 std::string he = msprintf("/History/Events/%d", evid);
2359
2360 std::string xname;
2361 status = db_get_value_string(fDB, 0, he.c_str(), 0, &xname);
2362 if (status == DB_SUCCESS && xname != event_name) {
2363 cm_msg(MERROR, "add_event", "History events \"%s\" and \"%s\" use the same history event id %d. If both equipments write to the history, their data will be mixed up. To fix this, enable per-variable history, turn off the \"MIDAS\" history (use \"FILE\" history) or change event IDs or set \"common/log history\" to zero", event_name, xname.c_str(), evid);
2364 }
2365
2366 status = db_set_value(fDB, 0, he.c_str(), name, strlen(name)+1, 1, TID_STRING);
2367 assert(status == DB_SUCCESS);
2368
2369 //printf("AllocateEventId: event [%s] allocated common/event id %d\n", event_name, evid);
2370
2371 return evid;
2372 }
2373 }
2374
2375 for (int evid = 101; evid < 65000; evid++) {
2376 char tmp[256];
2377 HNDLE hKey;
2378
2379 sprintf(tmp,"/History/Events/%d", evid);
2380
2381 status = db_find_key(fDB, 0, tmp, &hKey);
2382 if (status != DB_SUCCESS) {
2383
2384 status = db_set_value(fDB, 0, tmp, name, strlen(name)+1, 1, TID_STRING);
2385 assert(status == DB_SUCCESS);
2386
2387 //printf("AllocateEventId: event [%s] allocated next sequential id %d\n", event_name, evid);
2388
2389 return evid;
2390 }
2391 }
2392
2393 cm_msg(MERROR, "AllocateEventId", "Cannot allocate history event id - all in use - please examine /History/Events");
2394 return -1;
2395 }
2396
2397 /*------------------------------------------------------------------*/
2398
2399 int CreateOdbTags(int event_id, const char* event_name, int ntags, const TAG tags[])
2400 {
2401 int disableTags;
2402 int oldTags;
2403 int size, status;
2404
2405 /* create history tags for mhttpd */
2406
2407 disableTags = 0;
2408 size = sizeof(disableTags);
2409 status = db_get_value(fDB, 0, "/History/DisableTags", &disableTags, &size, TID_BOOL, TRUE);
2410
2411 oldTags = 0;
2412 size = sizeof(oldTags);
2413 status = db_get_value(fDB, 0, "/History/CreateOldTags", &oldTags, &size, TID_BOOL, FALSE);
2414
2415 if (disableTags) {
2416 status = db_delete(fDB, 0, "/History/Tags");
2417 if (status != DB_SUCCESS) {
2418 cm_msg(MERROR, "add_event", "Cannot delete /History/Tags, db_delete() status %d", status);
2419 }
2420 } else if (oldTags) {
2421
2422 char buf[256];
2423
2424 sprintf(buf, "/History/Tags/%d", event_id);
2425
2426 //printf("Set tag \'%s\' = \'%s\'\n", buf, event_name);
2427
2428 status = db_set_value(fDB, 0, buf, (void*)event_name, strlen(event_name)+1, 1, TID_STRING);
2429 assert(status == DB_SUCCESS);
2430
2431 for (int i=0; i<ntags; i++) {
2432 WORD v = (WORD) tags[i].n_data;
2433 sprintf(buf, "/History/Tags/Tags %d/%s", event_id, tags[i].name);
2434
2435 //printf("Set tag \'%s\' = %d\n", buf, v);
2436
2437 status = db_set_value(fDB, 0, buf, &v, sizeof(v), 1, TID_WORD);
2438 assert(status == DB_SUCCESS);
2439
2440 if (strlen(tags[i].name) == NAME_LENGTH-1)
2441 cm_msg(MERROR, "add_event",
2442 "Tag name \'%s\' in event %d (%s) may have been truncated to %d characters",
2443 tags[i].name, event_id, event_name, NAME_LENGTH-1);
2444 }
2445
2446 } else {
2447
2448 const int kLength = 32 + NAME_LENGTH + NAME_LENGTH;
2449 char buf[kLength];
2450 HNDLE hKey;
2451
2452 sprintf(buf, "/History/Tags/%d", event_id);
2453 status = db_find_key(fDB, 0, buf, &hKey);
2454
2455 if (status == DB_SUCCESS) {
2456 // add new tags
2457 KEY key;
2458
2460 assert(status == DB_SUCCESS);
2461
2462 assert(key.type == TID_STRING);
2463
2464 if (key.item_size < kLength && key.num_values == 1) {
2465 // old style tags are present. Convert them to new style!
2466
2467 HNDLE hTags;
2468
2469 cm_msg(MINFO, "add_event", "Converting old event %d (%s) tags to new style", event_id, event_name);
2470
2471 mstrlcpy(buf, event_name, kLength);
2472
2473 status = db_set_data(fDB, hKey, buf, kLength, 1, TID_STRING);
2474 assert(status == DB_SUCCESS);
2475
2476 sprintf(buf, "/History/Tags/Tags %d", event_id);
2477
2478 status = db_find_key(fDB, 0, buf, &hTags);
2479
2480 if (status == DB_SUCCESS) {
2481 for (int i=0; ; i++) {
2482 HNDLE h;
2483 int size;
2484 KEY key;
2485 WORD w;
2486
2487 status = db_enum_key(fDB, hTags, i, &h);
2489 break;
2490 assert(status == DB_SUCCESS);
2491
2492 status = db_get_key(fDB, h, &key);
2493
2494 size = sizeof(w);
2495 status = db_get_data(fDB, h, &w, &size, TID_WORD);
2496 assert(status == DB_SUCCESS);
2497
2498 sprintf(buf, "%d[%d] %s", 0, w, key.name);
2499
2500 status = db_set_data_index(fDB, hKey, buf, kLength, 1+i, TID_STRING);
2501 assert(status == DB_SUCCESS);
2502 }
2503
2504 status = db_delete_key(fDB, hTags);
2505 assert(status == DB_SUCCESS);
2506 }
2507
2508 // format conversion has changed the key, get it again
2510 assert(status == DB_SUCCESS);
2511 }
2512
2513 if (1) {
2514 // add new tags
2515
2516 int size = key.item_size * key.num_values;
2517 int num = key.num_values;
2518
2519 char* s = (char*)malloc(size);
2520 assert(s != NULL);
2521
2522 TAG* t = (TAG*)malloc(sizeof(TAG)*(key.num_values + ntags));
2523 assert(t != NULL);
2524
2525 status = db_get_data(fDB, hKey, s, &size, TID_STRING);
2526 assert(status == DB_SUCCESS);
2527
2528 for (int i=1; i<key.num_values; i++) {
2529 char* ss = s + i*key.item_size;
2530
2531 t[i].type = 0;
2532 t[i].n_data = 0;
2533 t[i].name[0] = 0;
2534
2535 if (isdigit(ss[0])) {
2536 //sscanf(ss, "%d[%d] %s", &t[i].type, &t[i].n_data, t[i].name);
2537
2538 t[i].type = strtoul(ss, &ss, 0);
2539 assert(*ss == '[');
2540 ss++;
2541 t[i].n_data = strtoul(ss, &ss, 0);
2542 assert(*ss == ']');
2543 ss++;
2544 assert(*ss == ' ');
2545 ss++;
2546 mstrlcpy(t[i].name, ss, sizeof(t[i].name));
2547
2548 //printf("type %d, n_data %d, name [%s]\n", t[i].type, t[i].n_data, t[i].name);
2549 }
2550 }
2551
2552 for (int i=0; i<ntags; i++) {
2553 int k = 0;
2554
2555 for (int j=1; j<key.num_values; j++) {
2556 if (equal_ustring((char*)tags[i].name, (char*)t[j].name)) {
2557 if ((tags[i].type!=t[j].type) || (tags[i].n_data!=t[j].n_data)) {
2558 cm_msg(MINFO, "add_event", "Event %d (%s) tag \"%s\" type and size changed from %d[%d] to %d[%d]",
2559 event_id, event_name,
2560 tags[i].name,
2561 t[j].type, t[j].n_data,
2562 tags[i].type, tags[i].n_data);
2563 k = j;
2564 break;
2565 }
2566
2567 k = -1;
2568 break;
2569 }
2570 }
2571
2572 // if tag not present, k==0, so append it to the array
2573
2574 if (k==0)
2575 k = num;
2576
2577 if (k > 0) {
2578 sprintf(buf, "%d[%d] %s", tags[i].type, tags[i].n_data, tags[i].name);
2579
2580 status = db_set_data_index(fDB, hKey, buf, kLength, k, TID_STRING);
2581 assert(status == DB_SUCCESS);
2582
2583 if (k >= num)
2584 num = k+1;
2585 }
2586 }
2587
2588 free(s);
2589 free(t);
2590 }
2591
2592 } else if (status == DB_NO_KEY) {
2593 // create new array of tags
2594 status = db_create_key(fDB, 0, buf, TID_STRING);
2595 assert(status == DB_SUCCESS);
2596
2597 status = db_find_key(fDB, 0, buf, &hKey);
2598 assert(status == DB_SUCCESS);
2599
2600 mstrlcpy(buf, event_name, kLength);
2601
2602 status = db_set_data(fDB, hKey, buf, kLength, 1, TID_STRING);
2603 assert(status == DB_SUCCESS);
2604
2605 for (int i=0; i<ntags; i++) {
2606 sprintf(buf, "%d[%d] %s", tags[i].type, tags[i].n_data, tags[i].name);
2607
2608 status = db_set_data_index(fDB, hKey, buf, kLength, 1+i, TID_STRING);
2609 assert(status == DB_SUCCESS);
2610 }
2611 } else {
2612 cm_msg(MERROR, "add_event", "Error: db_find_key(%s) status %d", buf, status);
2613 return HS_FILE_ERROR;
2614 }
2615 }
2616
2617 return HS_SUCCESS;
2618 }
2619
2620 /*------------------------------------------------------------------*/
2621
2622 int hs_define_event(const char* event_name, time_t timestamp, int ntags, const TAG tags[])
2623 {
2624 int event_id = FindEventId(event_name);
2625 if (event_id < 0)
2626 event_id = AllocateEventId(event_name);
2627 if (event_id < 0)
2628 return HS_FILE_ERROR;
2629 fEvidCache[event_name] = event_id;
2630 CreateOdbTags(event_id, event_name, ntags, tags);
2631 return ::hs_define_event(event_id, (char*)event_name, (TAG*)tags, ntags*sizeof(TAG));
2632 }
2633
2634 /*------------------------------------------------------------------*/
2635
2636 int hs_write_event(const char* event_name, time_t timestamp, int data_size, const char* data)
2637 {
2638 int event_id = fEvidCache[event_name];
2639 //printf("write event [%s] evid %d\n", event_name, event_id);
2640 return ::hs_write_event(event_id, (void*)data, data_size);
2641 }
2642
2643 /*------------------------------------------------------------------*/
2644
2646 {
2647 //printf("hs_flush_buffers!\n");
2648 return HS_SUCCESS;
2649 }
2650
2651 /*------------------------------------------------------------------*/
2652
2653 int GetEventsFromOdbEvents(std::vector<std::string> *events)
2654 {
2655 HNDLE hKeyRoot;
2656 int status;
2657
2658 status = db_find_key(fDB, 0, "/History/Events", &hKeyRoot);
2659 if (status != DB_SUCCESS) {
2660 return HS_FILE_ERROR;
2661 }
2662
2663 /* loop over tags to display event names */
2664 for (int i = 0;; i++) {
2665 HNDLE hKeyEq;
2666 char *s;
2667 char evname[1024+NAME_LENGTH];
2668 int size;
2669
2670 status = db_enum_key(fDB, hKeyRoot, i, &hKeyEq);
2671 if (status != DB_SUCCESS)
2672 break;
2673
2674 size = sizeof(evname);
2675 status = db_get_data(fDB, hKeyEq, evname, &size, TID_STRING);
2676 assert(status == DB_SUCCESS);
2677
2678 s = strchr(evname,':');
2679 if (s)
2680 *s = '/';
2681
2682 /* skip duplicated event names */
2683
2684 int found = 0;
2685 for (unsigned i=0; i<events->size(); i++) {
2686 if (equal_ustring(evname, (*events)[i].c_str())) {
2687 found = 1;
2688 break;
2689 }
2690 }
2691
2692 if (found)
2693 continue;
2694
2695 events->push_back(evname);
2696
2697 //printf("event \'%s\'\n", evname);
2698 }
2699
2700 return HS_SUCCESS;
2701 }
2702
2703 int GetEventsFromOdbTags(std::vector<std::string> *events)
2704 {
2705 HNDLE hKeyRoot;
2706 int status;
2707
2708 status = db_find_key(fDB, 0, "/History/Tags", &hKeyRoot);
2709 if (status != DB_SUCCESS) {
2710 return HS_FILE_ERROR;
2711 }
2712
2713 /* loop over tags to display event names */
2714 for (int i = 0;; i++) {
2715 HNDLE hKeyEq;
2716 KEY key;
2717 char *s;
2718 WORD event_id;
2719 char evname[1024+NAME_LENGTH];
2720 int size;
2721
2722 status = db_enum_key(fDB, hKeyRoot, i, &hKeyEq);
2723 if (status != DB_SUCCESS)
2724 break;
2725
2726 /* get event name */
2727 db_get_key(fDB, hKeyEq, &key);
2728
2729 //printf("key \'%s\'\n", key.name);
2730
2731 if (key.type != TID_STRING)
2732 continue;
2733
2734 /* parse event name in format: "event_id" or "event_id:var_name" */
2735 s = key.name;
2736
2737 event_id = (WORD)strtoul(s,&s,0);
2738 if (event_id == 0)
2739 continue;
2740 if (s[0] != 0)
2741 continue;
2742
2743 size = sizeof(evname);
2744 status = db_get_data_index(fDB, hKeyEq, evname, &size, 0, TID_STRING);
2745 assert(status == DB_SUCCESS);
2746
2747 /* skip duplicated event names */
2748
2749 int found = 0;
2750 for (unsigned i=0; i<events->size(); i++) {
2751 if (equal_ustring(evname, (*events)[i].c_str())) {
2752 found = 1;
2753 break;
2754 }
2755 }
2756
2757 if (found)
2758 continue;
2759
2760 events->push_back(evname);
2761
2762 //printf("event %d \'%s\'\n", event_id, evname);
2763 }
2764
2765 return HS_SUCCESS;
2766 }
2767
2768 int hs_get_events(time_t t, std::vector<std::string> *pevents)
2769 {
2770 assert(pevents);
2771 pevents->clear();
2772
2773 if (fEventsCache.size() == 0) {
2774 int status;
2775
2776 if (fDebug)
2777 printf("hs_get_events: reading events list!\n");
2778
2780
2781 if (status != HS_SUCCESS)
2783
2784 if (status != HS_SUCCESS)
2785 return status;
2786 }
2787
2788 for (unsigned i=0; i<fEventsCache.size(); i++)
2789 pevents->push_back(fEventsCache[i]);
2790
2791 return HS_SUCCESS;
2792 }
2793
2794 int GetEventIdFromHS(time_t ltime, const char* evname, const char* tagname)
2795 {
2796 HNDLE hKeyRoot;
2797 int status;
2798
2799 status = db_find_key(fDB, 0, "/History/Events", &hKeyRoot);
2800 if (status != DB_SUCCESS) {
2801 return -1;
2802 }
2803
2804 for (int i = 0;; i++) {
2805 HNDLE hKey;
2806 KEY key;
2807 int evid;
2808 char buf[256];
2809 int size;
2810 char *s;
2811 int ntags = 0;
2812 TAG* tags = NULL;
2813 char event_name[NAME_LENGTH];
2814
2815 status = db_enum_key(fDB, hKeyRoot, i, &hKey);
2816 if (status != DB_SUCCESS)
2817 break;
2818
2820 assert(status == DB_SUCCESS);
2821
2822 if (!isdigit(key.name[0]))
2823 continue;
2824
2825 evid = atoi(key.name);
2826
2827 assert(key.item_size < (int)sizeof(buf));
2828
2829 size = sizeof(buf);
2830 status = db_get_data(fDB, hKey, buf, &size, TID_STRING);
2831 assert(status == DB_SUCCESS);
2832
2833 mstrlcpy(event_name, buf, sizeof(event_name));
2834
2835 s = strchr(buf,':');
2836 if (s)
2837 *s = 0;
2838
2839 //printf("Found event %d, event [%s] name [%s], looking for [%s][%s]\n", evid, event_name, buf, evname, tagname);
2840
2841 if (!equal_ustring((char *)evname, buf))
2842 continue;
2843
2844 status = ::hs_get_tags((DWORD)ltime, evid, event_name, &ntags, &tags);
2845
2846 for (int j=0; j<ntags; j++) {
2847 //printf("at %d [%s] looking for [%s]\n", j, tags[j].name, tagname);
2848
2849 if (equal_ustring((char *)tagname, tags[j].name)) {
2850 if (tags)
2851 free(tags);
2852 return evid;
2853 }
2854 }
2855
2856 if (tags)
2857 free(tags);
2858 tags = NULL;
2859 }
2860
2861 return -1;
2862 }
2863
2864 int GetEventIdFromOdbTags(const char* evname, const char* tagname)
2865 {
2866 HNDLE hKeyRoot;
2867 int status;
2868
2869 status = db_find_key(fDB, 0, "/History/Tags", &hKeyRoot);
2870 if (status != DB_SUCCESS) {
2871 return -1;
2872 }
2873
2874 for (int i = 0;; i++) {
2875 HNDLE hKey;
2876 KEY key;
2877 int evid;
2878 char buf[256];
2879 int size;
2880 char *s;
2881
2882 status = db_enum_key(fDB, hKeyRoot, i, &hKey);
2883 if (status != DB_SUCCESS)
2884 break;
2885
2887 assert(status == DB_SUCCESS);
2888
2889 if (key.type != TID_STRING)
2890 continue;
2891
2892 if (!isdigit(key.name[0]))
2893 continue;
2894
2895 evid = atoi(key.name);
2896
2897 assert(key.item_size < (int)sizeof(buf));
2898
2899 size = sizeof(buf);
2900 status = db_get_data_index(fDB, hKey, buf, &size, 0, TID_STRING);
2901 assert(status == DB_SUCCESS);
2902
2903 s = strchr(buf,'/');
2904 if (s)
2905 *s = 0;
2906
2907 //printf("Found event %d, name [%s], looking for [%s][%s]\n", evid, buf, evname, tagname);
2908
2909 if (!equal_ustring((char *)evname, buf))
2910 continue;
2911
2912 for (int j=1; j<key.num_values; j++) {
2913 size = sizeof(buf);
2914 status = db_get_data_index(fDB, hKey, buf, &size, j, TID_STRING);
2915 assert(status == DB_SUCCESS);
2916
2917 if (!isdigit(buf[0]))
2918 continue;
2919
2920 s = strchr(buf,' ');
2921 if (!s)
2922 continue;
2923
2924 s++;
2925
2926 //printf("at %d [%s] [%s] compare to [%s]\n", j, buf, s, tagname);
2927
2928 if (equal_ustring((char *)tagname, s)) {
2929 //printf("Found evid %d\n", evid);
2930 return evid;
2931 }
2932 }
2933 }
2934
2935 return -1;
2936 }
2937
2938 int GetEventId(time_t t, const char* event_name, const char* tag_name, int *pevid)
2939 {
2940 int event_id = -1;
2941
2942 if (fDebug && event_name != NULL && tag_name != NULL)
2943 printf("xhs_event_id for event [%s], tag [%s]\n", event_name, tag_name);
2944
2945 *pevid = 0;
2946
2947 /* use "/History/Tags" if available */
2948 event_id = GetEventIdFromOdbTags(event_name, tag_name);
2949
2950 /* if no Tags, use "/History/Events" and hs_get_tags() to read definition from history files */
2951 if (event_id < 0)
2952 event_id = GetEventIdFromHS(t, event_name, tag_name);
2953
2954 /* if nothing works, use hs_get_event_id() */
2955 if (event_id <= 0) {
2956 DWORD evid = 0;
2957 int status = ::hs_get_event_id((DWORD)t, (char*)event_name, &evid);
2958 if (status != HS_SUCCESS)
2959 return status;
2960 event_id = evid;
2961 }
2962
2963 if (event_id < 0)
2964 return HS_UNDEFINED_VAR;
2965
2966 *pevid = event_id;
2967
2968 return HS_SUCCESS;
2969 }
2970
2971 int GetTagsFromHS(const char* event_name, std::vector<TAG> *ptags)
2972 {
2973 time_t now = time(NULL);
2974 int evid;
2975 int status = GetEventId(now, event_name, NULL, &evid);
2976 if (status != HS_SUCCESS)
2977 return status;
2978
2979 if (fDebug)
2980 printf("hs_get_tags: get tags for event [%s] %d\n", event_name, evid);
2981
2982 int ntags;
2983 TAG* tags;
2984 status = ::hs_get_tags((DWORD)now, evid, (char*)event_name, &ntags, &tags);
2985
2986 if (status != HS_SUCCESS)
2987 return status;
2988
2989 for (int i=0; i<ntags; i++)
2990 ptags->push_back(tags[i]);
2991
2992 if (tags)
2993 free(tags);
2994
2995 if (fDebug)
2996 printf("hs_get_tags: get tags for event [%s] %d, found %d tags\n", event_name, evid, ntags);
2997
2998 return HS_SUCCESS;
2999 }
3000
3001 int GetTagsFromOdb(const char* event_name, std::vector<TAG> *ptags)
3002 {
3003 HNDLE hKeyRoot;
3004 int status;
3005
3006 status = db_find_key(fDB, 0, "/History/Tags", &hKeyRoot);
3007 if (status != DB_SUCCESS) {
3008 return HS_FILE_ERROR;
3009 }
3010
3011 /* loop over equipment to display event name */
3012 for (int i = 0;; i++) {
3013 HNDLE hKey;
3014 KEY key;
3015 WORD event_id;
3016 char buf[256];
3017 int size;
3018 char* s;
3019
3020 status = db_enum_key(fDB, hKeyRoot, i, &hKey);
3021 if (status != DB_SUCCESS)
3022 break;
3023
3024 /* get event name */
3026 assert(status == DB_SUCCESS);
3027
3028 /* parse event id */
3029 if (!isdigit(key.name[0]))
3030 continue;
3031
3032 event_id = atoi(key.name);
3033 if (event_id == 0)
3034 continue;
3035
3036 if (key.item_size >= (int)sizeof(buf))
3037 continue;
3038
3039 if (key.num_values == 1) { // old format of "/History/Tags"
3040
3041 HNDLE hKeyDir;
3042 sprintf(buf, "Tags %d", event_id);
3043 status = db_find_key(fDB, hKeyRoot, buf, &hKeyDir);
3044 if (status != DB_SUCCESS)
3045 continue;
3046
3047 /* loop over tags */
3048 for (int j=0; ; j++) {
3049 HNDLE hKey;
3050 WORD array;
3051 int size;
3052 char var_name[NAME_LENGTH];
3053
3054 status = db_enum_key(fDB, hKeyDir, j, &hKey);
3055 if (status != DB_SUCCESS)
3056 break;
3057
3058 /* get event name */
3060 assert(status == DB_SUCCESS);
3061
3062 array = 1;
3063 size = sizeof(array);
3064 status = db_get_data(fDB, hKey, &array, &size, TID_WORD);
3065 assert(status == DB_SUCCESS);
3066
3067 mstrlcpy(var_name, key.name, sizeof(var_name));
3068
3069 //printf("Found %s, event %d (%s), tag (%s) array %d\n", key.name, event_id, event_name, var_name, array);
3070
3071 TAG t;
3072 mstrlcpy(t.name, var_name, sizeof(t.name));
3073 t.n_data = array;
3074 t.type = 0;
3075
3076 ptags->push_back(t);
3077 }
3078
3079 continue;
3080 }
3081
3082 if (key.type != TID_STRING)
3083 continue;
3084
3085 size = sizeof(buf);
3086 status = db_get_data_index(fDB, hKey, buf, &size, 0, TID_STRING);
3087 assert(status == DB_SUCCESS);
3088
3089 if (strchr(event_name, '/')==NULL) {
3090 char* s = strchr(buf, '/');
3091 if (s)
3092 *s = 0;
3093 }
3094
3095 //printf("evid %d, name [%s]\n", event_id, buf);
3096
3097 if (!equal_ustring(buf, event_name))
3098 continue;
3099
3100 /* loop over tags */
3101 for (int j=1; j<key.num_values; j++) {
3102 int array;
3103 int size;
3104 char var_name[NAME_LENGTH];
3105 int ev_type;
3106
3107 size = sizeof(buf);
3108 status = db_get_data_index(fDB, hKey, buf, &size, j, TID_STRING);
3109 assert(status == DB_SUCCESS);
3110
3111 //printf("index %d [%s]\n", j, buf);
3112
3113 if (!isdigit(buf[0]))
3114 continue;
3115
3116 sscanf(buf, "%d[%d]", &ev_type, &array);
3117
3118 s = strchr(buf, ' ');
3119 if (!s)
3120 continue;
3121 s++;
3122
3123 mstrlcpy(var_name, s, sizeof(var_name));
3124
3125 TAG t;
3126 mstrlcpy(t.name, var_name, sizeof(t.name));
3127 t.n_data = array;
3128 t.type = ev_type;
3129
3130 //printf("Found %s, event %d, tag (%s) array %d, type %d\n", buf, event_id, var_name, array, ev_type);
3131
3132 ptags->push_back(t);
3133 }
3134 }
3135
3136 return HS_SUCCESS;
3137 }
3138
3139 /*------------------------------------------------------------------*/
3140
3141 int hs_get_tags(const char* event_name, time_t t, std::vector<TAG> *ptags)
3142 {
3143 std::vector<TAG>& ttt = fTagsCache[event_name];
3144
3145 if (ttt.size() == 0) {
3146 int status = HS_FILE_ERROR;
3147
3148 if (fDebug)
3149 printf("hs_get_tags: reading tags for event [%s]\n", event_name);
3150
3151 status = GetTagsFromOdb(event_name, &ttt);
3152
3153 if (status != HS_SUCCESS)
3154 status = GetTagsFromHS(event_name, &ttt);
3155
3156 if (status != HS_SUCCESS)
3157 return status;
3158 }
3159
3160 for (unsigned i=0; i<ttt.size(); i++)
3161 ptags->push_back(ttt[i]);
3162
3163 return HS_SUCCESS;
3164 }
3165
3166 /*------------------------------------------------------------------*/
3167
3168 int hs_get_last_written(time_t start_time, int num_var, const char* const event_name[], const char* const tag_name[], const int var_index[], time_t last_written[])
3169 {
3170 for (int i=0; i<num_var; i++)
3171 last_written[i] = 0;
3172 return HS_FILE_ERROR;
3173 }
3174
3175 /*------------------------------------------------------------------*/
3176
3177
3178 int hs_read(time_t start_time, time_t end_time, time_t interval,
3179 int num_var,
3180 const char* const event_name[], const char* const tag_name[], const int var_index[],
3181 int num_entries[],
3182 time_t* time_buffer[], double* data_buffer[],
3183 int read_status[])
3184 {
3185 DWORD* tbuffer = NULL;
3186 char* ybuffer = NULL;
3187 DWORD bsize, tsize;
3188 int hbuffer_size = 0;
3189
3190 if (hbuffer_size == 0) {
3191 hbuffer_size = 1000 * sizeof(DWORD);
3192 tbuffer = (DWORD*)malloc(hbuffer_size);
3193 ybuffer = (char*)malloc(hbuffer_size);
3194 }
3195
3196 for (int i=0; i<num_var; i++) {
3197 DWORD tid = 0;
3198 int event_id = 0;
3199
3200 if (event_name[i]==NULL) {
3201 read_status[i] = HS_UNDEFINED_EVENT;
3202 num_entries[i] = 0;
3203 continue;
3204 }
3205
3206 int status = GetEventId(end_time, event_name[i], tag_name[i], &event_id);
3207
3208 if (status != HS_SUCCESS) {
3209 read_status[i] = status;
3210 continue;
3211 }
3212
3213 DWORD n_point = 0;
3214
3215 do {
3216 bsize = tsize = hbuffer_size;
3217 memset(ybuffer, 0, bsize);
3218 status = ::hs_read(event_id, (DWORD)start_time, (DWORD)end_time, (DWORD)interval,
3219 tag_name[i], var_index[i],
3220 tbuffer, &tsize,
3221 ybuffer, &bsize,
3222 &tid, &n_point,
3223 NULL);
3224
3225 if (fDebug)
3226 printf("hs_read %d \'%s\' [%d] returned %d, %d entries\n", event_id, tag_name[i], var_index[i], status, n_point);
3227
3228 if (status == HS_TRUNCATED) {
3229 hbuffer_size *= 2;
3230 tbuffer = (DWORD*)realloc(tbuffer, hbuffer_size);
3231 assert(tbuffer);
3232 ybuffer = (char*)realloc(ybuffer, hbuffer_size);
3233 assert(ybuffer);
3234 }
3235
3236 } while (status == HS_TRUNCATED);
3237
3238 read_status[i] = status;
3239
3240 time_t* x = (time_t*)malloc(n_point*sizeof(time_t));
3241 assert(x);
3242 double* y = (double*)malloc(n_point*sizeof(double));
3243 assert(y);
3244
3245 time_buffer[i] = x;
3246 data_buffer[i] = y;
3247
3248 int n_vp = 0;
3249
3250 for (unsigned j = 0; j < n_point; j++) {
3251 x[n_vp] = tbuffer[j];
3252
3253 /* convert data to float */
3254 switch (tid) {
3255 default:
3256 y[n_vp] = 0;
3257 break;
3258 case TID_BYTE:
3259 y[n_vp] = *(((BYTE *) ybuffer) + j);
3260 break;
3261 case TID_SBYTE:
3262 y[n_vp] = *(((char *) ybuffer) + j);
3263 break;
3264 case TID_CHAR:
3265 y[n_vp] = *(((char *) ybuffer) + j);
3266 break;
3267 case TID_WORD:
3268 y[n_vp] = *(((WORD *) ybuffer) + j);
3269 break;
3270 case TID_SHORT:
3271 y[n_vp] = *(((short *) ybuffer) + j);
3272 break;
3273 case TID_DWORD:
3274 y[n_vp] = *(((DWORD *) ybuffer) + j);
3275 break;
3276 case TID_INT:
3277 y[n_vp] = *(((INT *) ybuffer) + j);
3278 break;
3279 case TID_BOOL:
3280 y[n_vp] = *(((BOOL *) ybuffer) + j);
3281 break;
3282 case TID_FLOAT:
3283 y[n_vp] = *(((float *) ybuffer) + j);
3284 break;
3285 case TID_DOUBLE:
3286 y[n_vp] = *(((double *) ybuffer) + j);
3287 break;
3288 }
3289
3290 n_vp++;
3291 }
3292
3293 num_entries[i] = n_vp;
3294 }
3295
3296 if (ybuffer)
3297 free(ybuffer);
3298 if (tbuffer)
3299 free(tbuffer);
3300
3301 return HS_SUCCESS;
3302 }
3303
3304 /*------------------------------------------------------------------*/
3305#if 0
3306 int hs_read2(time_t start_time, time_t end_time, time_t interval,
3307 int num_var,
3308 const char* const event_name[], const char* const tag_name[], const int var_index[],
3309 int num_entries[],
3310 time_t* time_buffer[],
3311 double* mean_buffer[],
3312 double* rms_buffer[],
3313 double* min_buffer[],
3314 double* max_buffer[],
3315 int read_status[])
3316 {
3317 int status = hs_read(start_time, end_time, interval, num_var, event_name, tag_name, var_index, num_entries, time_buffer, mean_buffer, read_status);
3318
3319 for (int i=0; i<num_var; i++) {
3320 int num = num_entries[i];
3321 rms_buffer[i] = (double*)malloc(sizeof(double)*num);
3322 min_buffer[i] = (double*)malloc(sizeof(double)*num);
3323 max_buffer[i] = (double*)malloc(sizeof(double)*num);
3324
3325 for (int j=0; j<num; j++) {
3326 rms_buffer[i][j] = 0;
3327 min_buffer[i][j] = mean_buffer[i][j];
3328 max_buffer[i][j] = mean_buffer[i][j];
3329 }
3330 }
3331
3332 return status;
3333 }
3334#endif
3335
3336 int hs_read_buffer(time_t start_time, time_t end_time,
3337 int num_var, const char* const event_name[], const char* const tag_name[], const int var_index[],
3339 int read_status[])
3340 {
3341 for (int i=0; i<num_var; i++) {
3342 int event_id = 0;
3343
3344 if (event_name[i]==NULL) {
3345 read_status[i] = HS_UNDEFINED_EVENT;
3346 continue;
3347 }
3348
3349 int status = GetEventId(end_time, event_name[i], tag_name[i], &event_id);
3350
3351 if (status != HS_SUCCESS) {
3352 read_status[i] = status;
3353 continue;
3354 }
3355
3356 status = ::hs_read(event_id, (DWORD)start_time, (DWORD)end_time, 0,
3357 tag_name[i], var_index[i],
3358 NULL, NULL,
3359 NULL, NULL,
3360 NULL, NULL,
3361 buffer[i]);
3362
3363 if (fDebug) {
3364 printf("hs_read %d \'%s\' [%d] returned %d\n", event_id, tag_name[i], var_index[i], status);
3365 }
3366
3367 read_status[i] = status;
3368 }
3369
3370 return HS_SUCCESS;
3371 }
3372
3373 int hs_read_binned(time_t start_time, time_t end_time, int num_bins,
3374 int num_var, const char* const event_name[], const char* const tag_name[], const int var_index[],
3375 int num_entries[],
3376 int* count_bins[], double* mean_bins[], double* rms_bins[], double* min_bins[], double* max_bins[],
3377 time_t* bins_first_time[], double* bins_first_value[],
3378 time_t* bins_last_time[], double* bins_last_value[],
3379 time_t last_time[], double last_value[],
3380 int read_status[])
3381 {
3382 int status;
3383
3384 MidasHistoryBinnedBuffer** buffer = new MidasHistoryBinnedBuffer*[num_var];
3386
3387 for (int i=0; i<num_var; i++) {
3388 buffer[i] = new MidasHistoryBinnedBuffer(start_time, end_time, num_bins);
3389 xbuffer[i] = buffer[i];
3390
3391 if (count_bins)
3392 buffer[i]->fCount = count_bins[i];
3393 if (mean_bins)
3394 buffer[i]->fMean = mean_bins[i];
3395 if (rms_bins)
3396 buffer[i]->fRms = rms_bins[i];
3397 if (min_bins)
3398 buffer[i]->fMin = min_bins[i];
3399 if (max_bins)
3400 buffer[i]->fMax = max_bins[i];
3401 if (bins_first_time)
3402 buffer[i]->fBinsFirstTime = bins_first_time[i];
3403 if (bins_first_value)
3404 buffer[i]->fBinsFirstValue = bins_first_value[i];
3405 if (bins_last_time)
3406 buffer[i]->fBinsLastTime = bins_last_time[i];
3407 if (bins_last_value)
3408 buffer[i]->fBinsLastValue = bins_last_value[i];
3409 if (last_time)
3410 buffer[i]->fLastTimePtr = &last_time[i];
3411 if (last_value)
3412 buffer[i]->fLastValuePtr = &last_value[i];
3413
3414 buffer[i]->Start();
3415 }
3416
3417 status = hs_read_buffer(start_time, end_time,
3418 num_var, event_name, tag_name, var_index,
3419 xbuffer,
3420 read_status);
3421
3422 for (int i=0; i<num_var; i++) {
3423 buffer[i]->Finish();
3424 if (num_entries)
3425 num_entries[i] = buffer[i]->fNumEntries;
3426 //if (0) {
3427 // for (int j=0; j<num_bins; j++) {
3428 // printf("var %d bin %d count %d, first %s last %s value first %f last %f\n", i, j, count_bins[i][j], TimeToString(bins_first_time[i][j]).c_str(), TimeToString(bins_last_time[i][j]).c_str(), bins_first_value[i][j], bins_last_value[i][j]);
3429 // }
3430 //}
3431 delete buffer[i];
3432 }
3433
3434 delete[] buffer;
3435 delete[] xbuffer;
3436
3437 return status;
3438 }
3439
3440}; // end class
3441
3442
3443/********************************************************************/
3452/********************************************************************/
3453
3454#define HISTORY_PANEL(_name) const char *_name[] = {\
3455"[.]",\
3456"Variables = STRING : [64] :",\
3457"Timescale = STRING : [32] 10m",\
3458"Zero ylow = BOOL : n",\
3459"Show run markers = BOOL : y",\
3460"Buttons = STRING[7] :",\
3461"[32] 10m",\
3462"[32] 1h",\
3463"[32] 3h",\
3464"[32] 12h",\
3465"[32] 24h",\
3466"[32] 3d",\
3467"[32] 7d",\
3468"Log axis = BOOL : n",\
3469"Show values = BOOL : y",\
3470"Sort vars = BOOL : n",\
3471"Show old vars = BOOL : n",\
3472"Minimum = DOUBLE : -inf",\
3473"Maximum = DOUBLE : inf",\
3474"Label = STRING : [32] ",\
3475"Colour = STRING : [32] ",\
3476"Formula = STRING : [64] ",\
3477"Show fill = BOOL : y",\
3478"",\
3479NULL }
3480
3481
3482INT hs_define_panel(const char *group, const char *panel, const std::vector<std::string> var)
3483{
3484 HNDLE hDB, hKey, hKeyVar;
3485 HISTORY_PANEL(history_panel_str);
3486 char str[256];
3487
3488 const char *color[] = {
3489 "#00AAFF", "#FF9000", "#FF00A0", "#00C030",
3490 "#A0C0D0", "#D0A060", "#C04010", "#807060",
3491 "#F0C000", "#2090A0", "#D040D0", "#90B000",
3492 "#B0B040", "#B0B0FF", "#FFA0A0", "#A0FFA0",
3493 "#808080"};
3494
3496
3497 snprintf(str, sizeof(str), "/History/Display/%s/%s", group, panel);
3498
3499 db_create_record(hDB, 0, str, strcomb1(history_panel_str).c_str());
3500 db_find_key(hDB, 0, str, &hKey);
3501 if (!hKey)
3502 return DB_NO_MEMORY;
3503
3504 int i=0;
3505 for(auto const& v: var) {
3506 db_find_key(hDB, hKey, "Variables", &hKeyVar);
3507 db_set_data_index(hDB, hKeyVar, v.c_str(), 64, i, TID_STRING);
3508
3509 str[0] = 0;
3510 db_set_value_index(hDB, hKey, "Formula", str, 64, i, TID_STRING, false);
3511 db_set_value_index(hDB, hKey, "Label", str, 32, i, TID_STRING, false);
3512 db_set_value_index(hDB, hKey, "Colour", color[i < 16 ? i : 16], 32, i, TID_STRING, false);
3513
3514 i++;
3515 }
3516
3517 return HS_SUCCESS;
3518}
3519
3520INT hs_define_panel2(const char *group, const char *panel, const std::vector<std::string> var,
3521 const std::vector<std::string> label, const std::vector<std::string> formula,
3522 const std::vector<std::string> color)
3523{
3524 HNDLE hDB, hKey, hKeyVar;
3525 HISTORY_PANEL(history_panel_str);
3526 char str[256];
3527
3528 const char *default_color[] = {
3529 "#00AAFF", "#FF9000", "#FF00A0", "#00C030",
3530 "#A0C0D0", "#D0A060", "#C04010", "#807060",
3531 "#F0C000", "#2090A0", "#D040D0", "#90B000",
3532 "#B0B040", "#B0B0FF", "#FFA0A0", "#A0FFA0",
3533 "#808080"};
3534
3536
3537 snprintf(str, sizeof(str), "/History/Display/%s/%s", group, panel);
3538
3539 db_create_record(hDB, 0, str, strcomb1(history_panel_str).c_str());
3540 db_find_key(hDB, 0, str, &hKey);
3541 if (!hKey)
3542 return DB_NO_MEMORY;
3543
3544 int i=0;
3545 for(auto const& v: var) {
3546 db_find_key(hDB, hKey, "Variables", &hKeyVar);
3547 db_set_data_index(hDB, hKeyVar, v.c_str(), 64, i, TID_STRING);
3548
3549 if (i < (int)formula.size())
3550 mstrlcpy(str, formula[i].c_str(), sizeof(str)-1);
3551 else
3552 str[0] = 0;
3553 db_set_value_index(hDB, hKey, "Formula", str, 64, i, TID_STRING, false);
3554
3555 if (i < (int)label.size())
3556 mstrlcpy(str, label[i].c_str(), sizeof(str)-1);
3557 else
3558 str[0] = 0;
3559 db_set_value_index(hDB, hKey, "Label", str, 32, i, TID_STRING, false);
3560
3561 if (i < (int)color.size())
3562 mstrlcpy(str, color[i].c_str(), sizeof(str)-1);
3563 else
3564 mstrlcpy(str, default_color[i < 16 ? i : 16], sizeof(str)-1);
3565 db_set_value_index(hDB, hKey, "Colour", str, 32, i, TID_STRING, false);
3566
3567 i++;
3568 }
3569
3570 return HS_SUCCESS;
3571}
3572
3574{
3575#if 0
3576 // midas history is a singleton class
3577 static MidasHistory* gh = NULL;
3578 if (!gh)
3579 gh = new MidasHistory;
3580 return gh;
3581#endif
3582 return new MidasHistory();
3583}
3584
3585/* emacs
3586 * Local Variables:
3587 * tab-width: 8
3588 * c-basic-offset: 3
3589 * indent-tabs-mode: nil
3590 * End:
3591 */
#define FALSE
Definition cfortran.h:309
virtual void Add(time_t time, double value)=0
char type[NAME_LENGTH]
history channel name
Definition history.h:112
char name[NAME_LENGTH]
Definition history.h:111
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition midas.cxx:3026
INT cm_get_experiment_semaphore(INT *semaphore_alarm, INT *semaphore_elog, INT *semaphore_history, INT *semaphore_msg)
Definition midas.cxx:3048
#define DB_SUCCESS
Definition midas.h:632
#define DB_NO_MEMORY
Definition midas.h:634
#define DB_NO_KEY
Definition midas.h:643
#define DB_NO_MORE_SUBKEYS
Definition midas.h:647
#define SS_SUCCESS
Definition midas.h:664
#define HS_UNDEFINED_VAR
Definition midas.h:734
#define HS_SUCCESS
Definition midas.h:728
#define HS_FILE_ERROR
Definition midas.h:729
#define HS_TRUNCATED
Definition midas.h:731
#define HS_NO_MEMORY
Definition midas.h:730
#define HS_WRONG_INDEX
Definition midas.h:732
#define HS_UNDEFINED_EVENT
Definition midas.h:733
static INT hs_open_file(time_t ltime, const char *suffix, INT mode, std::string *pfile_name, int *fh)
Definition history.cxx:206
static std::vector< HISTORY * > _history
Definition history.cxx:45
static int xread(const std::string &fn, int fh, void *buf, size_t count, bool eof_ok=false)
Definition history.cxx:73
int GetEventsFromOdbTags(std::vector< std::string > *events)
Definition history.cxx:2703
static INT hs_enum_vars(DWORD ltime, DWORD event_id, char *var_name, DWORD *size, DWORD *var_n, DWORD *n_size)
Definition history.cxx:1128
MidasHistoryInterface * MakeMidasHistory()
Definition history.cxx:3573
static INT hs_search_file(DWORD *ltime, INT direction)
Definition history.cxx:353
int hs_define_event(const char *event_name, time_t timestamp, int ntags, const TAG tags[])
see hs_define_event(), returns HS_SUCCESS or HS_FILE_ERROR
Definition history.cxx:2622
static bool xwrite(const std::string &fn, int fh, const void *buf, size_t count)
Definition history.cxx:51
int hs_flush_buffers()
flush buffered data to storage where it is visible to mhttpd
Definition history.cxx:2645
int hs_get_last_written(time_t start_time, int num_var, const char *const event_name[], const char *const tag_name[], const int var_index[], time_t last_written[])
Definition history.cxx:3168
static INT hs_define_event(DWORD event_id, const char *name, const TAG *tag, DWORD size)
Definition history.cxx:427
static bool xtruncate(const std::string &fn, int fh, DWORD pos)
Definition history.cxx:152
int hs_disconnect()
disconnect from history, returns HS_SUCCESS
Definition history.cxx:2258
int GetEventId(time_t t, const char *event_name, const char *tag_name, int *pevid)
Definition history.cxx:2938
int hs_read_buffer(time_t start_time, time_t end_time, int num_var, const char *const event_name[], const char *const tag_name[], const int var_index[], MidasHistoryBufferInterface *buffer[], int read_status[])
returns HS_SUCCESS
Definition history.cxx:3336
static INT hs_count_vars(DWORD ltime, DWORD event_id, DWORD *count)
Definition history.cxx:1060
int hs_write_event(const char *event_name, time_t timestamp, int data_size, const char *data)
see hs_write_event(), returns HS_SUCCESS or HS_FILE_ERROR
Definition history.cxx:2636
int GetTagsFromOdb(const char *event_name, std::vector< TAG > *ptags)
Definition history.cxx:3001
static DWORD xcurpos(const std::string &fn, int fh)
Definition history.cxx:133
int hs_set_debug(int debug)
set debug level, returns previous debug level
Definition history.cxx:2266
int hs_read_binned(time_t start_time, time_t end_time, int num_bins, int num_var, const char *const event_name[], const char *const tag_name[], const int var_index[], int num_entries[], int *count_bins[], double *mean_bins[], double *rms_bins[], double *min_bins[], double *max_bins[], time_t *bins_first_time[], double *bins_first_value[], time_t *bins_last_time[], double *bins_last_value[], time_t last_time[], double last_value[], int read_status[])
returns HS_SUCCESS
Definition history.cxx:3373
INT hs_define_panel2(const char *group, const char *panel, const std::vector< std::string > var, const std::vector< std::string > label, const std::vector< std::string > formula, const std::vector< std::string > color)
Definition history.cxx:3520
INT hs_define_panel(const char *group, const char *panel, const std::vector< std::string > var)
Definition history.cxx:3482
int FindEventId(const char *event_name)
Definition history.cxx:2286
int GetEventsFromOdbEvents(std::vector< std::string > *events)
Definition history.cxx:2653
static INT hs_count_events(DWORD ltime, DWORD *count)
Definition history.cxx:907
static INT hs_get_tags(DWORD ltime, DWORD event_id, char event_name[NAME_LENGTH], int *n_tags, TAG **tags)
Definition history.cxx:1328
int GetTagsFromHS(const char *event_name, std::vector< TAG > *ptags)
Definition history.cxx:2971
int hs_get_tags(const char *event_name, time_t t, std::vector< TAG > *ptags)
get list of history variables for given event (use event names returned by hs_get_events()) that exis...
Definition history.cxx:3141
int hs_get_events(time_t t, std::vector< std::string > *pevents)
get list of events that exist(ed) at given time and later (value 0 means "return all events from begi...
Definition history.cxx:2768
static bool xseek_end(const std::string &fn, int fh)
Definition history.cxx:109
std::vector< std::string > fEventsCache
Definition history.cxx:2223
#define HISTORY_PANEL(_name)
Definition history.cxx:3454
static INT hs_read(DWORD event_id, DWORD start_time, DWORD end_time, DWORD interval, const char *tag_name, DWORD var_index, DWORD *time_buffer, DWORD *tbsize, void *data_buffer, DWORD *dbsize, DWORD *data_type, DWORD *data_n, MidasHistoryBufferInterface *buffer)
Definition history.cxx:1451
static INT hs_get_event_id(DWORD ltime, const char *name, DWORD *id)
Definition history.cxx:984
static INT hs_enum_events(DWORD ltime, char *event_name, DWORD *name_size, INT event_id[], DWORD *id_size)
Definition history.cxx:823
int hs_clear_cache()
clear internal cache, returns HS_SUCCESS
Definition history.cxx:2273
static bool xseek_cur(const std::string &fn, int fh, int offset)
Definition history.cxx:121
double hs_to_double(int tid, const void *ybuffer)
Definition history.cxx:1420
static INT hs_get_var(DWORD ltime, DWORD event_id, const char *var_name, DWORD *type, INT *n_data)
Definition history.cxx:1232
static INT hs_gen_index(DWORD ltime)
Definition history.cxx:237
int AllocateEventId(const char *event_name)
Definition history.cxx:2334
int CreateOdbTags(int event_id, const char *event_name, int ntags, const TAG tags[])
Definition history.cxx:2399
int GetEventIdFromHS(time_t ltime, const char *evname, const char *tagname)
Definition history.cxx:2794
std::map< std::string, std::vector< TAG > > fTagsCache
Definition history.cxx:2224
static INT hs_set_path(const char *path)
Definition history.cxx:178
static INT hs_dump(DWORD event_id, DWORD start_time, DWORD end_time, DWORD interval, BOOL binary_time)
Definition history.cxx:1954
int hs_read(time_t start_time, time_t end_time, time_t interval, int num_var, const char *const event_name[], const char *const tag_name[], const int var_index[], int num_entries[], time_t *time_buffer[], double *data_buffer[], int read_status[])
see hs_read(), returns HS_SUCCESS
Definition history.cxx:3178
static bool xseek(const std::string &fn, int fh, DWORD pos)
Definition history.cxx:97
int GetEventIdFromOdbTags(const char *evname, const char *tagname)
Definition history.cxx:2864
int hs_connect(const char *path)
returns HS_SUCCESS
Definition history.cxx:2240
static std::string _hs_path_name
Definition history.cxx:46
static INT hs_write_event(DWORD event_id, const void *data, DWORD size)
Definition history.cxx:656
std::map< std::string, int > fEvidCache
Definition history.cxx:2225
unsigned short int WORD
Definition mcstd.h:49
unsigned char BYTE
Definition mcstd.h:48
unsigned int DWORD
Definition mcstd.h:51
#define SUCCESS
Definition mcstd.h:54
#define TID_DOUBLE
Definition midas.h:343
#define TID_SBYTE
Definition midas.h:329
#define TID_BOOL
Definition midas.h:340
#define TID_SHORT
Definition midas.h:334
#define TID_WORD
Definition midas.h:332
#define MINFO
Definition midas.h:560
#define TID_BYTE
Definition midas.h:327
#define TID_STRING
Definition midas.h:346
#define MERROR
Definition midas.h:559
#define TID_CHAR
Definition midas.h:331
#define TID_INT
Definition midas.h:338
#define TID_FLOAT
Definition midas.h:341
#define TID_DWORD
Definition midas.h:336
#define O_BINARY
Definition msystem.h:226
time_t ss_mktime(struct tm *tms)
Definition system.cxx:3437
void ss_tzset()
Definition system.cxx:3427
INT ss_semaphore_release(HNDLE semaphore_handle)
Definition system.cxx:2853
DWORD ss_time()
Definition system.cxx:3534
INT ss_semaphore_wait_for(HNDLE semaphore_handle, DWORD timeout_millisec)
Definition system.cxx:2711
INT cm_msg(INT message_type, const char *filename, INT line, const char *routine, const char *format,...)
Definition midas.cxx:930
BOOL equal_ustring(const char *str1, const char *str2)
Definition odb.cxx:3285
INT db_get_data_index(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT idx, DWORD type)
Definition odb.cxx:6917
INT db_delete_key(HNDLE hDB, HNDLE hKey, BOOL follow_links)
Definition odb.cxx:3933
INT db_get_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, void *data, INT *buf_size, DWORD type, BOOL create)
Definition odb.cxx:5185
std::string strcomb1(const char **list)
Definition odb.cxx:668
INT db_get_data(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, DWORD type)
Definition odb.cxx:6563
INT db_create_key(HNDLE hDB, HNDLE hKey, const char *key_name, DWORD type)
Definition odb.cxx:3392
INT db_get_key(HNDLE hDB, HNDLE hKey, KEY *key)
Definition odb.cxx:6043
INT EXPRT db_get_value_string(HNDLE hdb, HNDLE hKeyRoot, const char *key_name, int index, std::string *s, BOOL create, int create_string_length)
Definition odb.cxx:13967
INT db_set_data_index(HNDLE hDB, HNDLE hKey, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:7668
INT db_set_data(HNDLE hDB, HNDLE hKey, const void *data, INT buf_size, INT num_values, DWORD type)
Definition odb.cxx:7239
INT db_delete(HNDLE hDB, HNDLE hKeyRoot, const char *odb_path)
Definition odb.cxx:3999
INT db_sprintf(char *string, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:10865
INT db_set_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, const void *data, INT data_size, INT num_values, DWORD type)
Definition odb.cxx:5028
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition odb.cxx:4256
INT db_set_value_index(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, const void *data, INT data_size, INT idx, DWORD type, BOOL trunc)
Definition odb.cxx:5135
INT db_enum_key(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition odb.cxx:5357
INT db_create_record(HNDLE hDB, HNDLE hKey, const char *orig_key_name, const char *init_str)
Definition odb.cxx:12831
bool rpc_is_remote(void)
Definition midas.cxx:12786
INT rpc_tid_size(INT id)
Definition midas.cxx:11782
HNDLE hKey
DWORD n[4]
Definition mana.cxx:247
INT index
Definition mana.cxx:271
DWORD last_time
Definition mana.cxx:3070
void * data
Definition mana.cxx:268
BOOL debug
debug printouts
Definition mana.cxx:254
INT type
Definition mana.cxx:269
HNDLE hDB
main ODB handle
Definition mana.cxx:207
char color[][16]
Definition mchart.cxx:32
double count
Definition mdump.cxx:33
KEY key
Definition mdump.cxx:34
INT i
Definition mdump.cxx:32
static int offset
Definition mgd.cxx:1500
#define DWORD
Definition mhdump.cxx:31
BOOL binary_time
Definition mhist.cxx:18
std::string msprintf(const char *format,...)
Definition midas.cxx:419
#define DIR_SEPARATOR
Definition midas.h:193
INT HNDLE
Definition midas.h:132
#define M_MALLOC(x)
Definition midas.h:1551
DWORD BOOL
Definition midas.h:105
#define DIR_SEPARATOR_STR
Definition midas.h:194
int INT
Definition midas.h:129
#define RT_DEF
Definition midas.h:1357
#define M_FREE(x)
Definition midas.h:1553
#define RT_DATA
Definition midas.h:1356
#define TRUE
Definition midas.h:182
#define NAME_LENGTH
Definition midas.h:272
#define read(n, a, f)
#define event_id
#define write(n, a, f, d)
#define name(x)
Definition midas_macro.h:24
MUTEX_T * tm
Definition odbedit.cxx:39
INT j
Definition odbhist.cxx:40
INT k
Definition odbhist.cxx:40
char str[256]
Definition odbhist.cxx:33
char file_name[256]
Definition odbhist.cxx:41
DWORD status
Definition odbhist.cxx:39
char var_name[256]
Definition odbhist.cxx:41
DWORD def_offset
Definition midas.h:1370
DWORD event_id
Definition midas.h:1368
char event_name[NAME_LENGTH]
Definition midas.h:1369
DWORD def_offset
Definition midas.h:1363
DWORD record_type
Definition midas.h:1360
DWORD time
Definition midas.h:1362
DWORD data_size
Definition midas.h:1364
DWORD event_id
Definition midas.h:1361
DWORD time
Definition midas.h:1375
DWORD offset
Definition midas.h:1376
DWORD event_id
Definition midas.h:1374
Definition midas.h:1027
INT num_values
Definition midas.h:1029
DWORD type
Definition midas.h:1028
char name[NAME_LENGTH]
Definition midas.h:1030
INT item_size
Definition midas.h:1033
Definition midas.h:1233
DWORD type
Definition midas.h:1235
DWORD n_data
Definition midas.h:1236
char name[NAME_LENGTH]
Definition midas.h:1234