The Sparta Modeling Framework
Loading...
Searching...
No Matches
DeltaCheckpoint.hpp
1// <DeltaCheckpoint.hpp> -*- C++ -*-
2
3#pragma once
4
5#include <iostream>
6#include <sstream>
7#include <stack>
8
10#include "sparta/functional/ArchData.hpp"
14
15#include "sparta/serialization/checkpoint/Checkpointer.hpp"
17
18
19namespace sparta::serialization::checkpoint
20{
21 namespace storage
22 {
27 {
28 class Segment{
30 std::unique_ptr<char []> data_;
31 uint32_t bytes_;
32 public:
33
37 Segment(const Segment&) = delete;
38
42 Segment(Segment&& rhp) :
43 idx_(rhp.idx_),
44 data_(std::move(rhp.data_)),
45 bytes_(rhp.bytes_)
46 {
48 rhp.bytes_ = 0;
49 }
50
54 Segment() :
56 bytes_(0)
57 {;}
58
62 Segment& operator=(const Segment& rhp) = delete;
63
67 Segment(ArchData::line_idx_type idx, const char* data, size_t bytes) :
68 idx_(idx), bytes_(bytes)
69 {
71 "Attempted to create segment of " << bytes << " bytes with invalid line index");
72 data_.reset(new char[bytes]);
73 ::memcpy(data_.get(), data, bytes);
74 }
75
76 ArchData::line_idx_type getLineIdx() const {
77 return idx_;
78 }
79
80 uint32_t getSize() const {
81 return sizeof(decltype(*this)) + bytes_;
82 }
83
84 void copyTo(char* buf, uint32_t size) const {
85 sparta_assert(size == bytes_, \
86 "Attempted to restore checkpoint data for a line where the "
87 "data was " << bytes_ << " bytes but the loader requested "
88 << size << " bytes. The sizes must match up or something is "
89 "wrong");
90 memcpy(buf, data_.get(), bytes_);
91 }
92
93 void dump(std::ostream& o) const {
95 std::cout << "\nEnd of ArchData";
96 return;
97 }
98
99 std::cout << "\nLine: " << std::dec << idx_ << " (" << bytes_ << ") bytes";
100 for(uint32_t off = 0; off < bytes_;){
101 char chr = data_[off];
102 if(off % 32 == 0){
103 o << std::endl << std::setw(7) << std::hex << off;
104 }
105 if(chr == 0){
106 o << ' ' << "..";
107 }else{
108 o << ' ' << std::setfill('0') << std::setw(2) << std::hex << (0xff & (uint16_t)chr);
109 }
110 off++;
111 }
112 }
113 };
114
118 std::vector<Segment> data_;
119
124
128 uint32_t next_restore_idx_ = 0;
129
134 decltype(data_)::const_iterator cur_restore_itr_;
135
136 public:
137 VectorStorage() {
138 }
139
141 }
142
143 void dump(std::ostream& o) const {
144 for(auto const &seg : data_){
145 seg.dump(o);
146 }
147 }
148
149 uint32_t getSize() const {
150 uint32_t bytes = sizeof(decltype(*this));
151 for(Segment const & seg : data_){
152 bytes += seg.getSize();
153 }
154 return bytes;
155 }
156
157 void prepareForLoad() {
158 next_restore_idx_ = 0;
159 cur_restore_itr_ = data_.begin();
160 }
161
162 void beginLine(ArchData::line_idx_type idx) {
164 "Cannot begin line with INVALID_LINE_IDX index");
165 next_idx_ = idx;
166 }
167
168 void writeLineBytes(const char* data, size_t size) {
169 sparta_assert(data_.size() == 0 || data_.back().getLineIdx() != next_idx_,
170 "Cannot store the same line idx twice in a checkpoint. Line "
171 << next_idx_ << " detected twice in a row");
173 "Cannot write line bytes with INVALID_LINE_IDX index");
174 data_.emplace_back(next_idx_, data, size);
175 }
176
180 void endArchData() {
181 data_.emplace_back();
182 }
183
188 bool good() const {
189 return next_restore_idx_ <= data_.size(); // Not past end of stream
190 }
191
197 if(next_restore_idx_ == data_.size()){
198 next_restore_idx_++; // Increment to detect errors
199 return ArchData::INVALID_LINE_IDX; // Done with restore
200 }else if(next_restore_idx_ > data_.size()){ // Past the end
201 throw SpartaException("Failed to restore a checkpoint because ")
202 << "caller tried to keep getting next line even after "
203 "reaching the end of the restore data";
204 }
205 if(next_restore_idx_ != 0){
206 cur_restore_itr_++;
207 }
208 next_restore_idx_++;
209
210 const auto next_line_idx = cur_restore_itr_->getLineIdx(); // May be invalid to indicate end of ArchData
211 return next_line_idx;
212 };
213
217 void copyLineBytes(char* buf, uint32_t size) {
218 sparta_assert(cur_restore_itr_ != data_.end(),
219 "Attempted to copy line bytes from an invalid line iterator");
220 sparta_assert(cur_restore_itr_->getLineIdx() != ArchData::INVALID_LINE_IDX,
221 "About to return line from checkpoint data segment with INVALID_LINE_IDX index");
222 cur_restore_itr_->copyTo(buf, size);
223 }
224
230 //void stealLineBytes(char*& buf_ptr, uint32_t size) {
231 // cur_restore_itr_->stealBuffer(buf_ptr, size);
232 //}
233 };
234
241 {
242 std::stringstream ss_;
243
244 public:
246 ss_.exceptions(std::ostream::eofbit | std::ostream::badbit |
247 std::ostream::failbit | std::ostream::goodbit);
248 }
249
250 void dump(std::ostream& o) const {
251 auto s = ss_.str();
252 auto itr = s.begin();
253 for(; itr != s.end(); itr++){
254 char chr = *itr;
255 if(chr == 'L'){
256 uint32_t off = 0;
258 strncpy((char*)&ln_idx, s.substr(itr-s.begin(), sizeof(ln_idx)).c_str(), sizeof(ln_idx));
259 std::cout << "\nLine: " << ln_idx << std::endl;
260 itr += sizeof(ArchData::line_idx_type);
261
262 for(uint16_t i=0; i<64; ++i){
263 chr = *itr;
264 if(off % 32 == 0){
265 o << std::setw(7) << std::hex << off;
266 }
267 if(chr == 0){
268 o << ' ' << "..";
269 }else{
270 o << ' ' << std::setfill('0') << std::setw(2) << std::hex << (0xff & (uint16_t)chr);
271 }
272 off++;
273 if(off % 32 == 0){
274 o << std::endl;
275 }
276 ++itr;
277 }
278 }
279 }
280 }
281
282 uint32_t getSize() const {
283 return ss_.str().size() + sizeof(decltype(*this));
284 }
285
286 void prepareForLoad() {
287 ss_.seekg(0); // Seek to start with get pointer before consuming
288 }
289
290 void beginLine(ArchData::line_idx_type idx) {
291 ss_ << 'L'; // Line start char
292
293 ArchData::line_idx_type idx_repr = reorder<ArchData::line_idx_type, LE>(idx);
294 ss_.write((char*)&idx_repr, sizeof(ArchData::line_idx_type));
295 }
296
297 void writeLineBytes(const char* data, size_t size) {
298 ss_.write(data, size);
299 }
300
304 void endArchData() {
305 ss_ << "E"; // Indicates end of this checkpoint data
306
307 sparta_assert(ss_.good(),
308 "Ostream error while writing checkpoint data");
309 }
310
315 bool good() const {
316 return ss_.good();
317 }
318
324 char ctrl;
325 ss_ >> ctrl;
326 sparta_assert(ss_.good(),
327 "Encountered checkpoint data stream error or eof");
328 if(ctrl == 'L'){
329 ArchData::line_idx_type ln_idx = 0;
330 ss_.read((char*)&ln_idx, sizeof(ln_idx)); // Presumed LE encoding
331 return ln_idx;
332 }else if(ctrl == 'E'){
333 return ArchData::INVALID_LINE_IDX; // Done with restore
334 }else{
335 throw SpartaException("Failed to restore a checkpoint because a '")
336 << ctrl << "' control character was found where an 'L' or 'E' was found";
337 }
338 };
339
343 void copyLineBytes(char* buf, uint32_t size) {
344 ss_.read(buf, size);
345 }
346 };
347
348 } // namespace storage
349
350 class FastCheckpointer;
351
370 template<typename StorageT=storage::StringStreamStorage>
372 {
373 public:
374
378
380 DeltaCheckpoint() = delete;
381
384
387
388 private:
389
420 const std::vector<ArchData*>& dats,
421 chkpt_id_t id,
422 tick_t tick,
423 DeltaCheckpoint* prev_delta,
424 bool is_snapshot) :
425 Checkpoint(id, tick, prev_delta),
426 deleted_id_(UNIDENTIFIED_CHECKPOINT),
427 is_snapshot_(is_snapshot)
428 {
429 (void) root;
430 if(nullptr == prev_delta){
431 if(is_snapshot == false){
432 throw CheckpointError("Cannot create a DeltaCheckpoint id=")
433 << id << " at tick=" << tick << " which has no prev_delta and is not a snapshot";
434 }
435 }else{
436 prev_delta->addNext(this);
437 }
438
439 // Store the checkpoint from root
440 if(is_snapshot){
441 storeSnapshot_(dats);
442 }else{
443 storeDelta_(dats);
444 }
445 }
446
448 friend class FastCheckpointer;
449
450 public:
451
460 if(!canDelete()){
461 std::cerr << "WARNING: DeltaCheckpoint " << getID()
462 << " being destructed without being allowed to delete" << std::endl;
463 }
464 }
465
468
472 virtual std::string stringize() const override {
473 std::stringstream ss;
474 ss << "<DeltaCheckpoint id=";
475 if(isFlaggedDeleted()){
476 ss << "DELETED";
477 }else{
478 ss << getID();
479 }
480 ss << " at t=" << getTick();
481 if(isSnapshot()){
482 ss << "(snapshot)";
483 }
484 ss << ' ' << getTotalMemoryUse()/1000.0f << "kB (" << getContentMemoryUse()/1000.0f << "kB Data)";
485 ss << '>';
486 return ss.str();
487 }
488
494 virtual void dumpData(std::ostream& o) const override {
495 data_.dump(o);
496 }
497
503 void dumpRestoreChain(std::ostream& o) const {
504 auto rc = getRestoreChain();
505 while(1){
506 const DeltaCheckpoint* cp = rc.top();
507 rc.pop();
508 if(cp->isSnapshot()){
509 o << '(';
510 }
511 if(cp->getID() == UNIDENTIFIED_CHECKPOINT){
512 o << "*" << getDeletedID() << "";
513 }else{
514 o << cp->getID();
515 }
516 if(cp->isSnapshot()){
517 o << ')';
518 }
519 if(rc.empty()){
520 break;
521 }else{
522 o << " --> ";
523 }
524 }
525 }
526
530 virtual uint64_t getTotalMemoryUse() const noexcept override {
531 return getContentMemoryUse() \
532 + sizeof(decltype(*this)) \
533 + (getNexts().size() * sizeof(typename std::remove_reference<decltype(*this)>::type*));
534 }
535
539 virtual uint64_t getContentMemoryUse() const noexcept override {
540 return data_.getSize();
541 }
542
546
550 void traceValue(std::ostream& o, const std::vector<ArchData*>& dats,
551 const ArchData* container, uint32_t offset, uint32_t size)
552 {
553 std::stack<DeltaCheckpoint*> dcps = getHistoryChain();
554
555 std::vector<std::pair<uint8_t,bool>> bytes; // pair<value,valid>
556 bytes.resize(size, decltype(bytes)::value_type(0,false));
557
558 constexpr uint32_t BUF_SIZE = 8192*2;
559 std::unique_ptr<char[]> buf(new char[BUF_SIZE]); // Line-reading buffer
560
561 while(!dcps.empty()){
562 DeltaCheckpoint* d = dcps.top();
563 o << "trace: Checkpoint " << d->getDeletedRepr() << (d->isSnapshot()?" (snapshot)":"") << std::endl;
564 dcps.pop();
565 d->data_.prepareForLoad();
566 bool found_ad = false;
567 bool changed = false;
568 for(ArchData* ad : dats){
569 if(ad == container){
570 found_ad = true;
571 if(d->isSnapshot()){
572 for(auto &x : bytes){
573 x.second = false; // Invalidate result due to snapshot load
574 }
575 }
576 }
577 while(1){
578 auto ln_idx = d->data_.getNextRestoreLine();
579 if(ln_idx == ArchData::INVALID_LINE_IDX){
580 if(ad == container){
581 //if(changed == false){
582 // o << "trace: No data for this value" << std::endl;
583 //}
584 }
585 break; // Done with this ArchData
586 }
587 auto ln_off = ln_idx * ad->getLineSize();
588 sparta_assert(BUF_SIZE > ad->getLineSize(),
589 "Cannot trace value on ArchDatas with line sizes > " << BUF_SIZE << " (" << ad->getLineSize() << ")");
590 d->data_.copyLineBytes((char*)buf.get(), ad->getLineSize()); // Need to read regardless of usefulness of data
591 if(ad == container){
592 //o << "trace: Contains data for line idx " << std::dec << ln_idx
593 // << " offsets [" << ln_off << "," << ln_off+ad->getLineSize() << ")" << std::endl;
594 if(offset >= ln_off && offset < ln_off + ad->getLineSize()){
595 sparta_assert(offset+size < ln_off + ad->getLineSize(),
596 "Cannot trace value which spans multiple lines!");
597 sparta_assert(changed == false,
598 "Value being traced changed twice in the same checkpoint");
599 changed = true;
600 auto off_in_line = offset - ln_off;
601 o << "trace: Value changed (line " << std::dec << ln_idx << ")" << std::endl;
602 for(uint32_t i=0; i<bytes.size(); i++){
603 bytes[i].first = buf.get()[i+off_in_line];
604 bytes[i].second = true; // Valid
605 }
606 }
607 }
608 }
609 }
610 if(!found_ad){
611 o << "trace: Could not find selected ArchData " << (const void*)container << " in this checkpoint!" << std::endl;
612 }
613 o << "trace: Value:";
614 for(uint32_t i=0; i<bytes.size(); i++){
615 if(bytes[i].second){
616 o << ' ' << std::setfill('0') << std::setw(2) << std::hex << (uint16_t)bytes[i].first;
617 }else{
618 o << " xx"; // Invalid
619 }
620 }
621 o << std::endl;
622 }
623 o << std::endl;
624 }
625
633 std::stack<DeltaCheckpoint*> getHistoryChain() {
634 // Build stack up to last snapshot
635 DeltaCheckpoint* n = this;
636 std::stack<DeltaCheckpoint*> dcps;
637 while(n){
638 dcps.push(n);
639 n = static_cast<DeltaCheckpoint*>(n->getPrev());
640 }
641 return dcps;
642 }
643
649 std::stack<DeltaCheckpoint*> getRestoreChain() {
650 // Build stack up to last snapshot
651 DeltaCheckpoint* n = this;
652 std::stack<DeltaCheckpoint*> dcps;
653 while(1){
654 dcps.push(n);
655 if(n->isSnapshot()){
656 break;
657 }
658 n = static_cast<DeltaCheckpoint*>(n->getPrev());
659 }
660 return dcps;
661 }
662
666 std::stack<const DeltaCheckpoint*> getRestoreChain() const {
667 // Build stack up to last snapshot
668 const DeltaCheckpoint* n = this;
669 std::stack<const DeltaCheckpoint*> dcps;
670 while(1){
671 dcps.push(n);
672 if(n->isSnapshot()){
673 break;
674 }
675 n = static_cast<const DeltaCheckpoint*>(n->getPrev());
676 }
677 return dcps;
678 }
679
687 virtual void load(const std::vector<ArchData*>& dats) override {
688 // Build stack up to last snapshot
689 std::stack<DeltaCheckpoint*> dcps = getRestoreChain();
690
691 // Load in proper order
692 while(!dcps.empty()){
693 DeltaCheckpoint* d = dcps.top();
694 dcps.pop();
695 d->loadState(dats);
696 }
697 }
698
707 bool canDelete() const noexcept {
708 if(!isFlaggedDeleted()){
709 return false;
710 }
711 for(auto d : getNexts()){
712 const DeltaCheckpoint* dcp = static_cast<const DeltaCheckpoint*>(d);
713 if(!dcp->canDelete() && !dcp->isSnapshot()){
714 return false;
715 }
716 }
717 return true; // This checkpoint was flagged deleted
718 }
719
731 void flagDeleted() {
733 "Cannot delete a checkpoint when it is already deleted: " << this);
734 deleted_id_ = getID();
736 }
737
745 bool isFlaggedDeleted() const noexcept {
746 return getID() == UNIDENTIFIED_CHECKPOINT;
747 }
748
754 chkpt_id_t getDeletedID() const noexcept {
755 return deleted_id_;
756 }
757
764 virtual std::string getDeletedRepr() const override {
765 std::stringstream ss;
766 if(isFlaggedDeleted()){
767 ss << "*" << getDeletedID();
768 }else{
769 ss << getID();
770 }
771 return ss.str();
772 }
773
777 bool isSnapshot() const noexcept { return is_snapshot_; }
778
789 uint32_t getDistanceToPrevSnapshot() const noexcept {
790 const DeltaCheckpoint* d = this;
791 uint32_t dist = 0;
792 while(d){
793 if(d->isSnapshot()){
794 return dist;
795 }
796 d = static_cast<const DeltaCheckpoint*>(d->getPrev());
797 ++dist;
798 }
799
800 // This will compile just fine....
801#ifdef __clang__
802 // This is known to be needed with Clang 8.0.0; not sure about other versions.
803#pragma clang diagnostic push
804#pragma clang diagnostic ignored "-Wexceptions"
805#elif defined __GNUC__ // Note that clang defines both __clang__ and __GNUC__
806#pragma GCC diagnostic push
807#if __GNUC__ > 5
808 // gcc 4.7 doesn't like this.
809#pragma GCC diagnostic ignored "-Wterminate"
810#endif // __GNUC__ > 5
811#endif // ifdef __clang__ ... elif defined __GNUC__ ...
812
813
814 throw CheckpointError() << "In getDistanceToPrevious, somehow reached null "
815 << "previous-checkpoint without encountering a snapshot. This should "
816 << "never occur and is a critical error";
817#ifdef __clang__
818#pragma clang diagnostic pop
819#elif defined __GNUC__
820#pragma GCC diagnostic pop
821#endif
822
823
824 // But using my macro that injects the pragmas doesn't work... ugh
825 /*
826 TERMINATING_THROW(CheckpointError, "In getDistanceToPrevious, somehow reached null "
827 << "previous-checkpoint without encountering a snapshot. This should "
828 << "never occur and is a critical error");
829 */
830 }
831
834
835 protected:
836
842 void loadState(const std::vector<ArchData*>& dats) {
843 data_.prepareForLoad();
844 sparta_assert(data_.good(),
845 "Attempted to loadState from a DeltaCheckpoint with a bad data buffer");
846 if(isSnapshot()){
847 for(ArchData* ad : dats){
848 //std::cout << "Restoring for ArchData: " << (void*)ad << " " << ad->getOwnerNode()->getLocation() << std::endl;
849 ad->restoreAll(data_);
850 }
851 }else{
852 for(ArchData* ad : dats){
853 //std::cout << "Restoring for ArchData: " << (void*)ad << " " << ad->getOwnerNode()->getLocation() << std::endl;
854 ad->restore(data_);
855 }
856 }
857 }
858
859 private:
860
864
871 void storeSnapshot_(const std::vector<ArchData*>& dats) {
872 sparta_assert(data_.good(),
873 "Attempted to storeSnapshot_ from a DeltaCheckpoint with a bad data buffer");
874 // Cannot have stored already
875 for(ArchData* ad : dats){
876 //std::cout << "SaveAll for ArchData: " << ad->getOwnerNode()->getLocation() << std::endl;
877 ad->saveAll(data_);
878 }
879 }
880
887 void storeDelta_(const std::vector<ArchData*>& dats) {
888 sparta_assert(data_.good(),
889 "Attempted to storeDelta_ from a DeltaCheckpoint with a bad data buffer");
890 // Cannot have stored already
891 for(ArchData* ad : dats){
892 //std::cout << "Save for ArchData: " << ad->getOwnerNode()->getLocation() << std::endl;
893 ad->save(data_);
894 }
895 }
896
899
900
906 chkpt_id_t deleted_id_;
907 bool const is_snapshot_;
908 StorageT data_;
909 };
910
911} // namespace sparta::serialization::checkpoint
File that contains checkpoint exception types.
A simple time-based, event precedence based scheduler.
Set of macros for Sparta assertions. Caught by the framework.
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
Exception class for all of Sparta.
Basic Node framework in sparta device tree composite pattern.
Contains a set of contiguous line of architectural data which can be referred to by any architected o...
Definition ArchData.hpp:39
static const line_idx_type INVALID_LINE_IDX
Invalid line index.
Definition ArchData.hpp:112
offset_type line_idx_type
Represents offsets into this ArchData.
Definition ArchData.hpp:59
Used to construct and throw a standard C++ exception. Inherits from std::exception.
Node in a composite tree representing a sparta Tree item.
Definition TreeNode.hpp:205
Indicates that there was an issue operating on checkpoints within the SPARTA framework.
Single checkpoint object interface with a tick number and an ID unique to the owning Checkpointer ins...
Checkpoint * getPrev() const noexcept
Returns the previous checkpoint. If this checkpoint is a snapshot, it has no previous checkpoint.
const std::vector< Checkpoint * > & getNexts() const noexcept
Returns next checkpoint following *this. May be an empty vector if there are no later checkpoints fol...
chkpt_id_t getID() const noexcept
Returns the ID of this checkpoint.
tick_t getTick() const noexcept
Returns the tick number at which this checkpoint was taken.
sparta::Scheduler::Tick tick_t
tick_t Tick type to which checkpoints will refer
void addNext(Checkpoint *next)
Adds another next checkpoint following *this.
void setID_(chkpt_id_t id)
Sets the checkpoint ID.
uint64_t chkpt_id_t
tick_t Tick type to which checkpoints will refer
static const chkpt_id_t UNIDENTIFIED_CHECKPOINT
Indicates unidentified checkpoint (could mean 'invalid' or 'any') depending on context.
Single delta checkpoint object containing all simulator state which changed since some previous Delta...
chkpt_id_t getDeletedID() const noexcept
Return the ID had by this checkpoint before it was deleted If this checkpoint has not been flagged fo...
virtual void dumpData(std::ostream &o) const override
Writes all checkpoint raw data to an ostream.
DeltaCheckpoint()=delete
Not default constructable.
std::stack< DeltaCheckpoint * > getHistoryChain()
Returns a stack of checkpoints from this checkpoint as far back as possible until no previous link is...
bool isSnapshot() const noexcept
Is this checkpoint a snapshot (contains ALL simulator state)
std::stack< const DeltaCheckpoint * > getRestoreChain() const
Const-qualified version of getRestoreChain.
bool isFlaggedDeleted() const noexcept
Indicates whether this checkpoint has been flagged deleted.
virtual std::string getDeletedRepr() const override
Gets the representation of this deleted checkpoint as part of a checkpoint chain (if that checkpointe...
std::stack< DeltaCheckpoint * > getRestoreChain()
Returns a stack of checkpoints that must be restored from top-to-bottom to fully restore the state as...
virtual void load(const std::vector< ArchData * > &dats) override
Attempts to restore this checkpoint including any previous deltas (dependencies).
bool canDelete() const noexcept
Can this checkpoint be deleted Cannot be deleted if:
void traceValue(std::ostream &o, const std::vector< ArchData * > &dats, const ArchData *container, uint32_t offset, uint32_t size)
Implement trace of a value across the restore chain as described in Checkpointer::traceValue.
void flagDeleted()
Allows this checkpoint to be deleted if it is no longer a previous delta of some other delta (i....
const DeltaCheckpoint & operator=(const DeltaCheckpoint &)=delete
Non-assignable.
void loadState(const std::vector< ArchData * > &dats)
Loads delta state of this checkpoint to root. Does not look at any other checkpoints checkpoints.
DeltaCheckpoint(const DeltaCheckpoint &)=delete
Not copy constructable.
virtual uint64_t getContentMemoryUse() const noexcept override
Returns memory usage by the content of this checkpoint.
virtual uint64_t getTotalMemoryUse() const noexcept override
Returns memory usage by this checkpoint.
virtual std::string stringize() const override
Returns a string describing this object.
uint32_t getDistanceToPrevSnapshot() const noexcept
Determines how many checkpoints away the closest, earlier snapshot is.
void dumpRestoreChain(std::ostream &o) const
Dumps the restore chain for this checkpoint.
Implements quick checkpointing through delta-checkpoint trees which store state-deltas in a compact f...
void copyLineBytes(char *buf, uint32_t size)
Read bytes for the current line.
void endArchData()
Signals end of this checkpoint's data.
bool good() const
Is the reading state of this storage good? (i.e. haven't tried to read past the end of the data)
ArchData::line_idx_type getNextRestoreLine()
Restore next line. Return ArchData::INVALID_LINE_IDX on end of data.
ArchData::line_idx_type getNextRestoreLine()
Restore next line. Return ArchData::INVALID_LINE_IDX on end of data.
void copyLineBytes(char *buf, uint32_t size)
Read bytes for the current line.
bool good() const
Is the reading state of this storage good? (i.e. haven't tried to read past the end of the data)
void endArchData()
Signals end of this checkpoint's data for one ArchData.