00001 #ifndef artdaq_core_Data_ContainerFragment_hh
00002 #define artdaq_core_Data_ContainerFragment_hh
00003
00004 #include "artdaq-core/Data/Fragment.hh"
00005 #include "cetlib_except/exception.h"
00006
00007
00008
00009
00010
00011
00012 namespace artdaq
00013 {
00014 class ContainerFragment;
00015 }
00016
00020 class artdaq::ContainerFragment
00021 {
00022 public:
00023
00024 static constexpr uint8_t CURRENT_VERSION = 1;
00025 static constexpr size_t CONTAINER_MAGIC = 0x00BADDEED5B1BEE5;
00026
00030 struct MetadataV0
00031 {
00035 static constexpr int CONTAINER_FRAGMENT_COUNT_MAX = 100;
00036
00037 typedef uint8_t data_t;
00038 typedef uint64_t count_t;
00039
00040 count_t block_count : 55;
00041 count_t fragment_type : 8;
00042 count_t missing_data : 1;
00043
00045 size_t index[CONTAINER_FRAGMENT_COUNT_MAX];
00046
00048 static size_t const size_words = 8ul + CONTAINER_FRAGMENT_COUNT_MAX * sizeof(size_t) / sizeof(data_t);
00049 };
00050 static_assert (sizeof(MetadataV0) == MetadataV0::size_words * sizeof(MetadataV0::data_t), "ContainerFragment::MetadataV0 size changed");
00051
00055 struct Metadata
00056 {
00057 typedef uint8_t data_t;
00058 typedef uint64_t count_t;
00059
00060 count_t block_count : 16;
00061 count_t fragment_type : 8;
00062 count_t version : 4;
00063 count_t missing_data : 1;
00064 count_t has_index : 1;
00065 count_t unused_flag1 : 1;
00066 count_t unused_flag2 : 1;
00067 count_t unused : 32;
00068
00069 uint64_t index_offset;
00070
00072 static size_t const size_words = 16ul;
00073 };
00074 static_assert (sizeof(Metadata) == Metadata::size_words * sizeof(Metadata::data_t), "ContainerFragment::Metadata size changed");
00075
00076 Metadata const* UpgradeMetadata(MetadataV0 const* in) const
00077 {
00078 TLOG(TLVL_DEBUG, "ContainerFragment") << "Upgrading ContainerFragment::MetadataV0 into new ContainerFragment::Metadata";
00079 assert(in->block_count < std::numeric_limits<Metadata::count_t>::max());
00080 metadata_alloc_ = true;
00081 Metadata md;
00082 md.block_count = in->block_count;
00083 md.fragment_type = in->fragment_type;
00084 md.has_index = 0;
00085 md.missing_data = in->missing_data;
00086 md.version = 0;
00087 index_ptr_ = in->index;
00088 metadata_ = new Metadata(md);
00089 return metadata_;
00090 }
00091
00098 explicit ContainerFragment(Fragment const& f) : artdaq_Fragment_(f), index_ptr_(nullptr), index_alloc_(false),metadata_(nullptr), metadata_alloc_(false) { }
00099
00100 virtual ~ContainerFragment()
00101 {
00102 if (index_alloc_)
00103 {
00104 delete[] index_ptr_;
00105 }
00106 if (metadata_alloc_)
00107 {
00108 delete metadata_;
00109 }
00110 }
00111
00116 Metadata const* metadata() const
00117 {
00118 if (metadata_alloc_) return metadata_;
00119
00120 if (artdaq_Fragment_.sizeBytes() - artdaq_Fragment_.dataSizeBytes() - sizeof(detail::RawFragmentHeader) == sizeof(MetadataV0))
00121 {
00122 return UpgradeMetadata(artdaq_Fragment_.metadata<MetadataV0>());
00123 }
00124
00125 return artdaq_Fragment_.metadata<Metadata>();
00126 }
00127
00132 Metadata::count_t block_count() const { return metadata()->block_count; }
00137 Fragment::type_t fragment_type() const { return static_cast<Fragment::type_t>(metadata()->fragment_type); }
00142 bool missing_data() const { return static_cast<bool>(metadata()->missing_data); }
00143
00148 void const* dataBegin() const
00149 {
00150 return reinterpret_cast<void const *>(&*artdaq_Fragment_.dataBegin());
00151 }
00152
00157 void const* dataEnd() const
00158 {
00159 return reinterpret_cast<void const *>(reinterpret_cast<uint8_t const *>(dataBegin()) + lastFragmentIndex());
00160 }
00161
00168 FragmentPtr at(size_t index) const
00169 {
00170 if (index >= block_count() || block_count() == 0)
00171 {
00172 throw cet::exception("ArgumentOutOfRange") << "Buffer overrun detected! ContainerFragment::at was asked for a non-existent Fragment!";
00173 }
00174 FragmentPtr frag(new Fragment(fragSize(index) / sizeof(RawDataType) - detail::RawFragmentHeader::num_words()));
00175 memcpy(frag->headerAddress(), reinterpret_cast<uint8_t const *>(dataBegin()) + fragmentIndex(index), fragSize(index));
00176 return frag;
00177 }
00178
00185 size_t fragSize(size_t index) const
00186 {
00187 if (index >= block_count() || block_count() == 0)
00188 {
00189 throw cet::exception("ArgumentOutOfRange") << "Buffer overrun detected! ContainerFragment::fragSize was asked for a non-existent Fragment!";
00190 }
00191 auto end = fragmentIndex(index + 1);
00192 if (index == 0) return end;
00193 return end - fragmentIndex(index);
00194 }
00195
00202 FragmentPtr operator[](size_t index) const
00203 {
00204 return this->at(index);
00205 }
00206
00213 size_t fragmentIndex(size_t index) const
00214 {
00215 if (index > block_count())
00216 {
00217 throw cet::exception("ArgumentOutOfRange") << "Buffer overrun detected! ContainerFragment::fragmentIndex was asked for a non-existent Fragment!";
00218 }
00219 if (index == 0) { return 0; }
00220
00221 auto index_ptr = get_index_();
00222
00223 return index_ptr[index - 1];
00224 }
00225
00230 size_t lastFragmentIndex() const
00231 {
00232 return fragmentIndex(block_count());
00233 }
00234
00235 protected:
00236
00241 static constexpr size_t words_per_frag_word_()
00242 {
00243 return sizeof(Fragment::value_type) / sizeof(Metadata::data_t);
00244 }
00245
00246 const size_t* create_index_() const
00247 {
00248 TLOG(TLVL_TRACE, "ContainerFragment") << "Creating new index for ContainerFragment";
00249 auto tmp = new size_t[metadata()->block_count + 1];
00250
00251 auto current = reinterpret_cast<uint8_t const*>(artdaq_Fragment_.dataBegin());
00252 size_t offset = 0;
00253 for (int ii = 0; ii < metadata()->block_count; ++ii)
00254 {
00255 auto this_size = reinterpret_cast<const detail::RawFragmentHeader*>(current)->word_count * sizeof(RawDataType);
00256 offset += this_size;
00257 tmp[ii] = offset;
00258 current += this_size;
00259 }
00260 tmp[metadata()->block_count] = CONTAINER_MAGIC;
00261 return tmp;
00262 }
00263
00264 void reset_index_ptr_() const
00265 {
00266 TLOG(TLVL_TRACE, "ContainerFragment") << "Request to reset index_ptr recieved. has_index=" << metadata()->has_index << ", Check word = " << std::hex
00267 << *(reinterpret_cast<size_t const*>(artdaq_Fragment_.dataBeginBytes() + metadata()->index_offset) + metadata()->block_count);
00268 if (metadata()->has_index && *(reinterpret_cast<size_t const*>(artdaq_Fragment_.dataBeginBytes() + metadata()->index_offset) + metadata()->block_count) == CONTAINER_MAGIC)
00269 {
00270 TLOG(TLVL_TRACE, "ContainerFragment") << "Setting index_ptr to found valid index";
00271 index_ptr_ = reinterpret_cast<size_t const*>(artdaq_Fragment_.dataBeginBytes() + metadata()->index_offset);
00272 }
00273 else
00274 {
00275 TLOG(TLVL_TRACE, "ContainerFragment") << "Index invalid or not found, allocating new index";
00276 if (index_alloc_)
00277 {
00278 delete[] index_ptr_;
00279 }
00280
00281 index_alloc_ = true;
00282 index_ptr_ = create_index_();
00283 }
00284 }
00285
00286 const size_t* get_index_() const
00287 {
00288 if (index_ptr_ != nullptr) return index_ptr_;
00289
00290 reset_index_ptr_();
00291
00292 return index_ptr_;
00293 }
00294
00295 private:
00296 Fragment const& artdaq_Fragment_;
00297
00298 mutable const size_t* index_ptr_;
00299 mutable bool index_alloc_;
00300 mutable const Metadata* metadata_;
00301 mutable bool metadata_alloc_;
00302 };
00303
00304 #endif