HIPO  4.3.0
High Performance Output data format for experimental physics
writer.cpp
Go to the documentation of this file.
1 //******************************************************************************
2 //* ██╗ ██╗██╗██████╗ ██████╗ ██╗ ██╗ ██████╗ *
3 //* ██║ ██║██║██╔══██╗██╔═══██╗ ██║ ██║ ██╔═████╗ *
4 //* ███████║██║██████╔╝██║ ██║ ███████║ ██║██╔██║ *
5 //* ██╔══██║██║██╔═══╝ ██║ ██║ ╚════██║ ████╔╝██║ *
6 //* ██║ ██║██║██║ ╚██████╔╝ ██║██╗╚██████╔╝ *
7 //* ╚═╝ ╚═╝╚═╝╚═╝ ╚═════╝ ╚═╝╚═╝ ╚═════╝ *
8 //************************ Jefferson National Lab (2017) ***********************
9 /*
10  * Copyright (c) 2017. Jefferson Lab (JLab). All rights reserved. Permission
11  * to use, copy, modify, and distribute this software and its documentation
12  * for educational, research, and not-for-profit purposes, without fee and
13  * without a signed licensing agreement.
14  *
15  * IN NO EVENT SHALL JLAB BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL
16  * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
17  * OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JLAB HAS
18  * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19  *
20  * JLAB SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE. THE HIPO DATA FORMAT SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF
23  * ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". JLAB HAS NO OBLIGATION TO
24  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25  *
26  * This software was developed under the United States Government license.
27  * For more information contact author at gavalian@jlab.org
28  * Department of Experimental Nuclear Physics, Jefferson Lab.
29  */
30 
35 #include "writer.h"
36 #include "constants.h"
37 #include <cstdlib>
38 
39 namespace hipo {
40 
45  void writer::open(const char *filename){
46  outputStream.open(filename);
47 
48  std::vector<std::string> schemaList = writerDictionary.getSchemaList();
49 
50  recordbuilder builder;
51  event schemaEvent;
52 
53  for(int i = 0; i < schemaList.size(); i++){
54  std::string schemaString = writerDictionary.getSchema(schemaList[i].c_str()).getSchemaString();
55  std::string schemaStringJson = writerDictionary.getSchema(schemaList[i].c_str()).getSchemaStringJson();
56  //---> Can open after debug level is introduced in the class
57  //printf("STR : %s\n",schemaString.c_str());
58  //printf("JSON : %s\n",schemaStringJson.c_str());
59  schemaEvent.reset();
60  structure schemaNode(DICT_GROUP,DICT_ITEM,schemaString);
61  structure schemaNodeJson(DICT_GROUP,DICT_JSON_ITEM,schemaStringJson);
62  schemaEvent.addStructure(schemaNodeJson);
63  schemaEvent.addStructure(schemaNode);
64  //schemaEvent.show();
65  builder.addEvent(schemaEvent);
66  }
67 
68  //-------------------------------------------------------------------------
69  // This section is added on April-28-2022, it will store user provided
70  // configurations along with the schema in the record that goes into
71  // HIPO header. G^2
72  //-------------------------------------------------------------------------
73  std::map<std::string,std::string>::iterator it;
74  event configEvent;
75 
76  for( it = userConfig.begin(); it != userConfig.end(); it++){
77  printf("::: adding user configuration (key): %s\n",it->first.c_str());
78 
79  std::string wKey = std::string(it->first.c_str());
80  std::string wConfig = std::string(it->second.c_str());
81 
82  structure configKey(CONFIG_GROUP,CONFIG_KEY_ITEM,wKey);
83  structure configString(CONFIG_GROUP,CONFIG_STRING_ITEM,wConfig);
84 
85  configEvent.reset();
86  configEvent.addStructure(configKey);
87  configEvent.addStructure(configString);
88  builder.addEvent(configEvent);
89  }
90 
91  //printf(" RECORD SIZE BEFORE BUILD = %d\n",builder.getRecordSize());
92  builder.build();
93  //printf(" RECORD SIZE AFTER BUILD = %d, NENTRIES = %d\n",
94  // builder.getRecordSize(),builder.getEntries());
95 
96  int dictionarySize = builder.getRecordSize();
97 
98  hipoFileHeader_t header;
99 
100  //header.uniqueid = 0x43455248;
102  header.filenumber = 1;
104  header.recordCount = 0;
105  header.indexArrayLength = 0;
107  header.userHeaderLength = dictionarySize;// will change with the dictionary
108  header.magicNumber = HEADER_MAGIC;
109  header.userRegister = 0;
110  header.trailerPosition = 0;
111  header.userIntegerOne = 0;
112  header.userIntegerTwo = 0;
113 
114  outputStream.write( reinterpret_cast<char *> (&header),sizeof(header));
115  long position = outputStream.tellp();
116 
117  printf("writing header:: position = %ld\n",position);
118  outputStream.write( reinterpret_cast<char *> (&builder.getRecordBuffer()[0]),dictionarySize);
119  position = outputStream.tellp();
120  printf("writing dictionary:: position = %ld\n",position);
121  }
122 
124  std::vector<std::string> schemaList = dict.getSchemaList();
125  for(int i = 0; i < schemaList.size(); i++){
126  writerDictionary.addSchema(dict.getSchema(schemaList[i].c_str()));
127  }
128 }
129 
131  if(hevent.getTag()==0){
132  bool status = recordBuilder.addEvent(hevent);
133  if(status==false){
134  writeRecord(recordBuilder);
135  recordBuilder.addEvent(hevent);
136  }
137  } else {
138  int tag = hevent.getTag();
139  extendedBuilder[tag].setUserWordOne(tag);
140  bool status = extendedBuilder[tag].addEvent(hevent);
141  if(status==false){
142  writeRecord(extendedBuilder[tag]);
143  extendedBuilder[tag].addEvent(hevent);
144  }
145  }
146  }
147 
148 void writer::addEvent(std::vector<char> &vec, int size ){
149  int transferSize = size;
150  if(size<0){ transferSize = vec.size(); }
151  bool status = recordBuilder.addEvent(vec,0,transferSize);
152  if(status==false){
153  writeRecord(recordBuilder);
154  recordBuilder.addEvent(vec,0,transferSize);
155  }
156 }
157 
159  builder.build();
160  recordInfo_t recordInfo;
161  recordInfo.recordPosition = outputStream.tellp();
162  recordInfo.recordEntries = builder.getEntries();
163  recordInfo.recordLength = builder.getRecordSize();
164  recordInfo.userWordOne = builder.getUserWordOne();
165  recordInfo.userWordTwo = builder.getUserWordTwo();
166  if(recordInfo.recordEntries>0){
167  outputStream.write( reinterpret_cast<char *> (&builder.getRecordBuffer()[0]),recordInfo.recordLength);
168  writerRecordInfo.push_back(recordInfo);
169  if(verbose>0) printf("%6ld : writing::record : size = %8d, entries = %8d, position = %12ld word = %12ld %12ld\n",
170  writerRecordInfo.size(), recordInfo.recordLength,recordInfo.recordEntries,
171  recordInfo.recordPosition,recordInfo.userWordOne,recordInfo.userWordTwo);
172  } else {
173  if(verbose>0) printf(" write::record : empty record will not be written.....\n");
174  }
175  builder.reset();
176  }
177 
179  for(int loop = 0; loop < writerRecordInfo.size(); loop++){
180  recordInfo_t recordInfo = writerRecordInfo[loop];
181  printf(" %6d : record INFO : size = %8d, entries = %8d, position = %12ld word = %12ld %12ld\n", loop,
182  recordInfo.recordLength,recordInfo.recordEntries,recordInfo.recordPosition,
183  recordInfo.userWordOne,recordInfo.userWordTwo);
184  }
185 }
186 
187 
188 void writer::writeIndexTable(){
189  hipo::schema indexSchema("file::index",FILE_INDEX_GROUP,FILE_INDEX_ITEM);
190  indexSchema.parse("position/L,length/I,entries/I,userWordOne/L,userWordTwo/L");
191  int nEntries = writerRecordInfo.size();
192  long indexPosition = outputStream.tellp();
193  printf("\n\n-----> writing file index : entries = %d, position = %ld\n",
194  nEntries,indexPosition);
195  hipo::bank indexBank(indexSchema,nEntries);
196  for(int i = 0; i < nEntries; i++){
197  recordInfo_t recordInfo = writerRecordInfo[i];
198  indexBank.putLong("position",i,recordInfo.recordPosition);
199  indexBank.putInt("length",i,recordInfo.recordLength);
200  indexBank.putInt("entries",i,recordInfo.recordEntries);
201  indexBank.putLong("userWordOne",i,recordInfo.userWordOne);
202  indexBank.putLong("userWordTwo",i,recordInfo.userWordTwo);
203  }
204 
205  int eventSize = 32*nEntries + 1024;
206 
207  hipo::event indexEvent(eventSize);
208  indexEvent.addStructure(indexBank);
209  recordBuilder.reset();
210  recordBuilder.addEvent(indexEvent);
211  writeRecord(recordBuilder);
212  outputStream.seekp(FH_TRAILER_POS_OFFSET);
213  outputStream.write(reinterpret_cast<char *> (&indexPosition), 8);
214 }
215 
217  writeRecord(recordBuilder);
218 
219  std::map<int,hipo::recordbuilder>::iterator it;
220  for(it = extendedBuilder.begin(); it != extendedBuilder.end(); it++){
221  writeRecord(it->second);
222  }
223 
224  writeIndexTable();
225  outputStream.close();
226  writerRecordInfo.clear();
227 }
228 
229 /***
230 * Function to change the record builder user word one
231 */
232 void writer::setUserIntegerOne(long userIntOne){
233  recordBuilder.setUserWordOne(userIntOne);
234 }
235 
236 /***
237 *Function to change the record builder user word two
238 */
239 void writer::setUserIntegerTwo(long userIntTwo){
240  recordBuilder.setUserWordTwo(userIntTwo);
241 }
242 
243 /***
244 *Function to write buffer.
245 */
247  writeRecord(recordBuilder);
248 }
249 
250 }
Represents a HIPO bank, a tabular data structure with rows and typed columns.
Definition: bank.h:352
Collection of schema definitions, typically read from a HIPO file header.
Definition: dictionary.h:248
void addSchema(schema sc)
Add a schema to the dictionary.
Definition: dictionary.h:260
std::vector< std::string > getSchemaList()
Get a list of all schema names in the dictionary.
Definition: dictionary.cpp:121
schema & getSchema(const char *name)
Retrieve a schema by name.
Definition: dictionary.h:271
Represents a HIPO event, a container for multiple structures/banks.
Definition: event.h:77
int getTag()
Definition: event.cpp:223
Builds HIPO records by accumulating events and compressing them.
Definition: recordbuilder.h:45
void build()
Compresses accumulated events and builds the final record.
void setUserWordOne(long userWordOne)
Sets the first user-defined word in the record header.
std::vector< char > & getRecordBuffer()
Returns a reference to the internal record buffer.
int getRecordSize()
Returns the total size of the built record in bytes.
void reset()
Resets the builder, clearing all accumulated events.
long getUserWordTwo()
Returns the second user-defined word stored in the record header.
void setUserWordTwo(long userWordTwo)
Sets the second user-defined word in the record header.
long getUserWordOne()
Returns the first user-defined word stored in the record header.
bool addEvent(std::vector< char > &vec, int start, int length)
Adds an event from a raw byte vector.
int getEntries()
Returns the number of events currently in the record.
Schema definition for a HIPO bank.
Definition: dictionary.h:73
std::string getSchemaString()
Serialize the schema to a definition string (e.g. "pid/I,px/F").
Definition: dictionary.cpp:86
std::string getSchemaStringJson()
Serialize the schema to a JSON-formatted string.
Definition: dictionary.cpp:100
Low-level data structure representing a HIPO structure.
Definition: bank.h:64
void open(const char *filename)
Open a file for writing.
Definition: writer.cpp:45
void writeRecord(recordbuilder &builder)
Write a completed record to the output file.
Definition: writer.cpp:158
void flush()
Flush the current record buffer to disk.
Definition: writer.cpp:246
void setUserIntegerTwo(long userIntTwo)
Set the second user-defined integer in the file header.
Definition: writer.cpp:239
void setUserIntegerOne(long userIntOne)
Set the first user-defined integer in the file header.
Definition: writer.cpp:232
void addDictionary(hipo::dictionary &dict)
Set the dictionary to be written into the file header.
Definition: writer.cpp:123
void addEvent(hipo::event &hevent)
Add an event to the current record buffer.
Definition: writer.cpp:130
void showSummary()
Print a summary of records written to stdout.
Definition: writer.cpp:178
void close()
Close the file, flushing remaining events and writing the trailer.
Definition: writer.cpp:216
Definition: bank.cpp:47
constexpr uint32_t HIPO_FILE_UNIQUE_WORD
Definition: constants.h:7
constexpr int FILE_INDEX_ITEM
Definition: constants.h:61
constexpr int FILE_HEADER_WORDS
Definition: constants.h:12
constexpr int DICT_GROUP
Definition: constants.h:54
constexpr int CONFIG_GROUP
Definition: constants.h:57
constexpr int CONFIG_KEY_ITEM
Definition: constants.h:58
constexpr uint32_t HEADER_MAGIC
Definition: constants.h:8
constexpr int FILE_INDEX_GROUP
Definition: constants.h:60
constexpr int DICT_JSON_ITEM
Definition: constants.h:56
constexpr uint32_t BITINFO_VERSION_MASK
Definition: constants.h:104
constexpr int FH_TRAILER_POS_OFFSET
Definition: constants.h:29
constexpr int HIPO_VERSION
Definition: constants.h:132
constexpr int DICT_ITEM
Definition: constants.h:55
constexpr int CONFIG_STRING_ITEM
Definition: constants.h:59
HIPO file header structure used by the writer.
Definition: writer.h:122
int userHeaderLength
User header length in bytes.
Definition: writer.h:129
int userIntegerTwo
Second user-defined integer.
Definition: writer.h:134
int userIntegerOne
First user-defined integer.
Definition: writer.h:133
int magicNumber
Magic number for endianness (0xc0da0100)
Definition: writer.h:130
long trailerPosition
File offset to trailer.
Definition: writer.h:132
int bitInfoVersion
Bit info and version packed word.
Definition: writer.h:128
int indexArrayLength
Index array length in bytes.
Definition: writer.h:127
int uniqueid
File format identifier.
Definition: writer.h:123
int recordCount
Number of records written.
Definition: writer.h:126
long userRegister
User-defined register.
Definition: writer.h:131
int filenumber
Split file number.
Definition: writer.h:124
int headerLength
Header length in words (usually 14)
Definition: writer.h:125
Metadata for a single record in a HIPO file.
Definition: reader.h:146
long userWordOne
First user-defined word.
Definition: reader.h:150
long userWordTwo
Second user-defined word.
Definition: reader.h:151
int recordLength
Total record length in bytes.
Definition: reader.h:148
long recordPosition
Byte position of the record in the file.
Definition: reader.h:147
int recordEntries
Number of events in the record.
Definition: reader.h:149
HIPO file writer for creating HIPO output files.