//---------------------------------------------------------------- // IElement::save // IStorage::IReceiptPtr IElement::save(IStorage & storage, uint64 vsizeBytesToUse) const { if (fixedSize_) { return savePaddedUpToSize(storage, fixedSize_); } if (!mustSave()) { return storage.receipt(); } unsigned char v[8]; uint64 elementIdSize = uintNumBytes(getId()); uintEncode(getId(), v, elementIdSize); receipt_ = storage.save(v, (std::size_t)elementIdSize); if (!receipt_) { return receipt_; } // shortcut: const IPayload & payload = getPayload(); // NOTE: due to VEltPosition the payload size is not actually // known until the payload is written, however we know the // payload size upper limit. Once the payload is saved it's // exact size will have to be saved again: uint64 payloadSize = payload.calcSize(); // must account for CRC-32 element as well: if (shouldComputeCrc32()) { payloadSize += uintNumBytes(kIdCrc32) + vsizeNumBytes(4) + 4; } // if necessary calculate number of bytes used to store the payload size: if (!vsizeBytesToUse) { vsizeBytesToUse = vsizeNumBytes(payloadSize); } vsizeEncode(payloadSize, v, vsizeBytesToUse); IStorage::IReceiptPtr payloadSizeReceipt = storage.save(v, (std::size_t)vsizeBytesToUse); *receipt_ += payloadSizeReceipt; // save payload receipt: offsetToPayload_ = elementIdSize + vsizeBytesToUse; offsetToCrc32_ = kUndefinedOffset; // save CRC-32 element placeholder: if (shouldComputeCrc32()) { IStorage::IReceiptPtr receiptCrc32 = storage.receipt(); TByteVec bytes; bytes << uintEncode(kIdCrc32) << vsizeEncode(4) << uintEncode(0, 4); receiptCrc32 = Yamka::save(storage, bytes); if (!receiptCrc32) { return receiptCrc32; } *receipt_ += receiptCrc32; offsetToCrc32_ = offsetToPayload_; } // save the payload: IStorage::IReceiptPtr receiptPayload = payload.save(storage); if (!receiptPayload) { return receiptPayload; } *receipt_ += receiptPayload; uint64 payloadBytesSaved = receipt_->numBytes() - offsetToPayload_; assert(payloadBytesSaved <= payloadSize); if (payloadBytesSaved < payloadSize) { // save exact payload size: vsizeEncode(payloadBytesSaved, v, vsizeBytesToUse); payloadSizeReceipt->save(v, (std::size_t)vsizeBytesToUse); } // save attached Void elements: typedef std::list<IPayload::TVoid>::const_iterator TVoidIter; for (TVoidIter i = payload.voids_.begin(); i != payload.voids_.end(); ++i) { const IPayload::TVoid & eltVoid = *i; IStorage::IReceiptPtr voidReceipt = eltVoid.save(storage); *receipt_ += voidReceipt; } return receipt_; }
//---------------------------------------------------------------- // IElement::savePaddedUpToSize // IStorage::IReceiptPtr IElement::savePaddedUpToSize(IStorage & storage, uint64 paddedSize) const { // shortcut: const IPayload & payload = getPayload(); const bool payloadSizeUnknown = (paddedSize == uintMax[8]); uint64 elementIdSize = uintNumBytes(getId()); uint64 payloadSize = payload.calcSize(); uint64 vsizeBytesToUse = vsizeNumBytes(payloadSize); // make sure the paddedSize is big enough to store the payload: uint64 elementSize = elementIdSize + vsizeBytesToUse + payloadSize; if (!payloadSizeUnknown && elementSize != paddedSize && elementSize + kMinVoidEltSize > paddedSize) { return IStorage::IReceiptPtr(); } // save element id: unsigned char v[8]; uintEncode(getId(), v, elementIdSize); receipt_ = storage.save(v, (std::size_t)elementIdSize); if (!receipt_) { return receipt_; } // save payload size: IStorage::IReceiptPtr payloadSizeReceipt; if (payloadSizeUnknown) { vsizeEncode(vsizeUnknown[8], v, 8); payloadSizeReceipt = storage.save(v, 8); } else { vsizeEncode(payloadSize, v, vsizeBytesToUse); payloadSizeReceipt = storage.save(v, (std::size_t)vsizeBytesToUse); } *receipt_ += payloadSizeReceipt; // save payload receipt: offsetToPayload_ = storage.receipt()->position() - receipt_->position(); offsetToCrc32_ = kUndefinedOffset; // save the payload: IStorage::IReceiptPtr payloadReceipt = payload.save(storage); if (!payloadReceipt) { return payloadReceipt; } *receipt_ += payloadReceipt; if (payloadSizeUnknown) { // done: return receipt_; } uint64 payloadBytesSaved = payloadReceipt->numBytes(); assert(payloadBytesSaved <= payloadSize); if (payloadBytesSaved < payloadSize) { // save exact payload size: vsizeEncode(payloadBytesSaved, v, vsizeBytesToUse); payloadSizeReceipt->save(v, (std::size_t)vsizeBytesToUse); } // add the padding: assert(payload.voids_.empty()); elementSize = (elementIdSize + vsizeBytesToUse + payloadBytesSaved); uint64 voidSize = paddedSize - elementSize; if (voidSize >= kMinVoidEltSize) { IPayload::TVoid eltVoid; uint64 voidIdSize = uintNumBytes(eltVoid.getId()); uint64 vsizeBytesToUse = vsizeNumBytes(voidSize - voidIdSize); eltVoid.payload_.set(voidSize - voidIdSize - vsizeBytesToUse); IStorage::IReceiptPtr receipt = eltVoid.save(storage, vsizeBytesToUse); if (receipt) { *receipt_ += receipt; } } return receipt_; }