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{
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;
210
211 /* generate new file name YYMMDD.xxx */
212 ss_tzset(); // required by localtime_r()
213 ttime = (time_t) ltime;
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)
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/********************************************************************/
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;
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)
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 {
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 */
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);
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;
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 */
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{
683 int fh, fhi, fhd;
685 std::string fn, fni, fnd;
686 INT semaphore;
687 int status;
688 struct tm tmb, tmr;
690
691 /* request semaphore */
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/********************************************************************/
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;
850
851 /* search latest history file */
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);
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;
931
932 /* search latest history file */
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);
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;
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;
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/********************************************************************/
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;
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;
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;
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{
1489 int fh, fhd, fhi, cp = 0;
1490 std::string fn, fnd, fni;
1491 int delta;
1492 int status;
1493 int cache_size;
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);
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);
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);
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)
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
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 */
1866 struct tm tms;
1867 localtime_r(&ltime, &tms);
1868 tms.tm_hour = tms.tm_min = tms.tm_sec = 0;
1870
1871 last_irec_time += 3600 * 24;
1872
1873 if (last_irec_time > end_time)
1874 break;
1875
1876 /* search next file */
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);
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);
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/********************************************************************/
1955{
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;
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);
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) {
2034 xseek(fn, fh, rec.def_offset);
2035 xread(fn, fh, (char *) &drec, sizeof(drec));
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];
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 */
2122 struct tm tms;
2123 localtime_r(&ltime, &tms);
2124 tms.tm_hour = tms.tm_min = tms.tm_sec = 0;
2126
2127 last_irec_time += 3600 * 24;
2128 if (last_irec_time > end_time)
2129 break;
2130
2131 /* search next file */
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);
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 if (1) {
2247 HNDLE hKey;
2248 int status = db_find_key(fDB, 0, "/History/ListSource", &hKey);
2249 if (status == DB_SUCCESS)
2251 }
2252
2253 ::hs_set_path(path);
2254
2255 if (fDebug)
2256 printf("hs_connect: path [%s]\n", path);
2257
2258 return HS_SUCCESS;
2259 }
2260
2261 /*------------------------------------------------------------------*/
2262
2264 {
2266 return HS_SUCCESS;
2267 }
2268
2269 /*------------------------------------------------------------------*/
2270
2272 {
2273 return debug;
2274 }
2275
2276 /*------------------------------------------------------------------*/
2277
2279 {
2280 if (fDebug)
2281 printf("hs_clear_cache!\n");
2282
2283 fEventsCache.clear();
2284 fTagsCache.clear();
2285 fEvidCache.clear();
2286 return HS_SUCCESS;
2287 }
2288
2289 /*------------------------------------------------------------------*/
2290
2291 int FindEventId(const char* event_name)
2292 {
2294 int status;
2295 char name[256];
2296 mstrlcpy(name, event_name, sizeof(name));
2297 char *s = strchr(name, '/');
2298 if (s)
2299 *s = ':';
2300
2301 //printf("Looking for event id for \'%s\'\n", name);
2302
2303 status = db_find_key(fDB, 0, "/History/Events", &hKeyRoot);
2304 if (status == DB_SUCCESS) {
2305 for (int i = 0;; i++) {
2306 HNDLE hKey;
2307 KEY key;
2308
2310 if (status != DB_SUCCESS)
2311 break;
2312
2314 assert(status == DB_SUCCESS);
2315
2316 //printf("key \'%s\'\n", key.name);
2317
2318 int evid = (WORD) strtol(key.name, NULL, 0);
2319 if (evid == 0)
2320 continue;
2321
2322 char tmp[NAME_LENGTH+NAME_LENGTH+2];
2323 int size = sizeof(tmp);
2324 status = db_get_data(fDB, hKey, tmp, &size, TID_STRING);
2325 assert(status == DB_SUCCESS);
2326
2327 //printf("got %d \'%s\' looking for \'%s\'\n", evid, tmp, name);
2328
2329 if (equal_ustring(name, tmp))
2330 return evid;
2331 }
2332 }
2333
2334 return -1;
2335 }
2336
2337 /*------------------------------------------------------------------*/
2338
2339 int AllocateEventId(const char* event_name)
2340 {
2341 int status;
2342 char name[256];
2343 mstrlcpy(name, event_name, sizeof(name));
2344 char *s = strchr(name, '/');
2345 if (s)
2346 *s = ':';
2347
2348 // special event id for run transitions
2349 if (strcmp(name, "Run transitions")==0) {
2350 status = db_set_value(fDB, 0, "/History/Events/0", name, strlen(name)+1, 1, TID_STRING);
2351 assert(status == DB_SUCCESS);
2352 return 0;
2353 }
2354
2355 if (1) {
2356 std::string tmp = msprintf("/Equipment/%s/Common/Event ID", name);
2357
2358 WORD evid = 0;
2359 int size = sizeof(evid);
2360 status = db_get_value(fDB, 0, tmp.c_str(), &evid, &size, TID_WORD, FALSE);
2361 if (status == DB_SUCCESS) {
2362
2363 std::string he = msprintf("/History/Events/%d", evid);
2364
2365 std::string xname;
2366 status = db_get_value_string(fDB, 0, he.c_str(), 0, &xname);
2367 if (status == DB_SUCCESS && xname != event_name) {
2368 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);
2369 }
2370
2371 status = db_set_value(fDB, 0, he.c_str(), name, strlen(name)+1, 1, TID_STRING);
2372 assert(status == DB_SUCCESS);
2373
2374 //printf("AllocateEventId: event [%s] allocated common/event id %d\n", event_name, evid);
2375
2376 return evid;
2377 }
2378 }
2379
2380 for (int evid = 101; evid < 65000; evid++) {
2381 char tmp[256];
2382 HNDLE hKey;
2383
2384 sprintf(tmp,"/History/Events/%d", evid);
2385
2386 status = db_find_key(fDB, 0, tmp, &hKey);
2387 if (status != DB_SUCCESS) {
2388
2390 assert(status == DB_SUCCESS);
2391
2392 //printf("AllocateEventId: event [%s] allocated next sequential id %d\n", event_name, evid);
2393
2394 return evid;
2395 }
2396 }
2397
2398 cm_msg(MERROR, "AllocateEventId", "Cannot allocate history event id - all in use - please examine /History/Events");
2399 return -1;
2400 }
2401
2402 /*------------------------------------------------------------------*/
2403
2404 int CreateOdbTags(int event_id, const char* event_name, int ntags, const TAG tags[])
2405 {
2406 int disableTags;
2407 int oldTags;
2408 int size, status;
2409
2410 /* create history tags for mhttpd */
2411
2412 disableTags = 0;
2413 size = sizeof(disableTags);
2414 status = db_get_value(fDB, 0, "/History/DisableTags", &disableTags, &size, TID_BOOL, TRUE);
2415
2416 oldTags = 0;
2417 size = sizeof(oldTags);
2418 status = db_get_value(fDB, 0, "/History/CreateOldTags", &oldTags, &size, TID_BOOL, FALSE);
2419
2420 if (disableTags) {
2421 HNDLE hKey;
2422
2423 status = db_find_key(fDB, 0, "/History/Tags", &hKey);
2424 if (status == DB_SUCCESS) {
2426 if (status != DB_SUCCESS)
2427 cm_msg(MERROR, "add_event", "Cannot delete /History/Tags, db_delete_key() status %d", status);
2428 }
2429
2430 } else if (oldTags) {
2431
2432 char buf[256];
2433
2434 sprintf(buf, "/History/Tags/%d", event_id);
2435
2436 //printf("Set tag \'%s\' = \'%s\'\n", buf, event_name);
2437
2438 status = db_set_value(fDB, 0, buf, (void*)event_name, strlen(event_name)+1, 1, TID_STRING);
2439 assert(status == DB_SUCCESS);
2440
2441 for (int i=0; i<ntags; i++) {
2442 WORD v = (WORD) tags[i].n_data;
2443 sprintf(buf, "/History/Tags/Tags %d/%s", event_id, tags[i].name);
2444
2445 //printf("Set tag \'%s\' = %d\n", buf, v);
2446
2447 status = db_set_value(fDB, 0, buf, &v, sizeof(v), 1, TID_WORD);
2448 assert(status == DB_SUCCESS);
2449
2450 if (strlen(tags[i].name) == NAME_LENGTH-1)
2451 cm_msg(MERROR, "add_event",
2452 "Tag name \'%s\' in event %d (%s) may have been truncated to %d characters",
2453 tags[i].name, event_id, event_name, NAME_LENGTH-1);
2454 }
2455
2456 } else {
2457
2458 const int kLength = 32 + NAME_LENGTH + NAME_LENGTH;
2459 char buf[kLength];
2460 HNDLE hKey;
2461
2462 sprintf(buf, "/History/Tags/%d", event_id);
2463 status = db_find_key(fDB, 0, buf, &hKey);
2464
2465 if (status == DB_SUCCESS) {
2466 // add new tags
2467 KEY key;
2468
2470 assert(status == DB_SUCCESS);
2471
2472 assert(key.type == TID_STRING);
2473
2474 if (key.item_size < kLength && key.num_values == 1) {
2475 // old style tags are present. Convert them to new style!
2476
2477 HNDLE hTags;
2478
2479 cm_msg(MINFO, "add_event", "Converting old event %d (%s) tags to new style", event_id, event_name);
2480
2481 mstrlcpy(buf, event_name, kLength);
2482
2484 assert(status == DB_SUCCESS);
2485
2486 sprintf(buf, "/History/Tags/Tags %d", event_id);
2487
2488 status = db_find_key(fDB, 0, buf, &hTags);
2489
2490 if (status == DB_SUCCESS) {
2491 for (int i=0; ; i++) {
2492 HNDLE h;
2493 int size;
2494 KEY key;
2495 WORD w;
2496
2497 status = db_enum_key(fDB, hTags, i, &h);
2499 break;
2500 assert(status == DB_SUCCESS);
2501
2502 status = db_get_key(fDB, h, &key);
2503
2504 size = sizeof(w);
2505 status = db_get_data(fDB, h, &w, &size, TID_WORD);
2506 assert(status == DB_SUCCESS);
2507
2508 sprintf(buf, "%d[%d] %s", 0, w, key.name);
2509
2511 assert(status == DB_SUCCESS);
2512 }
2513
2515 assert(status == DB_SUCCESS);
2516 }
2517
2518 // format conversion has changed the key, get it again
2520 assert(status == DB_SUCCESS);
2521 }
2522
2523 if (1) {
2524 // add new tags
2525
2526 int size = key.item_size * key.num_values;
2527 int num = key.num_values;
2528
2529 char* s = (char*)malloc(size);
2530 assert(s != NULL);
2531
2532 TAG* t = (TAG*)malloc(sizeof(TAG)*(key.num_values + ntags));
2533 assert(t != NULL);
2534
2535 status = db_get_data(fDB, hKey, s, &size, TID_STRING);
2536 assert(status == DB_SUCCESS);
2537
2538 for (int i=1; i<key.num_values; i++) {
2539 char* ss = s + i*key.item_size;
2540
2541 t[i].type = 0;
2542 t[i].n_data = 0;
2543 t[i].name[0] = 0;
2544
2545 if (isdigit(ss[0])) {
2546 //sscanf(ss, "%d[%d] %s", &t[i].type, &t[i].n_data, t[i].name);
2547
2548 t[i].type = strtoul(ss, &ss, 0);
2549 assert(*ss == '[');
2550 ss++;
2551 t[i].n_data = strtoul(ss, &ss, 0);
2552 assert(*ss == ']');
2553 ss++;
2554 assert(*ss == ' ');
2555 ss++;
2556 mstrlcpy(t[i].name, ss, sizeof(t[i].name));
2557
2558 //printf("type %d, n_data %d, name [%s]\n", t[i].type, t[i].n_data, t[i].name);
2559 }
2560 }
2561
2562 for (int i=0; i<ntags; i++) {
2563 int k = 0;
2564
2565 for (int j=1; j<key.num_values; j++) {
2566 if (equal_ustring((char*)tags[i].name, (char*)t[j].name)) {
2567 if ((tags[i].type!=t[j].type) || (tags[i].n_data!=t[j].n_data)) {
2568 cm_msg(MINFO, "add_event", "Event %d (%s) tag \"%s\" type and size changed from %d[%d] to %d[%d]",
2569 event_id, event_name,
2570 tags[i].name,
2571 t[j].type, t[j].n_data,
2572 tags[i].type, tags[i].n_data);
2573 k = j;
2574 break;
2575 }
2576
2577 k = -1;
2578 break;
2579 }
2580 }
2581
2582 // if tag not present, k==0, so append it to the array
2583
2584 if (k==0)
2585 k = num;
2586
2587 if (k > 0) {
2588 sprintf(buf, "%d[%d] %s", tags[i].type, tags[i].n_data, tags[i].name);
2589
2591 assert(status == DB_SUCCESS);
2592
2593 if (k >= num)
2594 num = k+1;
2595 }
2596 }
2597
2598 free(s);
2599 free(t);
2600 }
2601
2602 } else if (status == DB_NO_KEY) {
2603 // create new array of tags
2604 status = db_create_key(fDB, 0, buf, TID_STRING);
2605 assert(status == DB_SUCCESS);
2606
2607 status = db_find_key(fDB, 0, buf, &hKey);
2608 assert(status == DB_SUCCESS);
2609
2610 mstrlcpy(buf, event_name, kLength);
2611
2613 assert(status == DB_SUCCESS);
2614
2615 for (int i=0; i<ntags; i++) {
2616 sprintf(buf, "%d[%d] %s", tags[i].type, tags[i].n_data, tags[i].name);
2617
2619 assert(status == DB_SUCCESS);
2620 }
2621 } else {
2622 cm_msg(MERROR, "add_event", "Error: db_find_key(%s) status %d", buf, status);
2623 return HS_FILE_ERROR;
2624 }
2625 }
2626
2627 return HS_SUCCESS;
2628 }
2629
2630 /*------------------------------------------------------------------*/
2631
2632 int hs_define_event(const char* event_name, time_t timestamp, int ntags, const TAG tags[])
2633 {
2634 int event_id = FindEventId(event_name);
2635 if (event_id < 0)
2636 event_id = AllocateEventId(event_name);
2637 if (event_id < 0)
2638 return HS_FILE_ERROR;
2639 fEvidCache[event_name] = event_id;
2640 CreateOdbTags(event_id, event_name, ntags, tags);
2641 return ::hs_define_event(event_id, (char*)event_name, (TAG*)tags, ntags*sizeof(TAG));
2642 }
2643
2644 /*------------------------------------------------------------------*/
2645
2646 int hs_write_event(const char* event_name, time_t timestamp, int data_size, const char* data)
2647 {
2648 int event_id = fEvidCache[event_name];
2649 //printf("write event [%s] evid %d\n", event_name, event_id);
2650 return ::hs_write_event(event_id, (void*)data, data_size);
2651 }
2652
2653 /*------------------------------------------------------------------*/
2654
2656 {
2657 //printf("hs_flush_buffers!\n");
2658 return HS_SUCCESS;
2659 }
2660
2661 /*------------------------------------------------------------------*/
2662
2663 int GetEventsFromOdbEvents(std::vector<std::string> *events)
2664 {
2666 int status;
2667
2668 status = db_find_key(fDB, 0, "/History/Events", &hKeyRoot);
2669 if (status != DB_SUCCESS) {
2670 return HS_FILE_ERROR;
2671 }
2672
2673 /* loop over tags to display event names */
2674 for (int i = 0;; i++) {
2675 HNDLE hKeyEq;
2676 char *s;
2677 char evname[1024+NAME_LENGTH];
2678 int size;
2679
2681 if (status != DB_SUCCESS)
2682 break;
2683
2684 size = sizeof(evname);
2686 assert(status == DB_SUCCESS);
2687
2688 s = strchr(evname,':');
2689 if (s)
2690 *s = '/';
2691
2692 /* skip duplicated event names */
2693
2694 int found = 0;
2695 for (unsigned i=0; i<events->size(); i++) {
2696 if (equal_ustring(evname, (*events)[i].c_str())) {
2697 found = 1;
2698 break;
2699 }
2700 }
2701
2702 if (found)
2703 continue;
2704
2705 events->push_back(evname);
2706
2707 //printf("event \'%s\'\n", evname);
2708 }
2709
2710 return HS_SUCCESS;
2711 }
2712
2713 int GetEventsFromOdbTags(std::vector<std::string> *events)
2714 {
2716 int status;
2717
2718 status = db_find_key(fDB, 0, "/History/Tags", &hKeyRoot);
2719 if (status != DB_SUCCESS) {
2720 return HS_FILE_ERROR;
2721 }
2722
2723 /* loop over tags to display event names */
2724 for (int i = 0;; i++) {
2725 HNDLE hKeyEq;
2726 KEY key;
2727 char *s;
2728 WORD event_id;
2729 char evname[1024+NAME_LENGTH];
2730 int size;
2731
2733 if (status != DB_SUCCESS)
2734 break;
2735
2736 /* get event name */
2738
2739 //printf("key \'%s\'\n", key.name);
2740
2741 if (key.type != TID_STRING)
2742 continue;
2743
2744 /* parse event name in format: "event_id" or "event_id:var_name" */
2745 s = key.name;
2746
2747 event_id = (WORD)strtoul(s,&s,0);
2748 if (event_id == 0)
2749 continue;
2750 if (s[0] != 0)
2751 continue;
2752
2753 size = sizeof(evname);
2755 assert(status == DB_SUCCESS);
2756
2757 /* skip duplicated event names */
2758
2759 int found = 0;
2760 for (unsigned i=0; i<events->size(); i++) {
2761 if (equal_ustring(evname, (*events)[i].c_str())) {
2762 found = 1;
2763 break;
2764 }
2765 }
2766
2767 if (found)
2768 continue;
2769
2770 events->push_back(evname);
2771
2772 //printf("event %d \'%s\'\n", event_id, evname);
2773 }
2774
2775 return HS_SUCCESS;
2776 }
2777
2778 int hs_get_events(time_t t, std::vector<std::string> *pevents)
2779 {
2780 assert(pevents);
2781 pevents->clear();
2782
2783 if (fEventsCache.size() == 0) {
2784 int status;
2785
2786 if (fDebug)
2787 printf("hs_get_events: reading events list!\n");
2788
2790
2791 if (status != HS_SUCCESS)
2793
2794 if (status != HS_SUCCESS)
2795 return status;
2796 }
2797
2798 for (unsigned i=0; i<fEventsCache.size(); i++)
2799 pevents->push_back(fEventsCache[i]);
2800
2801 return HS_SUCCESS;
2802 }
2803
2804 int GetEventIdFromHS(time_t ltime, const char* evname, const char* tagname)
2805 {
2807 int status;
2808
2809 status = db_find_key(fDB, 0, "/History/Events", &hKeyRoot);
2810 if (status != DB_SUCCESS) {
2811 return -1;
2812 }
2813
2814 for (int i = 0;; i++) {
2815 HNDLE hKey;
2816 KEY key;
2817 int evid;
2818 char buf[256];
2819 int size;
2820 char *s;
2821 int ntags = 0;
2822 TAG* tags = NULL;
2823 char event_name[NAME_LENGTH];
2824
2826 if (status != DB_SUCCESS)
2827 break;
2828
2830 assert(status == DB_SUCCESS);
2831
2832 if (!isdigit(key.name[0]))
2833 continue;
2834
2835 evid = atoi(key.name);
2836
2837 assert(key.item_size < (int)sizeof(buf));
2838
2839 size = sizeof(buf);
2840 status = db_get_data(fDB, hKey, buf, &size, TID_STRING);
2841 assert(status == DB_SUCCESS);
2842
2843 mstrlcpy(event_name, buf, sizeof(event_name));
2844
2845 s = strchr(buf,':');
2846 if (s)
2847 *s = 0;
2848
2849 //printf("Found event %d, event [%s] name [%s], looking for [%s][%s]\n", evid, event_name, buf, evname, tagname);
2850
2851 if (!equal_ustring((char *)evname, buf))
2852 continue;
2853
2854 status = ::hs_get_tags((DWORD)ltime, evid, event_name, &ntags, &tags);
2855
2856 for (int j=0; j<ntags; j++) {
2857 //printf("at %d [%s] looking for [%s]\n", j, tags[j].name, tagname);
2858
2859 if (equal_ustring((char *)tagname, tags[j].name)) {
2860 if (tags)
2861 free(tags);
2862 return evid;
2863 }
2864 }
2865
2866 if (tags)
2867 free(tags);
2868 tags = NULL;
2869 }
2870
2871 return -1;
2872 }
2873
2874 int GetEventIdFromOdbTags(const char* evname, const char* tagname)
2875 {
2877 int status;
2878
2879 status = db_find_key(fDB, 0, "/History/Tags", &hKeyRoot);
2880 if (status != DB_SUCCESS) {
2881 return -1;
2882 }
2883
2884 for (int i = 0;; i++) {
2885 HNDLE hKey;
2886 KEY key;
2887 int evid;
2888 char buf[256];
2889 int size;
2890 char *s;
2891
2893 if (status != DB_SUCCESS)
2894 break;
2895
2897 assert(status == DB_SUCCESS);
2898
2899 if (key.type != TID_STRING)
2900 continue;
2901
2902 if (!isdigit(key.name[0]))
2903 continue;
2904
2905 evid = atoi(key.name);
2906
2907 assert(key.item_size < (int)sizeof(buf));
2908
2909 size = sizeof(buf);
2910 status = db_get_data_index(fDB, hKey, buf, &size, 0, TID_STRING);
2911 assert(status == DB_SUCCESS);
2912
2913 s = strchr(buf,'/');
2914 if (s)
2915 *s = 0;
2916
2917 //printf("Found event %d, name [%s], looking for [%s][%s]\n", evid, buf, evname, tagname);
2918
2919 if (!equal_ustring((char *)evname, buf))
2920 continue;
2921
2922 for (int j=1; j<key.num_values; j++) {
2923 size = sizeof(buf);
2924 status = db_get_data_index(fDB, hKey, buf, &size, j, TID_STRING);
2925 assert(status == DB_SUCCESS);
2926
2927 if (!isdigit(buf[0]))
2928 continue;
2929
2930 s = strchr(buf,' ');
2931 if (!s)
2932 continue;
2933
2934 s++;
2935
2936 //printf("at %d [%s] [%s] compare to [%s]\n", j, buf, s, tagname);
2937
2938 if (equal_ustring((char *)tagname, s)) {
2939 //printf("Found evid %d\n", evid);
2940 return evid;
2941 }
2942 }
2943 }
2944
2945 return -1;
2946 }
2947
2948 int GetEventId(time_t t, const char* event_name, const char* tag_name, int *pevid)
2949 {
2950 int event_id = -1;
2951
2952 if (fDebug && event_name != NULL && tag_name != NULL)
2953 printf("xhs_event_id for event [%s], tag [%s]\n", event_name, tag_name);
2954
2955 *pevid = 0;
2956
2957 /* use "/History/Tags" if available */
2958 event_id = GetEventIdFromOdbTags(event_name, tag_name);
2959
2960 /* if no Tags, use "/History/Events" and hs_get_tags() to read definition from history files */
2961 if (event_id < 0)
2962 event_id = GetEventIdFromHS(t, event_name, tag_name);
2963
2964 /* if nothing works, use hs_get_event_id() */
2965 if (event_id <= 0) {
2966 DWORD evid = 0;
2967 int status = ::hs_get_event_id((DWORD)t, (char*)event_name, &evid);
2968 if (status != HS_SUCCESS)
2969 return status;
2970 event_id = evid;
2971 }
2972
2973 if (event_id < 0)
2974 return HS_UNDEFINED_VAR;
2975
2976 *pevid = event_id;
2977
2978 return HS_SUCCESS;
2979 }
2980
2981 int GetTagsFromHS(const char* event_name, std::vector<TAG> *ptags)
2982 {
2983 time_t now = time(NULL);
2984 int evid;
2985 int status = GetEventId(now, event_name, NULL, &evid);
2986 if (status != HS_SUCCESS)
2987 return status;
2988
2989 if (fDebug)
2990 printf("hs_get_tags: get tags for event [%s] %d\n", event_name, evid);
2991
2992 int ntags;
2993 TAG* tags;
2994 status = ::hs_get_tags((DWORD)now, evid, (char*)event_name, &ntags, &tags);
2995
2996 if (status != HS_SUCCESS)
2997 return status;
2998
2999 for (int i=0; i<ntags; i++)
3000 ptags->push_back(tags[i]);
3001
3002 if (tags)
3003 free(tags);
3004
3005 if (fDebug)
3006 printf("hs_get_tags: get tags for event [%s] %d, found %d tags\n", event_name, evid, ntags);
3007
3008 return HS_SUCCESS;
3009 }
3010
3011 int GetTagsFromOdb(const char* event_name, std::vector<TAG> *ptags)
3012 {
3014 int status;
3015
3016 status = db_find_key(fDB, 0, "/History/Tags", &hKeyRoot);
3017 if (status != DB_SUCCESS) {
3018 return HS_FILE_ERROR;
3019 }
3020
3021 /* loop over equipment to display event name */
3022 for (int i = 0;; i++) {
3023 HNDLE hKey;
3024 KEY key;
3025 WORD event_id;
3026 char buf[256];
3027 int size;
3028 char* s;
3029
3031 if (status != DB_SUCCESS)
3032 break;
3033
3034 /* get event name */
3036 assert(status == DB_SUCCESS);
3037
3038 /* parse event id */
3039 if (!isdigit(key.name[0]))
3040 continue;
3041
3042 event_id = atoi(key.name);
3043 if (event_id == 0)
3044 continue;
3045
3046 if (key.item_size >= (int)sizeof(buf))
3047 continue;
3048
3049 if (key.num_values == 1) { // old format of "/History/Tags"
3050
3051 HNDLE hKeyDir;
3052 sprintf(buf, "Tags %d", event_id);
3054 if (status != DB_SUCCESS)
3055 continue;
3056
3057 /* loop over tags */
3058 for (int j=0; ; j++) {
3059 HNDLE hKey;
3060 WORD array;
3061 int size;
3062 char var_name[NAME_LENGTH];
3063
3065 if (status != DB_SUCCESS)
3066 break;
3067
3068 /* get event name */
3070 assert(status == DB_SUCCESS);
3071
3072 array = 1;
3073 size = sizeof(array);
3074 status = db_get_data(fDB, hKey, &array, &size, TID_WORD);
3075 assert(status == DB_SUCCESS);
3076
3077 mstrlcpy(var_name, key.name, sizeof(var_name));
3078
3079 //printf("Found %s, event %d (%s), tag (%s) array %d\n", key.name, event_id, event_name, var_name, array);
3080
3081 TAG t;
3082 mstrlcpy(t.name, var_name, sizeof(t.name));
3083 t.n_data = array;
3084 t.type = 0;
3085
3086 ptags->push_back(t);
3087 }
3088
3089 continue;
3090 }
3091
3092 if (key.type != TID_STRING)
3093 continue;
3094
3095 size = sizeof(buf);
3096 status = db_get_data_index(fDB, hKey, buf, &size, 0, TID_STRING);
3097 assert(status == DB_SUCCESS);
3098
3099 if (strchr(event_name, '/')==NULL) {
3100 char* s = strchr(buf, '/');
3101 if (s)
3102 *s = 0;
3103 }
3104
3105 //printf("evid %d, name [%s]\n", event_id, buf);
3106
3107 if (!equal_ustring(buf, event_name))
3108 continue;
3109
3110 /* loop over tags */
3111 for (int j=1; j<key.num_values; j++) {
3112 int array;
3113 int size;
3114 char var_name[NAME_LENGTH];
3115 int ev_type;
3116
3117 size = sizeof(buf);
3118 status = db_get_data_index(fDB, hKey, buf, &size, j, TID_STRING);
3119 assert(status == DB_SUCCESS);
3120
3121 //printf("index %d [%s]\n", j, buf);
3122
3123 if (!isdigit(buf[0]))
3124 continue;
3125
3126 sscanf(buf, "%d[%d]", &ev_type, &array);
3127
3128 s = strchr(buf, ' ');
3129 if (!s)
3130 continue;
3131 s++;
3132
3133 mstrlcpy(var_name, s, sizeof(var_name));
3134
3135 TAG t;
3136 mstrlcpy(t.name, var_name, sizeof(t.name));
3137 t.n_data = array;
3138 t.type = ev_type;
3139
3140 //printf("Found %s, event %d, tag (%s) array %d, type %d\n", buf, event_id, var_name, array, ev_type);
3141
3142 ptags->push_back(t);
3143 }
3144 }
3145
3146 return HS_SUCCESS;
3147 }
3148
3149 /*------------------------------------------------------------------*/
3150
3151 int hs_get_tags(const char* event_name, time_t t, std::vector<TAG> *ptags)
3152 {
3153 std::vector<TAG>& ttt = fTagsCache[event_name];
3154
3155 if (ttt.size() == 0) {
3156 int status = HS_FILE_ERROR;
3157
3158 if (fDebug)
3159 printf("hs_get_tags: reading tags for event [%s]\n", event_name);
3160
3161 status = GetTagsFromOdb(event_name, &ttt);
3162
3163 if (status != HS_SUCCESS)
3164 status = GetTagsFromHS(event_name, &ttt);
3165
3166 if (status != HS_SUCCESS)
3167 return status;
3168 }
3169
3170 for (unsigned i=0; i<ttt.size(); i++)
3171 ptags->push_back(ttt[i]);
3172
3173 return HS_SUCCESS;
3174 }
3175
3176 /*------------------------------------------------------------------*/
3177
3178 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[])
3179 {
3180 for (int i=0; i<num_var; i++)
3181 last_written[i] = 0;
3182 return HS_FILE_ERROR;
3183 }
3184
3185 /*------------------------------------------------------------------*/
3186
3187
3188 int hs_read(time_t start_time, time_t end_time, time_t interval,
3189 int num_var,
3190 const char* const event_name[], const char* const tag_name[], const int var_index[],
3191 int num_entries[],
3192 time_t* time_buffer[], double* data_buffer[],
3193 int read_status[])
3194 {
3195 DWORD* tbuffer = NULL;
3196 char* ybuffer = NULL;
3197 DWORD bsize, tsize;
3198 int hbuffer_size = 0;
3199
3200 if (hbuffer_size == 0) {
3201 hbuffer_size = 1000 * sizeof(DWORD);
3203 ybuffer = (char*)malloc(hbuffer_size);
3204 }
3205
3206 for (int i=0; i<num_var; i++) {
3207 DWORD tid = 0;
3208 int event_id = 0;
3209
3210 if (event_name[i]==NULL) {
3212 num_entries[i] = 0;
3213 continue;
3214 }
3215
3216 int status = GetEventId(end_time, event_name[i], tag_name[i], &event_id);
3217
3218 if (status != HS_SUCCESS) {
3219 read_status[i] = status;
3220 continue;
3221 }
3222
3223 DWORD n_point = 0;
3224
3225 do {
3227 memset(ybuffer, 0, bsize);
3228 status = ::hs_read(event_id, (DWORD)start_time, (DWORD)end_time, (DWORD)interval,
3229 tag_name[i], var_index[i],
3230 tbuffer, &tsize,
3231 ybuffer, &bsize,
3232 &tid, &n_point,
3233 NULL);
3234
3235 if (fDebug)
3236 printf("hs_read %d \'%s\' [%d] returned %d, %d entries\n", event_id, tag_name[i], var_index[i], status, n_point);
3237
3238 if (status == HS_TRUNCATED) {
3239 hbuffer_size *= 2;
3241 assert(tbuffer);
3243 assert(ybuffer);
3244 }
3245
3246 } while (status == HS_TRUNCATED);
3247
3248 read_status[i] = status;
3249
3250 time_t* x = (time_t*)malloc(n_point*sizeof(time_t));
3251 assert(x);
3252 double* y = (double*)malloc(n_point*sizeof(double));
3253 assert(y);
3254
3255 time_buffer[i] = x;
3256 data_buffer[i] = y;
3257
3258 int n_vp = 0;
3259
3260 for (unsigned j = 0; j < n_point; j++) {
3261 x[n_vp] = tbuffer[j];
3262
3263 /* convert data to float */
3264 switch (tid) {
3265 default:
3266 y[n_vp] = 0;
3267 break;
3268 case TID_BYTE:
3269 y[n_vp] = *(((BYTE *) ybuffer) + j);
3270 break;
3271 case TID_SBYTE:
3272 y[n_vp] = *(((char *) ybuffer) + j);
3273 break;
3274 case TID_CHAR:
3275 y[n_vp] = *(((char *) ybuffer) + j);
3276 break;
3277 case TID_WORD:
3278 y[n_vp] = *(((WORD *) ybuffer) + j);
3279 break;
3280 case TID_SHORT:
3281 y[n_vp] = *(((short *) ybuffer) + j);
3282 break;
3283 case TID_DWORD:
3284 y[n_vp] = *(((DWORD *) ybuffer) + j);
3285 break;
3286 case TID_INT:
3287 y[n_vp] = *(((INT *) ybuffer) + j);
3288 break;
3289 case TID_BOOL:
3290 y[n_vp] = *(((BOOL *) ybuffer) + j);
3291 break;
3292 case TID_FLOAT:
3293 y[n_vp] = *(((float *) ybuffer) + j);
3294 break;
3295 case TID_DOUBLE:
3296 y[n_vp] = *(((double *) ybuffer) + j);
3297 break;
3298 }
3299
3300 n_vp++;
3301 }
3302
3303 num_entries[i] = n_vp;
3304 }
3305
3306 if (ybuffer)
3307 free(ybuffer);
3308 if (tbuffer)
3309 free(tbuffer);
3310
3311 return HS_SUCCESS;
3312 }
3313
3314 /*------------------------------------------------------------------*/
3315#if 0
3316 int hs_read2(time_t start_time, time_t end_time, time_t interval,
3317 int num_var,
3318 const char* const event_name[], const char* const tag_name[], const int var_index[],
3319 int num_entries[],
3321 double* mean_buffer[],
3322 double* rms_buffer[],
3323 double* min_buffer[],
3324 double* max_buffer[],
3325 int read_status[])
3326 {
3327 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);
3328
3329 for (int i=0; i<num_var; i++) {
3330 int num = num_entries[i];
3331 rms_buffer[i] = (double*)malloc(sizeof(double)*num);
3332 min_buffer[i] = (double*)malloc(sizeof(double)*num);
3333 max_buffer[i] = (double*)malloc(sizeof(double)*num);
3334
3335 for (int j=0; j<num; j++) {
3336 rms_buffer[i][j] = 0;
3337 min_buffer[i][j] = mean_buffer[i][j];
3338 max_buffer[i][j] = mean_buffer[i][j];
3339 }
3340 }
3341
3342 return status;
3343 }
3344#endif
3345
3346 int hs_read_buffer(time_t start_time, time_t end_time,
3347 int num_var, const char* const event_name[], const char* const tag_name[], const int var_index[],
3349 int read_status[])
3350 {
3351 for (int i=0; i<num_var; i++) {
3352 int event_id = 0;
3353
3354 if (event_name[i]==NULL) {
3356 continue;
3357 }
3358
3359 int status = GetEventId(end_time, event_name[i], tag_name[i], &event_id);
3360
3361 if (status != HS_SUCCESS) {
3362 read_status[i] = status;
3363 continue;
3364 }
3365
3366 status = ::hs_read(event_id, (DWORD)start_time, (DWORD)end_time, 0,
3367 tag_name[i], var_index[i],
3368 NULL, NULL,
3369 NULL, NULL,
3370 NULL, NULL,
3371 buffer[i]);
3372
3373 if (fDebug) {
3374 printf("hs_read %d \'%s\' [%d] returned %d\n", event_id, tag_name[i], var_index[i], status);
3375 }
3376
3377 read_status[i] = status;
3378 }
3379
3380 return HS_SUCCESS;
3381 }
3382
3383 int hs_read_binned(time_t start_time, time_t end_time, int num_bins,
3384 int num_var, const char* const event_name[], const char* const tag_name[], const int var_index[],
3385 int num_entries[],
3386 int* count_bins[], double* mean_bins[], double* rms_bins[], double* min_bins[], double* max_bins[],
3389 time_t last_time[], double last_value[],
3390 int read_status[])
3391 {
3392 int status;
3393
3396
3397 for (int i=0; i<num_var; i++) {
3398 buffer[i] = new MidasHistoryBinnedBuffer(start_time, end_time, num_bins);
3399 xbuffer[i] = buffer[i];
3400
3401 if (count_bins)
3402 buffer[i]->fCount = count_bins[i];
3403 if (mean_bins)
3404 buffer[i]->fMean = mean_bins[i];
3405 if (rms_bins)
3406 buffer[i]->fRms = rms_bins[i];
3407 if (min_bins)
3408 buffer[i]->fMin = min_bins[i];
3409 if (max_bins)
3410 buffer[i]->fMax = max_bins[i];
3411 if (bins_first_time)
3412 buffer[i]->fBinsFirstTime = bins_first_time[i];
3413 if (bins_first_value)
3414 buffer[i]->fBinsFirstValue = bins_first_value[i];
3415 if (bins_last_time)
3416 buffer[i]->fBinsLastTime = bins_last_time[i];
3417 if (bins_last_value)
3418 buffer[i]->fBinsLastValue = bins_last_value[i];
3419 if (last_time)
3420 buffer[i]->fLastTimePtr = &last_time[i];
3421 if (last_value)
3422 buffer[i]->fLastValuePtr = &last_value[i];
3423
3424 buffer[i]->Start();
3425 }
3426
3427 status = hs_read_buffer(start_time, end_time,
3428 num_var, event_name, tag_name, var_index,
3429 xbuffer,
3430 read_status);
3431
3432 for (int i=0; i<num_var; i++) {
3433 buffer[i]->Finish();
3434 if (num_entries)
3435 num_entries[i] = buffer[i]->fNumEntries;
3436 //if (0) {
3437 // for (int j=0; j<num_bins; j++) {
3438 // 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]);
3439 // }
3440 //}
3441 delete buffer[i];
3442 }
3443
3444 delete[] buffer;
3445 delete[] xbuffer;
3446
3447 return status;
3448 }
3449
3450}; // end class
3451
3452
3453/********************************************************************/
3462/********************************************************************/
3463
3464#define HISTORY_PANEL(_name) const char *_name[] = {\
3465"[.]",\
3466"Variables = STRING : [64] :",\
3467"Timescale = STRING : [32] 10m",\
3468"Zero ylow = BOOL : n",\
3469"Show run markers = BOOL : y",\
3470"Buttons = STRING[7] :",\
3471"[32] 10m",\
3472"[32] 1h",\
3473"[32] 3h",\
3474"[32] 12h",\
3475"[32] 24h",\
3476"[32] 3d",\
3477"[32] 7d",\
3478"Log axis = BOOL : n",\
3479"Show values = BOOL : y",\
3480"Sort vars = BOOL : n",\
3481"Show old vars = BOOL : n",\
3482"Minimum = FLOAT : -inf",\
3483"Maximum = FLOAT : inf",\
3484"Label = STRING : [32] ",\
3485"Colour = STRING : [32] ",\
3486"Formula = STRING : [64] ",\
3487"Show fill = BOOL : y",\
3488"",\
3489NULL }
3490
3491
3492INT hs_define_panel(const char *group, const char *panel, const std::vector<std::string> var)
3493{
3494 HNDLE hDB, hKey, hKeyVar;
3496 char str[256];
3497
3498 const char *color[] = {
3499 "#00AAFF", "#FF9000", "#FF00A0", "#00C030",
3500 "#A0C0D0", "#D0A060", "#C04010", "#807060",
3501 "#F0C000", "#2090A0", "#D040D0", "#90B000",
3502 "#B0B040", "#B0B0FF", "#FFA0A0", "#A0FFA0",
3503 "#808080"};
3504
3506
3507 snprintf(str, sizeof(str), "/History/Display/%s/%s", group, panel);
3508
3510 db_find_key(hDB, 0, str, &hKey);
3511 if (!hKey)
3512 return DB_NO_MEMORY;
3513
3514 int i=0;
3515 for(auto const& v: var) {
3516 db_find_key(hDB, hKey, "Variables", &hKeyVar);
3517 db_set_data_index(hDB, hKeyVar, v.c_str(), 64, i, TID_STRING);
3518
3519 str[0] = 0;
3520 db_set_value_index(hDB, hKey, "Formula", str, 64, i, TID_STRING, false);
3521 db_set_value_index(hDB, hKey, "Label", str, 32, i, TID_STRING, false);
3522 db_set_value_index(hDB, hKey, "Colour", color[i < 16 ? i : 16], 32, i, TID_STRING, false);
3523
3524 i++;
3525 }
3526
3527 return HS_SUCCESS;
3528}
3529
3530INT hs_define_panel2(const char *group, const char *panel, const std::vector<std::string> var,
3531 const std::vector<std::string> label, const std::vector<std::string> formula,
3532 const std::vector<std::string> color)
3533{
3534 HNDLE hDB, hKey, hKeyVar;
3536 char str[256];
3537
3538 const char *default_color[] = {
3539 "#00AAFF", "#FF9000", "#FF00A0", "#00C030",
3540 "#A0C0D0", "#D0A060", "#C04010", "#807060",
3541 "#F0C000", "#2090A0", "#D040D0", "#90B000",
3542 "#B0B040", "#B0B0FF", "#FFA0A0", "#A0FFA0",
3543 "#808080"};
3544
3546
3547 snprintf(str, sizeof(str), "/History/Display/%s/%s", group, panel);
3548
3550 db_find_key(hDB, 0, str, &hKey);
3551 if (!hKey)
3552 return DB_NO_MEMORY;
3553
3554 int i=0;
3555 for(auto const& v: var) {
3556 db_find_key(hDB, hKey, "Variables", &hKeyVar);
3557 db_set_data_index(hDB, hKeyVar, v.c_str(), 64, i, TID_STRING);
3558
3559 if (i < (int)formula.size())
3560 mstrlcpy(str, formula[i].c_str(), sizeof(str)-1);
3561 else
3562 str[0] = 0;
3563 db_set_value_index(hDB, hKey, "Formula", str, 64, i, TID_STRING, false);
3564
3565 if (i < (int)label.size())
3566 mstrlcpy(str, label[i].c_str(), sizeof(str)-1);
3567 else
3568 str[0] = 0;
3569 db_set_value_index(hDB, hKey, "Label", str, 32, i, TID_STRING, false);
3570
3571 if (i < (int)color.size())
3572 mstrlcpy(str, color[i].c_str(), sizeof(str)-1);
3573 else
3574 mstrlcpy(str, default_color[i < 16 ? i : 16], sizeof(str)-1);
3575 db_set_value_index(hDB, hKey, "Colour", str, 32, i, TID_STRING, false);
3576
3577 i++;
3578 }
3579
3580 return HS_SUCCESS;
3581}
3582
3584{
3585#if 0
3586 // midas history is a singleton class
3587 static MidasHistory* gh = NULL;
3588 if (!gh)
3589 gh = new MidasHistory;
3590 return gh;
3591#endif
3592 return new MidasHistory();
3593}
3594
3595/* emacs
3596 * Local Variables:
3597 * tab-width: 8
3598 * c-basic-offset: 3
3599 * indent-tabs-mode: nil
3600 * End:
3601 */
#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:3011
INT cm_get_experiment_semaphore(INT *semaphore_alarm, INT *semaphore_elog, INT *semaphore_history, INT *semaphore_msg)
Definition midas.cxx:3033
#define DB_SUCCESS
Definition midas.h:631
#define DB_NO_MEMORY
Definition midas.h:633
#define DB_NO_KEY
Definition midas.h:642
#define DB_NO_MORE_SUBKEYS
Definition midas.h:646
#define SS_SUCCESS
Definition midas.h:663
#define HS_UNDEFINED_VAR
Definition midas.h:733
#define HS_SUCCESS
Definition midas.h:727
#define HS_FILE_ERROR
Definition midas.h:728
#define HS_TRUNCATED
Definition midas.h:730
#define HS_NO_MEMORY
Definition midas.h:729
#define HS_WRONG_INDEX
Definition midas.h:731
#define HS_UNDEFINED_EVENT
Definition midas.h:732
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:2713
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:3583
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:2632
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:2655
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:3178
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:2263
int GetEventId(time_t t, const char *event_name, const char *tag_name, int *pevid)
Definition history.cxx:2948
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:3346
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:2646
int GetTagsFromOdb(const char *event_name, std::vector< TAG > *ptags)
Definition history.cxx:3011
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:2271
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:3383
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:3530
INT hs_define_panel(const char *group, const char *panel, const std::vector< std::string > var)
Definition history.cxx:3492
int FindEventId(const char *event_name)
Definition history.cxx:2291
int GetEventsFromOdbEvents(std::vector< std::string > *events)
Definition history.cxx:2663
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:2981
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:3151
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:2778
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:3464
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:2278
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:2339
int CreateOdbTags(int event_id, const char *event_name, int ntags, const TAG tags[])
Definition history.cxx:2404
int GetEventIdFromHS(time_t ltime, const char *evname, const char *tagname)
Definition history.cxx:2804
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:3188
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:2874
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:219
time_t ss_mktime(struct tm *tms)
Definition system.cxx:3365
void ss_tzset()
Definition system.cxx:3355
INT ss_semaphore_release(HNDLE semaphore_handle)
Definition system.cxx:2781
DWORD ss_time()
Definition system.cxx:3462
INT ss_semaphore_wait_for(HNDLE semaphore_handle, DWORD timeout_millisec)
Definition system.cxx:2639
INT cm_msg(INT message_type, const char *filename, INT line, const char *routine, const char *format,...)
Definition midas.cxx:915
BOOL equal_ustring(const char *str1, const char *str2)
Definition odb.cxx:3201
INT db_get_data_index(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT idx, DWORD type)
Definition odb.cxx:6893
INT db_delete_key(HNDLE hDB, HNDLE hKey, BOOL follow_links)
Definition odb.cxx:3856
INT db_get_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, void *data, INT *buf_size, DWORD type, BOOL create)
Definition odb.cxx:5415
std::string strcomb1(const char **list)
Definition odb.cxx:598
INT db_get_data(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, DWORD type)
Definition odb.cxx:6539
INT db_create_key(HNDLE hDB, HNDLE hKey, const char *key_name, DWORD type)
Definition odb.cxx:3308
INT db_get_key(HNDLE hDB, HNDLE hKey, KEY *key)
Definition odb.cxx:6019
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:13934
INT db_set_data_index(HNDLE hDB, HNDLE hKey, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:7648
INT db_set_data(HNDLE hDB, HNDLE hKey, const void *data, INT buf_size, INT num_values, DWORD type)
Definition odb.cxx:7215
INT db_sprintf(char *string, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:10843
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:5261
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition odb.cxx:4079
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:5365
INT db_enum_key(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition odb.cxx:5586
INT db_create_record(HNDLE hDB, HNDLE hKey, const char *orig_key_name, const char *init_str)
Definition odb.cxx:12800
bool rpc_is_remote(void)
Definition midas.cxx:12761
INT rpc_tid_size(INT id)
Definition midas.cxx:11757
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:410
#define DIR_SEPARATOR
Definition midas.h:193
INT HNDLE
Definition midas.h:132
#define M_MALLOC(x)
Definition midas.h:1552
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:1358
#define M_FREE(x)
Definition midas.h:1554
#define RT_DATA
Definition midas.h:1357
#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
TH1X EXPRT * h1_book(const char *name, const char *title, int bins, double min, double max)
Definition rmidas.h:24
Definition midas.h:1026
INT num_values
Definition midas.h:1028
DWORD type
Definition midas.h:1027
char name[NAME_LENGTH]
Definition midas.h:1029
INT item_size
Definition midas.h:1032
Definition midas.h:1234
DWORD type
Definition midas.h:1236
DWORD n_data
Definition midas.h:1237
char name[NAME_LENGTH]
Definition midas.h:1235