Skip to content

Commit 1ac579a

Browse files
kubiak-jplLeStarchthomas-bc
authored
DpWriter shrink container buffer after processing (#4904)
* Add unit tests for shrinking processed buffer * Update DpWriter to shrink processed buffers after processing * Formatting * Updated DpWriter to use the dataSize in the container header to shrink the container size * Update DpWriter SDD with container shrinking steps * Re-run formatting * Reset container structure iff the container was processed. Remove cast comment * Fixed DpWriter formatting --------- Co-authored-by: M Starch <LeStarch@googlemail.com> Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>
1 parent bf52aa3 commit 1ac579a

14 files changed

Lines changed: 170 additions & 10 deletions

File tree

Fw/Dp/DpContainer.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,22 @@ void DpContainer::setBuffer(const Buffer& buffer) {
142142
this->m_dataSize = 0;
143143
}
144144

145+
void DpContainer::shrinkBufferSize() {
146+
// Calculate the assumed size for the Fw::Buffer
147+
const FwSizeType newSize = this->getPacketSize();
148+
149+
// Check that the buffer can still store a data product
150+
// AND
151+
// That the update is a shrink operation. Growing an
152+
// Fw::Buffer is not safe
153+
FW_ASSERT(newSize >= MIN_PACKET_SIZE, static_cast<FwAssertArgType>(newSize));
154+
FW_ASSERT(newSize <= this->m_buffer.getSize(), static_cast<FwAssertArgType>(newSize),
155+
static_cast<FwAssertArgType>(this->m_buffer.getSize()));
156+
157+
// Shrink the Fw::Buffer
158+
this->m_buffer.setSize(newSize);
159+
}
160+
145161
Utils::HashBuffer DpContainer::getHeaderHash() const {
146162
const FwSizeType bufferSize = this->m_buffer.getSize();
147163
const FwSizeType minBufferSize = HEADER_HASH_OFFSET + HASH_DIGEST_LENGTH;

Fw/Dp/DpContainer.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,10 @@ class DpContainer {
177177
void setBuffer(const Buffer& buffer //!< The packet buffer
178178
);
179179

180+
//! Shrink the Fw::Buffer size to match the
181+
//! DataSize in the container header
182+
void shrinkBufferSize();
183+
180184
//! Invalidate the packet buffer
181185
void invalidateBuffer() {
182186
this->m_buffer = Fw::Buffer();

Svc/DpWriter/DpWriter.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,17 +158,38 @@ Fw::Success::T DpWriter::deserializePacketHeader(Fw::Buffer& buffer, Fw::DpConta
158158
return status;
159159
}
160160

161-
void DpWriter::performProcessing(const Fw::DpContainer& container) {
161+
void DpWriter::performProcessing(Fw::DpContainer& container) {
162162
// Get the buffer
163163
Fw::Buffer buffer = container.getBuffer();
164164
// Get the bit mask for the processing types
165165
const Fw::DpCfg::ProcType::SerialType procTypes = container.getProcTypes();
166166
// Do the processing
167+
bool did_process = false;
167168
for (FwIndexType portNum = 0; portNum < NUM_PROCBUFFERSENDOUT_OUTPUT_PORTS; ++portNum) {
168169
if ((procTypes & (1 << portNum)) != 0) {
169170
this->procBufferSendOut_out(portNum, buffer);
171+
did_process = true;
170172
}
171173
}
174+
175+
if (did_process) {
176+
// Updated DpContainer object state with the returned value in the
177+
// container buffer
178+
Fw::SerializeStatus stat = container.deserializeHeader();
179+
FW_ASSERT(stat == Fw::FW_SERIALIZE_OK, stat);
180+
181+
// Check that the buffer size is compatible with the data size in
182+
// the container header
183+
FW_ASSERT(container.getDataSize() <= buffer.getSize(), static_cast<FwAssertArgType>(container.getDataSize()),
184+
static_cast<FwAssertArgType>(buffer.getSize()));
185+
186+
// Re-compute and serialize the container header into the buffer
187+
container.updateHeaderHash();
188+
container.serializeHeader();
189+
190+
// Shrink internal Fw::Buffer
191+
container.shrinkBufferSize();
192+
}
172193
}
173194

174195
Fw::Success::T DpWriter::writeFile(const Fw::DpContainer& container,

Svc/DpWriter/DpWriter.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ class DpWriter final : public DpWriterComponentBase {
7979
);
8080

8181
//! Perform processing on a packet buffer
82-
void performProcessing(const Fw::DpContainer& container //!< The container
82+
void performProcessing(Fw::DpContainer& container //!< The container
8383
);
8484

8585
//! Write the file

Svc/DpWriter/docs/sdd.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ SVC-DPWRITER-003 | On receiving a data product container _C_, `Svc::DpWriter` sh
3535
SVC-DPWRITER-004 | On receiving an `Fw::Buffer` _B_, and after performing any requested processing on _B_, `Svc::DpWriter` shall write _B_ to disk. | The purpose of `DpWriter` is to write data products to the disk. | Unit Test
3636
SVC-DPWRITER-005 | `Svc::DpWriter` shall provide a port for notifying other components that data products have been written. | This requirement allows `Svc::DpCatalog` or a similar component to update its catalog in real time. | Unit Test
3737
SVC-DPWRITER-006 | `Svc::DpManager` shall provide telemetry that reports the number of buffers received, the number of data products written, the number of bytes written, the number of failed writes, and the number of errors. | This requirement establishes the telemetry interface for the component. | Unit test
38+
SVC-DPWRITER-007 | On receiving an `Fw::Buffer` _B_, and after performing any requested processing on _B_, `Svc::DpWriter` shall re-parse the container header and shrink the size of the product. | Allows processing interfaces to compress data products and communicate that compressed state back to `Svc::DpWriter`. | Unit Test
3839

3940
## 3. Design
4041

@@ -125,6 +126,10 @@ It does the following:
125126
`procBufferSendOut` at port number `N`, passing in `B`.
126127
This step updates the memory pointed to by `B` in place.
127128

129+
1. Re-parse the container header pointed to by `B`. If necessary,
130+
shrink the size of the `B` buffer to be consistent with the data
131+
size in the updated container header.
132+
128133
1. Write `B` to a file, using the format described in the [**File
129134
Format**](#file_format) section. For the time stamp, use the time
130135
provided by `timeGetOut`.

Svc/DpWriter/test/ut/AbstractState.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,18 @@ namespace Svc {
2424
//! Get a data product buffer backed by m_bufferData
2525
//! \return The buffer
2626
Fw::Buffer AbstractState::getDpBuffer() {
27+
Fw::DpCfg::ProcType::SerialType procTypes = 0;
28+
for (FwIndexType i = 0; i < Fw::DpCfg::ProcType::NUM_CONSTANTS; i++) {
29+
const bool selector = static_cast<bool>(STest::Pick::lowerUpper(0, 1));
30+
if (selector) {
31+
procTypes = static_cast<Fw::DpCfg::ProcType::SerialType>(procTypes | (1 << i));
32+
}
33+
}
34+
35+
return getDpBufferWithProc(procTypes);
36+
}
37+
38+
Fw::Buffer AbstractState::getDpBufferWithProc(Fw::DpCfg::ProcType::SerialType procTypes) {
2739
// Generate the ID
2840
const FwDpIdType id = static_cast<FwDpIdType>(STest::Pick::lowerUpper(
2941
std::numeric_limits<FwDpIdType>::min(), static_cast<U32>(std::numeric_limits<FwDpIdType>::max())));
@@ -45,13 +57,6 @@ Fw::Buffer AbstractState::getDpBuffer() {
4557
const U32 microseconds = STest::Pick::startLength(0, 1000000);
4658
container.setTimeTag(Fw::Time(seconds, microseconds));
4759
// Update the processing types
48-
Fw::DpCfg::ProcType::SerialType procTypes = 0;
49-
for (FwIndexType i = 0; i < Fw::DpCfg::ProcType::NUM_CONSTANTS; i++) {
50-
const bool selector = static_cast<bool>(STest::Pick::lowerUpper(0, 1));
51-
if (selector) {
52-
procTypes = static_cast<Fw::DpCfg::ProcType::SerialType>(procTypes | (1 << i));
53-
}
54-
}
5560
container.setProcTypes(procTypes);
5661
// Update the data size
5762
container.setDataSize(dataSize);

Svc/DpWriter/test/ut/AbstractState.hpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ class AbstractState {
5151
m_NumFailedWrites(0),
5252
m_NumSuccessfulWrites(0),
5353
m_NumErrors(0),
54-
m_procTypes(0) {}
54+
m_procTypes(0),
55+
m_procShrinkDataSizeOpt() {}
5556

5657
public:
5758
// ----------------------------------------------------------------------
@@ -66,10 +67,16 @@ class AbstractState {
6667
//! Set the data size
6768
void setDataSize(FwSizeType dataSize) { this->m_dataSizeOpt.set(dataSize); }
6869

70+
void clearDataSize() { this->m_dataSizeOpt.clear(); }
71+
6972
//! Get a data product buffer backed by bufferData
7073
//! \return The buffer
7174
Fw::Buffer getDpBuffer();
7275

76+
//! Get a data product buffer backed by bufferData
77+
//! \return The buffer
78+
Fw::Buffer getDpBufferWithProc(Fw::DpCfg::ProcType::SerialType procTypes);
79+
7380
private:
7481
// ----------------------------------------------------------------------
7582
// Private state variables
@@ -127,6 +134,8 @@ class AbstractState {
127134

128135
//! Bit mask for processing out port calls
129136
Fw::DpCfg::ProcType::SerialType m_procTypes;
137+
138+
TestUtils::Option<FwSizeType> m_procShrinkDataSizeOpt;
130139
};
131140

132141
} // namespace Svc

Svc/DpWriter/test/ut/DpWriterTestMain.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,16 @@ TEST(BufferSendIn, OK) {
7171
tester.OK();
7272
}
7373

74+
TEST(BufferSendIn, OKProcShrink) {
75+
COMMENT("Invoke bufferSendIn with nominal input. Shrink the buffer in processing");
76+
REQUIREMENT("SVC-DPMANAGER-002");
77+
REQUIREMENT("SVC-DPMANAGER-003");
78+
REQUIREMENT("SVC-DPMANAGER-004");
79+
REQUIREMENT("SVC-DPMANAGER-007");
80+
BufferSendIn::Tester tester;
81+
tester.OKProcShrink();
82+
}
83+
7484
TEST(CLEAR_EVENT_THROTTLE, OK) {
7585
COMMENT("Test the CLEAR_EVENT_THROTTLE command.");
7686
REQUIREMENT("SVC-DPMANAGER-006");

Svc/DpWriter/test/ut/DpWriterTester.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@ void DpWriterTester::from_procBufferSendOut_handler(FwIndexType portNum, Fw::Buf
3535
this->pushFromPortEntry_procBufferSendOut(buffer);
3636
this->abstractState.m_procTypes =
3737
static_cast<Fw::DpCfg::ProcType::SerialType>(this->abstractState.m_procTypes | (1 << portNum));
38+
39+
if (this->abstractState.m_procShrinkDataSizeOpt.hasValue()) {
40+
// Update the data size in the container
41+
const FwSizeType newSize = this->abstractState.m_procShrinkDataSizeOpt.get();
42+
Fw::DpContainer c(0, buffer);
43+
c.deserializeHeader();
44+
c.setDataSize(newSize);
45+
c.serializeHeader();
46+
}
3847
}
3948

4049
// ----------------------------------------------------------------------

Svc/DpWriter/test/ut/Rules/BufferSendIn.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,72 @@ void TestState ::action__BufferSendIn__OK() {
7979
this->abstractState.m_NumSuccessfulWrites.value++;
8080
}
8181

82+
bool TestState ::precondition__BufferSendIn__OKProcShrink() const {
83+
const auto& fileData = Os::Stub::File::Test::StaticData::data;
84+
bool result = true;
85+
result &= (fileData.openStatus == Os::File::Status::OP_OK);
86+
result &= (fileData.writeStatus == Os::File::Status::OP_OK);
87+
return result;
88+
}
89+
90+
void TestState ::action__BufferSendIn__OKProcShrink() {
91+
// Clear the history
92+
this->clearHistory();
93+
// Reset the saved proc types
94+
// These are updated in the from_procBufferSendOut handler
95+
this->abstractState.m_procTypes = 0;
96+
// Reset the file pointer in the stub file implementation
97+
auto& fileData = Os::Stub::File::Test::StaticData::data;
98+
fileData.pointer = 0;
99+
// Update m_NumBuffersReceived
100+
this->abstractState.m_NumBuffersReceived.value++;
101+
// Construct a random buffer
102+
const FwSizeType buffer_data_size =
103+
STest::Pick::lowerUpper(AbstractState::MAX_DATA_SIZE / 2, AbstractState::MAX_DATA_SIZE);
104+
const FwSizeType shrink_data_size = buffer_data_size / 2;
105+
this->abstractState.setDataSize(buffer_data_size);
106+
Fw::Buffer buffer = this->abstractState.getDpBufferWithProc(1);
107+
// Instruct the proc handler to shrink the buffer
108+
this->abstractState.m_procShrinkDataSizeOpt.set(shrink_data_size);
109+
const FwSizeType exp_buffer_size = Fw::DpContainer::MIN_PACKET_SIZE + shrink_data_size;
110+
// Send the buffer
111+
this->invoke_to_bufferSendIn(0, buffer);
112+
this->doDispatch();
113+
// Deserialize the container header
114+
Fw::DpContainer container;
115+
container.setBuffer(buffer);
116+
const Fw::SerializeStatus status = container.deserializeHeader();
117+
ASSERT_EQ(status, Fw::FW_SERIALIZE_OK);
118+
// Check events
119+
ASSERT_EVENTS_SIZE(1);
120+
ASSERT_EVENTS_FileWritten_SIZE(1);
121+
Fw::FileNameString fileName;
122+
this->constructDpFileName(container.getId(), container.getTimeTag(), fileName);
123+
ASSERT_EVENTS_FileWritten(0, static_cast<U32>(exp_buffer_size), fileName.toChar());
124+
// Check processing types
125+
this->checkProcTypes(container);
126+
// Check DP notification
127+
ASSERT_from_dpWrittenOut_SIZE(1);
128+
ASSERT_from_dpWrittenOut(0, fileName, container.getPriority(), exp_buffer_size);
129+
// Check deallocation
130+
ASSERT_from_deallocBufferSendOut_SIZE(1);
131+
ASSERT_from_deallocBufferSendOut(0, buffer);
132+
// Check file write
133+
ASSERT_EQ(exp_buffer_size, fileData.pointer);
134+
ASSERT_EQ(0, ::memcmp(buffer.getData(), fileData.writeResult, exp_buffer_size));
135+
// Check data checksum is valid for the container buffer
136+
Utils::HashBuffer storedHash;
137+
Utils::HashBuffer computedHash;
138+
ASSERT_EQ(Fw::Success::SUCCESS, container.checkDataHash(storedHash, computedHash));
139+
// Update m_NumBytesWritten
140+
this->abstractState.m_NumBytesWritten.value += exp_buffer_size;
141+
// Update m_NumSuccessfulWrites
142+
this->abstractState.m_NumSuccessfulWrites.value++;
143+
144+
this->abstractState.clearDataSize();
145+
this->abstractState.m_procShrinkDataSizeOpt.clear();
146+
}
147+
82148
bool TestState ::precondition__BufferSendIn__InvalidBuffer() const {
83149
bool result = true;
84150
return result;
@@ -444,6 +510,11 @@ void Tester::OK() {
444510
this->testState.printEvents();
445511
}
446512

513+
void Tester::OKProcShrink() {
514+
this->ruleOKProcShrink.apply(this->testState);
515+
this->testState.printEvents();
516+
}
517+
447518
} // namespace BufferSendIn
448519

449520
} // namespace Svc

0 commit comments

Comments
 (0)