| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // ====================================================================== | ||
| 2 | |||
| 3 | // \title DpCatalog.cpp | ||
| 4 | // \author tcanham | ||
| 5 | // \brief cpp file for DpCatalog component implementation class | ||
| 6 | // ====================================================================== | ||
| 7 | |||
| 8 | #include "Svc/DpCatalog/DpCatalog.hpp" | ||
| 9 | #include "Fw/Dp/DpContainer.hpp" | ||
| 10 | #include "Fw/FPrimeBasicTypes.hpp" | ||
| 11 | |||
| 12 | #include <new> // placement new | ||
| 13 | #include "Fw/Types/StringUtils.hpp" | ||
| 14 | #include "Os/File.hpp" | ||
| 15 | #include "Os/FileSystem.hpp" | ||
| 16 | #include "Utils/Hash/Hash.hpp" | ||
| 17 | |||
| 18 | namespace Svc { | ||
| 19 | static_assert(DP_MAX_DIRECTORIES > 0, "Configuration DP_MAX_DIRECTORIES must be positive"); | ||
| 20 | static_assert(DP_MAX_FILES > 0, "Configuration DP_MAX_FILES must be positive"); | ||
| 21 | // ---------------------------------------------------------------------- | ||
| 22 | // Component construction and destruction | ||
| 23 | // ---------------------------------------------------------------------- | ||
| 24 | |||
| 25 |
7/13✓ Branch 15 taken 564 times.
✓ Branch 21 taken 564 times.
✓ Branch 39 taken 1128 times.
✓ Branch 42 taken 1128 times.
✓ Branch 43 taken 564 times.
✓ Branch 53 taken 564 times.
✓ Branch 91 taken 564 times.
✗ Branch 130 not taken.
✗ Branch 131 not taken.
✗ Branch 133 not taken.
✗ Branch 134 not taken.
✗ Branch 144 not taken.
✗ Branch 145 not taken.
|
1692 | DpCatalog ::DpCatalog(const char* const compName) : DpCatalogComponentBase(compName) { |
| 26 | // Members are default-initialized via in-class initializers in the header. | ||
| 27 | 564 | } | |
| 28 | |||
| 29 | 662 | void DpCatalog::configure(const Fw::ExternalArray<Fw::FileNameString>& directories, | |
| 30 | Fw::FileNameString& stateFile, | ||
| 31 | FwEnumStoreType memId, | ||
| 32 | Fw::MemAllocator& allocator) { | ||
| 33 | 662 | const FwSizeType numDirs = directories.getSize(); | |
| 34 | // Do some assertion checks | ||
| 35 | 662 | FW_ASSERT(numDirs <= DP_MAX_DIRECTORIES, static_cast<FwAssertArgType>(numDirs)); | |
| 36 | |||
| 37 |
1/1✓ Branch 7 taken 662 times.
|
662 | this->m_stateFile = stateFile; |
| 38 | |||
| 39 | // Request memory for state file data storage. | ||
| 40 | // RedBlackTreeSet storage is allocated as a member variable, so we only need | ||
| 41 | // to allocate memory for the state file tracking array. | ||
| 42 | static const FwSizeType slotSize = sizeof(DpDstateFileEntry); | ||
| 43 | 662 | this->m_memSize = DP_MAX_FILES * slotSize; | |
| 44 | 662 | bool notUsed; // we don't need to recover the catalog. | |
| 45 | // request memory. this->m_memSize will be modified if there is less than we requested | ||
| 46 |
1/1✓ Branch 11 taken 662 times.
|
662 | this->m_memPtr = allocator.allocate(memId, this->m_memSize, notUsed); |
| 47 | |||
| 48 | // Initialize if there is enough room for at least one record and memory was allocated | ||
| 49 |
2/4✓ Branch 4 taken 662 times.
✗ Branch 5 not taken.
✓ Branch 10 taken 662 times.
✗ Branch 11 not taken.
|
662 | if ((this->m_memSize >= slotSize) and (this->m_memPtr != nullptr)) { |
| 50 | // set the number of available record slots based on how much memory we actually got, | ||
| 51 | // never exceeding the DP_MAX_FILES working arrays even if the allocator returned more | ||
| 52 | // memory than was requested | ||
| 53 | 662 | const FwSizeType allocatedSlots = this->m_memSize / slotSize; | |
| 54 | 662 | this->m_numDpSlots = (allocatedSlots < DP_MAX_FILES) ? allocatedSlots : DP_MAX_FILES; | |
| 55 | // Initialize the catalog | ||
| 56 |
1/1✓ Branch 4 taken 662 times.
|
662 | this->resetCatalog(); |
| 57 | // assign pointer for the state file storage | ||
| 58 | 662 | this->m_stateFileData = static_cast<DpDstateFileEntry*>(this->m_memPtr); | |
| 59 | 662 | } else { | |
| 60 | // if we don't have enough memory, set the number of records | ||
| 61 | // to zero for later detection | ||
| 62 | ✗ | this->m_numDpSlots = 0; | |
| 63 | } | ||
| 64 | |||
| 65 | // assign directory names | ||
| 66 |
2/2✓ Branch 0 taken 767 times.
✓ Branch 1 taken 662 times.
|
1429 | for (FwSizeType dir = 0; dir < numDirs; dir++) { |
| 67 |
2/2✓ Branch 2 taken 767 times.
✓ Branch 11 taken 767 times.
|
767 | this->m_directories[dir] = directories[dir]; |
| 68 | } | ||
| 69 | 662 | this->m_numDirectories = numDirs; | |
| 70 | |||
| 71 | // store allocator | ||
| 72 | 662 | this->m_allocator = &allocator; | |
| 73 | 662 | this->m_allocatorId = memId; | |
| 74 | 662 | this->m_initialized = true; | |
| 75 | 662 | } | |
| 76 | |||
| 77 | ✗ | void DpCatalog::configure(Fw::FileNameString directories[DP_MAX_DIRECTORIES], | |
| 78 | FwSizeType numDirs, | ||
| 79 | Fw::FileNameString& stateFile, | ||
| 80 | FwEnumStoreType memId, | ||
| 81 | Fw::MemAllocator& allocator) { | ||
| 82 | ✗ | FW_ASSERT(numDirs <= DP_MAX_DIRECTORIES, static_cast<FwAssertArgType>(numDirs)); | |
| 83 | ✗ | const Fw::ExternalArray<Fw::FileNameString> directoryArray(directories, numDirs); | |
| 84 | ✗ | this->configure(directoryArray, stateFile, memId, allocator); | |
| 85 | ✗ | } | |
| 86 | |||
| 87 | 1332 | void DpCatalog::resetCatalog() { | |
| 88 | // Clear the catalog | ||
| 89 | 1332 | this->m_dpCatalog.clear(); | |
| 90 | // Clear transmission state | ||
| 91 | 1332 | this->m_hasCurrentXmit = false; | |
| 92 | // Reset counters | ||
| 93 | 1332 | this->m_pendingFiles = 0; | |
| 94 | 1332 | this->m_pendingDpBytes = 0; | |
| 95 | // Mark the catalog as un-built | ||
| 96 | 1332 | this->m_catalogBuilt = false; | |
| 97 | 1332 | } | |
| 98 | |||
| 99 | 169 | void DpCatalog::resetStateFileData() { | |
| 100 | // clear state file data | ||
| 101 |
2/2✓ Branch 4 taken 21339 times.
✓ Branch 5 taken 169 times.
|
21508 | for (FwSizeType slot = 0; slot < this->m_numDpSlots; slot++) { |
| 102 | 21339 | this->m_stateFileData[slot].used = false; | |
| 103 | 21339 | this->m_stateFileData[slot].visited = false; | |
| 104 |
1/3✓ Branch 9 taken 21339 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
|
21339 | (void)new (&this->m_stateFileData[slot].entry.record) DpRecord(); |
| 105 | } | ||
| 106 | 169 | this->m_stateFileEntries = 0; | |
| 107 | 169 | } | |
| 108 | |||
| 109 | 161 | Fw::CmdResponse DpCatalog::loadStateFile() { | |
| 110 | 161 | FW_ASSERT(this->m_stateFileData != nullptr); | |
| 111 | |||
| 112 | // Make sure that a file was specified | ||
| 113 |
3/3✓ Branch 6 taken 161 times.
✓ Branch 8 taken 28 times.
✓ Branch 9 taken 133 times.
|
161 | if (this->m_stateFile.length() == 0) { |
| 114 |
1/1✓ Branch 5 taken 28 times.
|
28 | this->log_WARNING_LO_NoStateFileSpecified(); |
| 115 |
1/1✓ Branch 1 taken 28 times.
|
28 | return Fw::CmdResponse::OK; |
| 116 | } | ||
| 117 | |||
| 118 | // buffer for reading entries | ||
| 119 | |||
| 120 | 133 | BYTE buffer[sizeof(FwIndexType) + DpRecord::SERIALIZED_SIZE]; | |
| 121 |
1/1✓ Branch 2 taken 133 times.
|
133 | Fw::ExternalSerializeBuffer entryBuffer(buffer, sizeof(buffer)); |
| 122 | |||
| 123 | // open the state file | ||
| 124 |
1/1✓ Branch 2 taken 133 times.
|
133 | Os::File stateFile; |
| 125 |
1/1✓ Branch 8 taken 133 times.
|
133 | Os::File::Status stat = stateFile.open(this->m_stateFile.toChar(), Os::File::OPEN_READ); |
| 126 |
2/2✓ Branch 0 taken 123 times.
✓ Branch 1 taken 10 times.
|
133 | if (stat == Os::File::DOESNT_EXIST) { |
| 127 | // A missing state file is expected on first boot and is not an error | ||
| 128 |
1/1✓ Branch 8 taken 123 times.
|
123 | this->log_WARNING_LO_NoStateFile(this->m_stateFile); |
| 129 |
1/1✓ Branch 1 taken 123 times.
|
123 | return Fw::CmdResponse::OK; |
| 130 | } | ||
| 131 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (stat != Os::File::OP_OK) { |
| 132 | ✗ | this->log_WARNING_HI_StateFileOpenError(this->m_stateFile, stat); | |
| 133 | ✗ | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 134 | } | ||
| 135 | |||
| 136 | 10 | FwSizeType fileSize = 0; | |
| 137 |
1/1✓ Branch 2 taken 10 times.
|
10 | stat = stateFile.size(fileSize); |
| 138 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (stat != Os::File::OP_OK) { |
| 139 | ✗ | this->log_WARNING_HI_StateFileReadError(this->m_stateFile, stat, 0); | |
| 140 | ✗ | stateFile.close(); | |
| 141 | ✗ | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 142 | } | ||
| 143 | |||
| 144 | 10 | FwSizeType fileLoc = 0; | |
| 145 | 10 | this->m_stateFileEntries = 0; | |
| 146 | |||
| 147 | // A product may have several records (a priority change, then its completion); the last one | ||
| 148 | // read wins, so the walk is bounded by the record count rather than the slot count | ||
| 149 | 10 | const FwSizeType maxRecords = fileSize / static_cast<FwSizeType>(sizeof(buffer)) + 1; | |
| 150 |
1/2✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
|
30 | for (FwSizeType record = 0; record < maxRecords; record++) { |
| 151 | 30 | FwSizeType size = static_cast<FwSizeType>(sizeof(buffer)); | |
| 152 | // read the directory index | ||
| 153 |
1/1✓ Branch 2 taken 30 times.
|
30 | stat = stateFile.read(buffer, size); |
| 154 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
|
30 | if (stat != Os::File::OP_OK) { |
| 155 | ✗ | this->log_WARNING_HI_StateFileReadError(this->m_stateFile, stat, static_cast<I32>(fileLoc)); | |
| 156 | ✗ | stateFile.close(); | |
| 157 | ✗ | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 158 | } | ||
| 159 | |||
| 160 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 22 times.
|
30 | if (0 == size) { |
| 161 | // no more entries | ||
| 162 | 8 | break; | |
| 163 | } | ||
| 164 | |||
| 165 | // check to see if the full entry was read. If not, | ||
| 166 | // abandon it and finish. We can at least operate on | ||
| 167 | // the entries that were read. | ||
| 168 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 21 times.
|
22 | if (size != sizeof(buffer)) { |
| 169 |
1/1✓ Branch 8 taken 1 times.
|
1 | this->log_WARNING_HI_StateFileTruncated(this->m_stateFile, static_cast<I32>(fileLoc), |
| 170 | static_cast<I32>(size)); | ||
| 171 |
1/1✓ Branch 2 taken 1 times.
|
1 | stateFile.close(); |
| 172 |
1/1✓ Branch 1 taken 1 times.
|
1 | return Fw::CmdResponse::OK; |
| 173 | } | ||
| 174 | |||
| 175 | // reset the buffer for deserializing the entry | ||
| 176 |
1/1✓ Branch 2 taken 21 times.
|
21 | Fw::SerializeStatus serStat = entryBuffer.setBuffLen(static_cast<Fw::Serializable::SizeType>(size)); |
| 177 | // should always fit | ||
| 178 | 21 | FW_ASSERT(Fw::FW_SERIALIZE_OK == serStat, serStat); | |
| 179 |
1/1✓ Branch 2 taken 21 times.
|
21 | entryBuffer.resetDeser(); |
| 180 | |||
| 181 | // deserialization after this point should always work, since | ||
| 182 | // the source buffer was specifically sized to hold the data | ||
| 183 | |||
| 184 | // Deserialize the file directory index. If an error occurs processing the file, | ||
| 185 | // generate event and return EXECUTION_ERROR. | ||
| 186 |
1/1✓ Branch 2 taken 21 times.
|
21 | DpStateEntry fileEntry{}; |
| 187 |
1/1✓ Branch 2 taken 21 times.
|
21 | Fw::SerializeStatus status = entryBuffer.deserializeTo(fileEntry.dir); |
| 188 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (status != Fw::FW_SERIALIZE_OK) { |
| 189 | ✗ | this->log_WARNING_HI_FileCorruptedDataError(this->m_stateFile, static_cast<I32>(status)); | |
| 190 | ✗ | stateFile.close(); | |
| 191 | ✗ | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 192 | } | ||
| 193 |
1/1✓ Branch 2 taken 21 times.
|
21 | status = entryBuffer.deserializeTo(fileEntry.record); |
| 194 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 20 times.
|
21 | if (status != Fw::FW_SERIALIZE_OK) { |
| 195 |
1/1✓ Branch 8 taken 1 times.
|
1 | this->log_WARNING_HI_FileCorruptedDataError(this->m_stateFile, static_cast<I32>(status)); |
| 196 |
1/1✓ Branch 2 taken 1 times.
|
1 | stateFile.close(); |
| 197 |
1/1✓ Branch 1 taken 1 times.
|
1 | return Fw::CmdResponse::EXECUTION_ERROR; |
| 198 | } | ||
| 199 | |||
| 200 |
1/1✓ Branch 4 taken 20 times.
|
20 | const FwSizeType slot = this->findStateFileSlot(fileEntry); |
| 201 |
2/2✓ Branch 4 taken 17 times.
✓ Branch 5 taken 3 times.
|
20 | if (slot == this->m_stateFileEntries) { |
| 202 |
2/2✓ Branch 8 taken 1 times.
✓ Branch 9 taken 16 times.
|
17 | if (this->m_stateFileEntries >= this->m_numDpSlots) { |
| 203 | // no slot for another product; later records for products that have a slot still apply | ||
| 204 | 1 | fileLoc += size; | |
| 205 | 1 | continue; | |
| 206 | } | ||
| 207 | 16 | this->m_stateFileEntries++; | |
| 208 | } | ||
| 209 |
1/1✓ Branch 9 taken 19 times.
|
19 | this->m_stateFileData[slot].entry = fileEntry; |
| 210 | 19 | this->m_stateFileData[slot].used = true; | |
| 211 | 19 | this->m_stateFileData[slot].visited = false; | |
| 212 | |||
| 213 | // increment the file location | ||
| 214 | 19 | fileLoc += size; | |
| 215 | 21 | } | |
| 216 |
1/1✓ Branch 2 taken 8 times.
|
8 | stateFile.close(); |
| 217 |
1/1✓ Branch 1 taken 8 times.
|
8 | return Fw::CmdResponse::OK; |
| 218 | 133 | } | |
| 219 | |||
| 220 | 6419 | void DpCatalog::getFileState(DpStateEntry& entry) { | |
| 221 | 6419 | FW_ASSERT(this->m_stateFileData != nullptr); | |
| 222 | 6419 | const FwSizeType line = this->findStateFileSlot(entry); | |
| 223 |
2/2✓ Branch 4 taken 19 times.
✓ Branch 5 taken 6400 times.
|
6419 | if (line < this->m_stateFileEntries) { |
| 224 | // a recorded priority differs from the file header only if SET_DP_PRIORITY changed it | ||
| 225 | 19 | entry.record.set_priority(this->m_stateFileData[line].entry.record.get_priority()); | |
| 226 | // update the transmitted state | ||
| 227 | 19 | entry.record.set_state(this->m_stateFileData[line].entry.record.get_state()); | |
| 228 | 19 | entry.record.set_blocks(this->m_stateFileData[line].entry.record.get_blocks()); | |
| 229 | // mark it as visited for later pruning if necessary | ||
| 230 | 19 | this->m_stateFileData[line].visited = true; | |
| 231 | } | ||
| 232 | 6419 | } | |
| 233 | |||
| 234 | 12565 | FwSizeType DpCatalog::findStateFileSlot(const DpStateEntry& entry) const { | |
| 235 | 12565 | FW_ASSERT(this->m_stateFileData != nullptr); | |
| 236 |
2/2✓ Branch 4 taken 350326 times.
✓ Branch 5 taken 12533 times.
|
362859 | for (FwSizeType line = 0; line < this->m_stateFileEntries; line++) { |
| 237 |
2/2✓ Branch 9 taken 32 times.
✓ Branch 10 taken 350294 times.
|
350326 | if (this->m_stateFileData[line].entry.isSameProduct(entry)) { |
| 238 | 32 | return line; | |
| 239 | } | ||
| 240 | } | ||
| 241 | 12533 | return this->m_stateFileEntries; | |
| 242 | } | ||
| 243 | |||
| 244 | 6126 | DpCatalog_StateFileUpdateStatus DpCatalog::updateStateFileData(const DpStateEntry& entry) { | |
| 245 | 6126 | FwSizeType slot = this->findStateFileSlot(entry); | |
| 246 |
2/2✓ Branch 4 taken 6116 times.
✓ Branch 5 taken 10 times.
|
6126 | if (slot == this->m_stateFileEntries) { |
| 247 | // outside a catalog build, a slot not visited by the last build is for a file that is gone | ||
| 248 |
2/2✓ Branch 4 taken 250046 times.
✓ Branch 5 taken 6116 times.
|
256162 | for (FwSizeType line = 0; line < this->m_stateFileEntries; line++) { |
| 249 |
2/4✗ Branch 6 not taken.
✓ Branch 7 taken 250046 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 250046 times.
|
250046 | if (not this->m_stateFileData[line].visited) { |
| 250 | ✗ | slot = line; | |
| 251 | ✗ | break; | |
| 252 | } | ||
| 253 | } | ||
| 254 | } | ||
| 255 |
2/2✓ Branch 4 taken 6116 times.
✓ Branch 5 taken 10 times.
|
6126 | if (slot == this->m_stateFileEntries) { |
| 256 |
2/2✓ Branch 8 taken 6 times.
✓ Branch 9 taken 6110 times.
|
6116 | if (this->m_stateFileEntries >= this->m_numDpSlots) { |
| 257 | // only worth reporting when the state is kept in a state file | ||
| 258 |
2/2✓ Branch 6 taken 2 times.
✓ Branch 7 taken 4 times.
|
6 | if (this->m_stateFile.length() > 0) { |
| 259 | 4 | this->log_WARNING_HI_StateFileFull(entry.record.get_id(), entry.record.get_tSec(), | |
| 260 | 2 | entry.record.get_tSub()); | |
| 261 | } | ||
| 262 | 6 | return DpCatalog_StateFileUpdateStatus::FULL; | |
| 263 | } | ||
| 264 | 6110 | this->m_stateFileEntries++; | |
| 265 | } | ||
| 266 | 6120 | this->m_stateFileData[slot].entry = entry; | |
| 267 | 6120 | this->m_stateFileData[slot].used = true; | |
| 268 | 6120 | this->m_stateFileData[slot].visited = true; | |
| 269 | 6120 | return DpCatalog_StateFileUpdateStatus::RECORDED; | |
| 270 | } | ||
| 271 | |||
| 272 | 166 | DpCatalog_StateFileWriteStatus DpCatalog::pruneAndWriteStateFile() { | |
| 273 | 166 | FW_ASSERT(this->m_stateFileData != nullptr); | |
| 274 | |||
| 275 | // There is a chance that a data product file can disappear after | ||
| 276 | // the state file is written from the last catalog build and transmit. | ||
| 277 | // This function will walk the state file data and write back only | ||
| 278 | // the entries that were visited during the last catalog build. This will | ||
| 279 | // remove any entries that are no longer valid. | ||
| 280 | |||
| 281 | // open the state file | ||
| 282 |
1/1✓ Branch 2 taken 166 times.
|
166 | Os::File stateFile; |
| 283 | // we open it as a new file so we don't accumulate invalid entries | ||
| 284 | Os::File::Status stat = | ||
| 285 |
1/1✓ Branch 8 taken 166 times.
|
166 | stateFile.open(this->m_stateFile.toChar(), Os::File::OPEN_CREATE, Os::FileInterface::OVERWRITE); |
| 286 | |||
| 287 |
2/2✓ Branch 0 taken 135 times.
✓ Branch 1 taken 31 times.
|
166 | if (stat != Os::File::OP_OK) { |
| 288 |
1/1✓ Branch 8 taken 135 times.
|
135 | this->log_WARNING_HI_StateFileOpenError(this->m_stateFile, stat); |
| 289 |
1/1✓ Branch 1 taken 135 times.
|
135 | return DpCatalog_StateFileWriteStatus::OPEN_ERROR; |
| 290 | } | ||
| 291 | |||
| 292 | // buffer for writing entries | ||
| 293 | 31 | BYTE buffer[sizeof(FwIndexType) + DpRecord::SERIALIZED_SIZE]; | |
| 294 |
1/1✓ Branch 2 taken 31 times.
|
31 | Fw::ExternalSerializeBuffer entryBuffer(buffer, sizeof(buffer)); |
| 295 | |||
| 296 | // write entries to the state file | ||
| 297 |
2/2✓ Branch 4 taken 3813 times.
✓ Branch 5 taken 31 times.
|
3844 | for (FwSizeType entry = 0; entry < this->m_numDpSlots; entry++) { |
| 298 | // only write entries that were used | ||
| 299 |
5/8✗ Branch 6 not taken.
✓ Branch 7 taken 3813 times.
✓ Branch 8 taken 22 times.
✓ Branch 9 taken 3791 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 22 times.
✓ Branch 18 taken 22 times.
✗ Branch 19 not taken.
|
3813 | if ((this->m_stateFileData[entry].used) and (this->m_stateFileData[entry].visited)) { |
| 300 | // reset the buffer for serializing the entry | ||
| 301 |
1/1✓ Branch 2 taken 22 times.
|
22 | entryBuffer.resetSer(); |
| 302 | // serialize the file directory index | ||
| 303 |
1/1✓ Branch 9 taken 22 times.
|
22 | Fw::SerializeStatus serStat = entryBuffer.serializeFrom(this->m_stateFileData[entry].entry.dir); |
| 304 | // Should always fit | ||
| 305 | 22 | FW_ASSERT(Fw::FW_SERIALIZE_OK == serStat, serStat); | |
| 306 |
1/1✓ Branch 10 taken 22 times.
|
22 | serStat = entryBuffer.serializeFrom(this->m_stateFileData[entry].entry.record); |
| 307 | // Should always fit | ||
| 308 | 22 | FW_ASSERT(Fw::FW_SERIALIZE_OK == serStat, serStat); | |
| 309 | // write the entry | ||
| 310 |
1/1✓ Branch 3 taken 22 times.
|
22 | FwSizeType size = entryBuffer.getSize(); |
| 311 | // Protect against overflow | ||
| 312 |
1/1✓ Branch 2 taken 22 times.
|
22 | stat = stateFile.write(buffer, size); |
| 313 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
|
22 | if (stat != Os::File::OP_OK) { |
| 314 | ✗ | this->log_WARNING_HI_StateFileWriteError(this->m_stateFile, stat); | |
| 315 | ✗ | stateFile.close(); | |
| 316 | ✗ | return DpCatalog_StateFileWriteStatus::WRITE_ERROR; | |
| 317 | } | ||
| 318 | } | ||
| 319 | } | ||
| 320 | |||
| 321 | // close the state file | ||
| 322 |
1/1✓ Branch 2 taken 31 times.
|
31 | stateFile.close(); |
| 323 |
1/1✓ Branch 1 taken 31 times.
|
31 | return DpCatalog_StateFileWriteStatus::WRITTEN; |
| 324 | 166 | } | |
| 325 | |||
| 326 | 6118 | void DpCatalog::appendFileState(const DpStateEntry& entry) { | |
| 327 | 6118 | FW_ASSERT(this->m_stateFileData != nullptr); | |
| 328 | 6118 | FW_ASSERT(entry.dir < static_cast<FwIndexType>(this->m_numDirectories), static_cast<FwAssertArgType>(entry.dir), | |
| 329 | static_cast<FwAssertArgType>(this->m_numDirectories)); | ||
| 330 | |||
| 331 | // We will append state to the existing state file | ||
| 332 | // TODO: Have to handle case where state file has partially transmitted | ||
| 333 | // state already | ||
| 334 | |||
| 335 | // open the state file | ||
| 336 |
1/1✓ Branch 2 taken 6118 times.
|
6118 | Os::File stateFile; |
| 337 | // we open it as a new file so we don't accumulate invalid entries | ||
| 338 |
1/1✓ Branch 8 taken 6118 times.
|
6118 | Os::File::Status stat = stateFile.open(this->m_stateFile.toChar(), Os::File::OPEN_APPEND); |
| 339 |
2/2✓ Branch 0 taken 6071 times.
✓ Branch 1 taken 47 times.
|
6118 | if (stat != Os::File::OP_OK) { |
| 340 |
1/1✓ Branch 8 taken 6071 times.
|
6071 | this->log_WARNING_HI_StateFileOpenError(this->m_stateFile, stat); |
| 341 | 6071 | return; | |
| 342 | } | ||
| 343 | |||
| 344 | // buffer for writing entries | ||
| 345 | 47 | BYTE buffer[sizeof(FwIndexType) + DpRecord::SERIALIZED_SIZE]; | |
| 346 |
1/1✓ Branch 2 taken 47 times.
|
47 | Fw::ExternalSerializeBuffer entryBuffer(buffer, sizeof(buffer)); |
| 347 | // reset the buffer for serializing the entry | ||
| 348 |
1/1✓ Branch 2 taken 47 times.
|
47 | entryBuffer.resetSer(); |
| 349 | // serialize the file directory index | ||
| 350 |
1/1✓ Branch 3 taken 47 times.
|
47 | Fw::SerializeStatus serStat = entryBuffer.serializeFrom(entry.dir); |
| 351 | // should fit | ||
| 352 | 47 | FW_ASSERT(serStat == Fw::FW_SERIALIZE_OK, serStat); | |
| 353 |
1/1✓ Branch 7 taken 47 times.
|
47 | serStat = entryBuffer.serializeFrom(entry.record); |
| 354 | // should fit | ||
| 355 | 47 | FW_ASSERT(serStat == Fw::FW_SERIALIZE_OK, serStat); | |
| 356 | // write the entry | ||
| 357 |
1/1✓ Branch 3 taken 47 times.
|
47 | FwSizeType size = entryBuffer.getSize(); |
| 358 |
1/1✓ Branch 2 taken 47 times.
|
47 | stat = stateFile.write(buffer, size); |
| 359 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 47 times.
|
47 | if (stat != Os::File::OP_OK) { |
| 360 | ✗ | stateFile.close(); | |
| 361 | ✗ | this->log_WARNING_HI_StateFileWriteError(this->m_stateFile, stat); | |
| 362 | ✗ | return; | |
| 363 | } | ||
| 364 | |||
| 365 | // close the state file | ||
| 366 |
1/1✓ Branch 2 taken 47 times.
|
47 | stateFile.close(); |
| 367 | 6118 | } | |
| 368 | |||
| 369 | 161 | Fw::CmdResponse DpCatalog::doCatalogBuild() { | |
| 370 | // check initialization | ||
| 371 |
2/3✓ Branch 4 taken 161 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 161 times.
|
161 | if (not this->checkInit()) { |
| 372 | ✗ | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 373 | } | ||
| 374 | |||
| 375 | // check that initialization got memory | ||
| 376 |
1/2✗ Branch 4 not taken.
✓ Branch 5 taken 161 times.
|
161 | if (0 == this->m_numDpSlots) { |
| 377 | ✗ | this->log_WARNING_HI_NoDpMemory(); | |
| 378 | ✗ | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 379 | } | ||
| 380 | |||
| 381 | // make sure a downlink is not in progress | ||
| 382 |
2/4✗ Branch 3 not taken.
✓ Branch 4 taken 161 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 161 times.
|
161 | if (this->m_xmitInProgress) { |
| 383 | ✗ | this->log_WARNING_LO_DpXmitInProgress(); | |
| 384 | ✗ | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 385 | } | ||
| 386 | |||
| 387 | // reset state file data | ||
| 388 |
1/1✓ Branch 4 taken 161 times.
|
161 | this->resetStateFileData(); |
| 389 | |||
| 390 | // load state data from file; proceeding on a failed load would later | ||
| 391 | // overwrite the state file and destroy the transmit state it records | ||
| 392 |
1/1✓ Branch 2 taken 161 times.
|
161 | Fw::CmdResponse response = this->loadStateFile(); |
| 393 |
2/2✓ Branch 2 taken 1 times.
✓ Branch 3 taken 160 times.
|
161 | if (response != Fw::CmdResponse::OK) { |
| 394 |
1/1✓ Branch 4 taken 1 times.
|
1 | this->resetStateFileData(); |
| 395 |
1/1✓ Branch 1 taken 1 times.
|
1 | return response; |
| 396 | } | ||
| 397 | |||
| 398 | // reset catalog | ||
| 399 |
1/1✓ Branch 4 taken 160 times.
|
160 | this->resetCatalog(); |
| 400 | |||
| 401 | // fill the catalog with DP files | ||
| 402 |
2/2✓ Branch 2 taken 160 times.
✓ Branch 7 taken 160 times.
|
160 | response = this->fillBinaryTree(); |
| 403 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 160 times.
|
160 | if (response != Fw::CmdResponse::OK) { |
| 404 | // clean up the catalog | ||
| 405 | ✗ | this->resetCatalog(); | |
| 406 | ✗ | this->resetStateFileData(); | |
| 407 | ✗ | return response; | |
| 408 | } | ||
| 409 | |||
| 410 | // prune and rewrite the state file. A failure is reported by event; the file then holds the records | ||
| 411 | // written before the failure (or the previous contents if it could not be opened), and the build | ||
| 412 | // still completes from the catalog in memory | ||
| 413 |
1/1✓ Branch 2 taken 160 times.
|
160 | (void)this->pruneAndWriteStateFile(); |
| 414 | |||
| 415 |
1/1✓ Branch 5 taken 160 times.
|
160 | this->log_ACTIVITY_HI_CatalogBuildComplete(); |
| 416 | |||
| 417 | // Flag so addToCat knows it is good to go | ||
| 418 | 160 | this->m_catalogBuilt = true; | |
| 419 | |||
| 420 |
1/1✓ Branch 1 taken 160 times.
|
160 | return Fw::CmdResponse::OK; |
| 421 | 161 | } | |
| 422 | |||
| 423 | 160 | Fw::CmdResponse DpCatalog::fillBinaryTree() { | |
| 424 | // keep cumulative number of files | ||
| 425 | 160 | FwSizeType totalFiles = 0; | |
| 426 | |||
| 427 | // get file listings from file system | ||
| 428 | // double bounds to appease static analysis | ||
| 429 |
3/4✓ Branch 4 taken 265 times.
✓ Branch 5 taken 158 times.
✓ Branch 6 taken 265 times.
✗ Branch 7 not taken.
|
423 | for (FwSizeType dir = 0; dir < this->m_numDirectories && dir < static_cast<FwSizeType>(DP_MAX_DIRECTORIES); dir++) { |
| 430 | // read in each directory and keep track of total | ||
| 431 |
1/1✓ Branch 9 taken 265 times.
|
265 | this->log_ACTIVITY_LO_ProcessingDirectory(this->m_directories[dir]); |
| 432 | 265 | FwSizeType filesProcessed = 0; | |
| 433 | |||
| 434 |
1/1✓ Branch 2 taken 265 times.
|
265 | Os::Directory dpDir; |
| 435 |
1/1✓ Branch 9 taken 265 times.
|
265 | Os::Directory::Status status = dpDir.open(this->m_directories[dir].toChar(), Os::Directory::OpenMode::READ); |
| 436 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 265 times.
|
265 | if (status != Os::Directory::OP_OK) { |
| 437 | ✗ | this->log_WARNING_HI_DirectoryOpenError(this->m_directories[dir], status); | |
| 438 | ✗ | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 439 | } | ||
| 440 | |||
| 441 | // bound the read loop by the number of entries in the directory | ||
| 442 | 265 | FwSizeType fileCount = 0; | |
| 443 |
1/1✓ Branch 2 taken 265 times.
|
265 | status = dpDir.getFileCount(fileCount); |
| 444 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 265 times.
|
265 | if (status != Os::Directory::OP_OK) { |
| 445 | ✗ | this->log_WARNING_HI_DirectoryOpenError(this->m_directories[dir], status); | |
| 446 | ✗ | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 447 | } | ||
| 448 | |||
| 449 | // read entries one at a time so non-DP files do not consume catalog slots | ||
| 450 |
1/1✓ Branch 2 taken 265 times.
|
265 | Fw::String fileName; |
| 451 |
2/2✓ Branch 0 taken 3169 times.
✓ Branch 1 taken 265 times.
|
3434 | for (FwSizeType entry = 0; entry < fileCount; entry++) { |
| 452 |
1/1✓ Branch 2 taken 3169 times.
|
3169 | status = dpDir.read(fileName); |
| 453 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3169 times.
|
3169 | if (status == Os::Directory::NO_MORE_FILES) { |
| 454 | ✗ | break; | |
| 455 | } | ||
| 456 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3169 times.
|
3169 | if (status != Os::Directory::OP_OK) { |
| 457 | ✗ | this->log_WARNING_HI_DirectoryOpenError(this->m_directories[dir], status); | |
| 458 | ✗ | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 459 | } | ||
| 460 | |||
| 461 | // only consider files with the DP extension | ||
| 462 |
1/1✓ Branch 2 taken 3169 times.
|
3169 | const FwSizeType fileNameLength = fileName.length(); |
| 463 |
1/1✓ Branch 1 taken 3169 times.
|
3169 | const FwSizeType dpExtLength = Fw::StringUtils::string_length(DP_EXT, sizeof(DP_EXT)); |
| 464 | const FwSignedSizeType loc = | ||
| 465 |
1/1✓ Branch 3 taken 3169 times.
|
3169 | Fw::StringUtils::substring_find_last(fileName.toChar(), fileNameLength, DP_EXT, dpExtLength); |
| 466 | |||
| 467 | // Only accept files whose final suffix is the data product extension | ||
| 468 |
3/4✓ Branch 0 taken 3033 times.
✓ Branch 1 taken 136 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3033 times.
|
3169 | if ((-1 == loc) || (static_cast<FwSizeType>(loc) + dpExtLength != fileNameLength)) { |
| 469 | 136 | continue; | |
| 470 | } | ||
| 471 | |||
| 472 | // stop if there is no free catalog slot for this DP file | ||
| 473 |
1/2✗ Branch 4 not taken.
✓ Branch 5 taken 3033 times.
|
3033 | if ((totalFiles + filesProcessed) == this->m_numDpSlots) { |
| 474 | ✗ | break; | |
| 475 | } | ||
| 476 | |||
| 477 |
1/1✓ Branch 2 taken 3033 times.
|
3033 | Fw::String fullFile; |
| 478 | Fw::FormatStatus formatStatus = | ||
| 479 |
1/1✓ Branch 11 taken 3033 times.
|
3033 | fullFile.format("%s/%s", this->m_directories[dir].toChar(), fileName.toChar()); |
| 480 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3033 times.
|
3033 | if (formatStatus != Fw::FormatStatus::SUCCESS) { |
| 481 | ✗ | this->log_WARNING_HI_FileNameFormatError(fileName, | |
| 482 | static_cast<Fw::StringFormatStatus::T>(formatStatus)); | ||
| 483 | ✗ | continue; | |
| 484 | } | ||
| 485 | |||
| 486 |
1/1✓ Branch 4 taken 3033 times.
|
3033 | const ProcessFileStatus ret = processFile(fullFile, dir); |
| 487 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3033 times.
|
3033 | if (ret == ProcessFileStatus::QUIT) { |
| 488 | ✗ | break; | |
| 489 | } | ||
| 490 | |||
| 491 |
2/2✓ Branch 0 taken 3016 times.
✓ Branch 1 taken 17 times.
|
3033 | if (ret == ProcessFileStatus::SUCCESS) { |
| 492 | 3016 | filesProcessed++; | |
| 493 | } | ||
| 494 | |||
| 495 | 3033 | } // end for each file in a directory | |
| 496 | |||
| 497 | 265 | totalFiles += filesProcessed; | |
| 498 | |||
| 499 |
1/1✓ Branch 13 taken 265 times.
|
795 | this->log_ACTIVITY_HI_ProcessingDirectoryComplete(this->m_directories[dir], static_cast<U32>(totalFiles), |
| 500 | 530 | this->m_pendingFiles, this->m_pendingDpBytes); | |
| 501 | |||
| 502 | // check to see if catalog is full | ||
| 503 | // that means generated products exceed the catalog size | ||
| 504 |
2/2✓ Branch 4 taken 2 times.
✓ Branch 5 taken 263 times.
|
265 | if (totalFiles == this->m_numDpSlots) { |
| 505 |
1/1✓ Branch 9 taken 2 times.
|
2 | this->log_WARNING_HI_CatalogFull(this->m_directories[dir]); |
| 506 | 2 | break; | |
| 507 | } | ||
| 508 | 267 | } // end for each directory | |
| 509 | |||
| 510 | 160 | return Fw::CmdResponse::OK; | |
| 511 | |||
| 512 | } // end fillBinaryTree() | ||
| 513 | |||
| 514 | 3389 | FwSizeType DpCatalog::determineDirectory(const Fw::String& fullFile) { | |
| 515 | 3389 | FW_ASSERT(this->m_numDirectories <= DP_MAX_DIRECTORIES, static_cast<FwAssertArgType>(this->m_numDirectories)); | |
| 516 | // Grab the directory string (up until the final slash) | ||
| 517 | // Could be found directly w/ a dirname func or regex | ||
| 518 | 10167 | FwSignedSizeType loc = Fw::StringUtils::substring_find_last( | |
| 519 | 6778 | fullFile.toChar(), fullFile.length(), DIRECTORY_DELIMITER, | |
| 520 | Fw::StringUtils::string_length(DIRECTORY_DELIMITER, sizeof(DIRECTORY_DELIMITER))); | ||
| 521 | |||
| 522 | // Seems like the logic works so long as the path styles match (i.e. relative vs absolute) | ||
| 523 | // Full path resolution might be a worthwhile add | ||
| 524 | |||
| 525 | // No directory delimiter found; return DP_MAX_DIRECTORIES to signal failure | ||
| 526 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3389 times.
|
3389 | if (-1 == loc) { |
| 527 | ✗ | return DP_MAX_DIRECTORIES; | |
| 528 | } | ||
| 529 | |||
| 530 |
1/2✓ Branch 4 taken 5101 times.
✗ Branch 5 not taken.
|
5101 | for (FwSizeType dir = 0; dir < this->m_numDirectories; dir++) { |
| 531 | 5101 | const Fw::FileNameString& dir_string = this->m_directories[dir]; | |
| 532 | |||
| 533 | // Compare both strings up to location of final slash | ||
| 534 | // StringUtils::substring_find will return zero if both paths agree | ||
| 535 | // memory safe since both are fixed width strings | ||
| 536 | // and loc is before the fixed width | ||
| 537 |
3/4✓ Branch 7 taken 5101 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 3389 times.
✓ Branch 10 taken 1712 times.
|
10202 | if ((dir_string.length() == static_cast<FwSizeType>(loc)) && |
| 538 |
2/2✓ Branch 16 taken 3389 times.
✓ Branch 17 taken 1712 times.
|
5101 | (Fw::StringUtils::substring_find(dir_string.toChar(), dir_string.length(), fullFile.toChar(), |
| 539 | static_cast<FwSizeType>(loc)) == 0)) { | ||
| 540 | 3389 | return dir; | |
| 541 | } | ||
| 542 | } | ||
| 543 | |||
| 544 | // No directory matched | ||
| 545 | ✗ | return DP_MAX_DIRECTORIES; | |
| 546 | } | ||
| 547 | |||
| 548 | 6422 | DpCatalog::ProcessFileStatus DpCatalog::processFile(const Fw::String& fullFile, FwSizeType dir) { | |
| 549 | 6422 | FW_ASSERT(dir < static_cast<FwSizeType>(DP_MAX_DIRECTORIES), static_cast<FwAssertArgType>(dir)); | |
| 550 | // file class instance for processing files | ||
| 551 |
1/1✓ Branch 2 taken 6422 times.
|
6422 | Os::File dpFile; |
| 552 | |||
| 553 | // Working buffer for DP headers | ||
| 554 | 6422 | U8 dpBuff[Fw::DpContainer::MIN_PACKET_SIZE]; // Header buffer | |
| 555 |
1/1✓ Branch 2 taken 6422 times.
|
6422 | Fw::Buffer hdrBuff(dpBuff, sizeof(dpBuff)); // buffer for container header decoding |
| 556 |
1/1✓ Branch 2 taken 6422 times.
|
6422 | Fw::DpContainer container; // container object for extracting header fields |
| 557 | |||
| 558 |
1/1✓ Branch 8 taken 6422 times.
|
6422 | this->log_ACTIVITY_LO_ProcessingFile(fullFile); |
| 559 | |||
| 560 | // get file size | ||
| 561 | 6422 | FwSizeType fileSize = 0; | |
| 562 |
1/1✓ Branch 5 taken 6422 times.
|
6422 | Os::FileSystem::Status sizeStat = Os::FileSystem::getFileSize(fullFile.toChar(), fileSize); |
| 563 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6422 times.
|
6422 | if (sizeStat != Os::FileSystem::OP_OK) { |
| 564 | ✗ | this->log_WARNING_HI_FileSizeError(fullFile, sizeStat); | |
| 565 | ✗ | return ProcessFileStatus::FAILED; | |
| 566 | } | ||
| 567 | |||
| 568 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6421 times.
|
6422 | if (fileSize < Fw::DpContainer::MIN_PACKET_SIZE) { |
| 569 |
1/1✓ Branch 8 taken 1 times.
|
1 | this->log_WARNING_HI_FileReadError(fullFile, Os::File::BAD_SIZE); |
| 570 | 1 | return ProcessFileStatus::FAILED; | |
| 571 | } | ||
| 572 | |||
| 573 |
1/1✓ Branch 6 taken 6421 times.
|
6421 | Os::File::Status stat = dpFile.open(fullFile.toChar(), Os::File::OPEN_READ); |
| 574 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6421 times.
|
6421 | if (stat != Os::File::OP_OK) { |
| 575 | ✗ | this->log_WARNING_HI_FileOpenError(fullFile, stat); | |
| 576 | ✗ | return ProcessFileStatus::FAILED; | |
| 577 | } | ||
| 578 | |||
| 579 | // Read DP header and header hash | ||
| 580 | 6421 | FwSizeType size = Fw::DpContainer::MIN_PACKET_SIZE; | |
| 581 | |||
| 582 |
1/1✓ Branch 2 taken 6421 times.
|
6421 | stat = dpFile.read(dpBuff, size); |
| 583 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6421 times.
|
6421 | if (stat != Os::File::OP_OK) { |
| 584 | ✗ | this->log_WARNING_HI_FileReadError(fullFile, stat); | |
| 585 | ✗ | dpFile.close(); | |
| 586 | ✗ | return ProcessFileStatus::FAILED; | |
| 587 | } | ||
| 588 | |||
| 589 | // if full header and hashes aren't read, something's wrong with the file, so skip | ||
| 590 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6421 times.
|
6421 | if (size != Fw::DpContainer::MIN_PACKET_SIZE) { |
| 591 | ✗ | this->log_WARNING_HI_FileReadError(fullFile, Os::File::BAD_SIZE); | |
| 592 | ✗ | dpFile.close(); | |
| 593 | ✗ | return ProcessFileStatus::FAILED; | |
| 594 | } | ||
| 595 | |||
| 596 | // if all is well, don't need the file any more | ||
| 597 |
1/1✓ Branch 2 taken 6421 times.
|
6421 | dpFile.close(); |
| 598 | |||
| 599 | // give buffer to container instance | ||
| 600 |
1/1✓ Branch 2 taken 6421 times.
|
6421 | container.setBuffer(hdrBuff); |
| 601 | |||
| 602 | // make sure the header metadata matches its stored hash before trusting it | ||
| 603 |
1/1✓ Branch 2 taken 6421 times.
|
6421 | Utils::HashBuffer storedHash; |
| 604 |
1/1✓ Branch 2 taken 6421 times.
|
6421 | Utils::HashBuffer computedHash; |
| 605 |
1/1✓ Branch 2 taken 6421 times.
|
6421 | Fw::Success::T hashStatus = container.checkHeaderHash(storedHash, computedHash); |
| 606 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6420 times.
|
6421 | if (hashStatus != Fw::Success::SUCCESS) { |
| 607 |
4/4✓ Branch 5 taken 1 times.
✓ Branch 9 taken 1 times.
✓ Branch 13 taken 1 times.
✓ Branch 20 taken 1 times.
|
2 | this->log_WARNING_HI_FileHdrError(fullFile, DpHdrField::CRC, computedHash.asBigEndianU32(), |
| 608 | 1 | storedHash.asBigEndianU32()); | |
| 609 | 1 | return ProcessFileStatus::FAILED; | |
| 610 | } | ||
| 611 | |||
| 612 | // reset header deserialization in the container | ||
| 613 |
1/1✓ Branch 2 taken 6420 times.
|
6420 | Fw::SerializeStatus desStat = container.deserializeHeader(); |
| 614 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6420 times.
|
6420 | if (desStat != Fw::FW_SERIALIZE_OK) { |
| 615 | ✗ | this->log_WARNING_HI_FileHdrDesError(fullFile, desStat); | |
| 616 | ✗ | return ProcessFileStatus::FAILED; | |
| 617 | } | ||
| 618 | |||
| 619 | 6420 | const FwSizeType dataSize = container.getDataSize(); | |
| 620 | 6420 | const FwSizeType expectedDataSize = fileSize - Fw::DpContainer::MIN_PACKET_SIZE; | |
| 621 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6420 times.
|
6420 | if (dataSize != expectedDataSize) { |
| 622 | ✗ | this->log_WARNING_HI_FileReadError(fullFile, Os::File::BAD_SIZE); | |
| 623 | ✗ | return ProcessFileStatus::FAILED; | |
| 624 | } | ||
| 625 | |||
| 626 |
1/1✓ Branch 2 taken 6420 times.
|
6420 | Fw::FileNameString canonicalFileName; |
| 627 | Fw::FormatStatus canonicalFormatStatus = | ||
| 628 |
3/3✓ Branch 2 taken 6420 times.
✓ Branch 5 taken 6420 times.
✓ Branch 17 taken 6420 times.
|
19260 | canonicalFileName.format(DP_FILENAME_FORMAT, this->m_directories[dir].toChar(), container.getId(), |
| 629 |
2/2✓ Branch 2 taken 6420 times.
✓ Branch 9 taken 6420 times.
|
19260 | container.getTimeTag().getSeconds(), container.getTimeTag().getUSeconds()); |
| 630 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6420 times.
|
6420 | if (canonicalFormatStatus != Fw::FormatStatus::SUCCESS) { |
| 631 | ✗ | this->log_WARNING_HI_FileNameFormatError(fullFile, | |
| 632 | static_cast<Fw::StringFormatStatus::T>(canonicalFormatStatus)); | ||
| 633 | ✗ | return ProcessFileStatus::FAILED; | |
| 634 | } | ||
| 635 |
3/3✓ Branch 5 taken 6420 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 6419 times.
|
6420 | if (canonicalFileName != fullFile) { |
| 636 |
1/1✓ Branch 8 taken 1 times.
|
1 | this->log_WARNING_HI_InvalidFileName(fullFile, canonicalFileName); |
| 637 | 1 | return ProcessFileStatus::FAILED; | |
| 638 | } | ||
| 639 | |||
| 640 | // add entry to catalog. | ||
| 641 |
1/1✓ Branch 2 taken 6419 times.
|
6419 | DpStateEntry entry{}; |
| 642 | 6419 | entry.dir = static_cast<FwIndexType>(dir); | |
| 643 |
1/1✓ Branch 4 taken 6419 times.
|
6419 | entry.record.set_id(container.getId()); |
| 644 |
1/1✓ Branch 4 taken 6419 times.
|
6419 | entry.record.set_priority(container.getPriority()); |
| 645 |
2/2✓ Branch 3 taken 6419 times.
✓ Branch 10 taken 6419 times.
|
6419 | entry.record.set_state(container.getState()); |
| 646 |
3/3✓ Branch 3 taken 6419 times.
✓ Branch 9 taken 6419 times.
✓ Branch 12 taken 6419 times.
|
6419 | entry.record.set_tSec(container.getTimeTag().getSeconds()); |
| 647 |
3/3✓ Branch 3 taken 6419 times.
✓ Branch 9 taken 6419 times.
✓ Branch 12 taken 6419 times.
|
6419 | entry.record.set_tSub(container.getTimeTag().getUSeconds()); |
| 648 |
1/1✓ Branch 2 taken 6419 times.
|
6419 | entry.record.set_size(static_cast<U64>(fileSize)); |
| 649 | |||
| 650 | // check the state file to see if there is transmit state | ||
| 651 |
1/1✓ Branch 4 taken 6419 times.
|
6419 | this->getFileState(entry); |
| 652 | |||
| 653 | // skip a file the state file records as already transmitted | ||
| 654 |
2/2✓ Branch 2 taken 15 times.
✓ Branch 3 taken 6404 times.
|
6419 | if (entry.record.get_state() == Fw::DpState::TRANSMITTED) { |
| 655 |
1/1✓ Branch 8 taken 15 times.
|
15 | this->log_ACTIVITY_HI_DpFileSkipped(fullFile); |
| 656 | 15 | return ProcessFileStatus::FAILED; | |
| 657 | } | ||
| 658 | |||
| 659 | // a duplicate insert updates the tree in place; skip it so pending counters are not double-counted. | ||
| 660 | // The sort key includes the priority, which SET_DP_PRIORITY may have changed since the file was | ||
| 661 | // added, so a file already in the catalog is recognized by its stable identity, not by the key | ||
| 662 |
1/1✓ Branch 2 taken 6404 times.
|
6404 | DpStateEntry existing{}; |
| 663 |
3/3✓ Branch 2 taken 6404 times.
✓ Branch 11 taken 4 times.
✓ Branch 12 taken 6400 times.
|
6404 | if (this->findEntryByIdentity(entry, existing) == DpCatalog_EntryLookupStatus::FOUND) { |
| 664 |
1/1✓ Branch 5 taken 4 times.
|
4 | this->log_DIAGNOSTIC_DpDuplicate(entry.record); |
| 665 | 4 | return ProcessFileStatus::FAILED; | |
| 666 | } | ||
| 667 | |||
| 668 | // make sure there is a free slot before inserting, so a full catalog is reported as such | ||
| 669 | // and the entry is not left in the tree uncounted | ||
| 670 |
3/3✓ Branch 6 taken 6400 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 6399 times.
|
6400 | if (this->m_dpCatalog.getSize() >= this->m_numDpSlots) { |
| 671 |
1/1✓ Branch 5 taken 1 times.
|
1 | this->log_WARNING_HI_DpCatalogFull(entry.record); |
| 672 | 1 | return ProcessFileStatus::QUIT; | |
| 673 | } | ||
| 674 | |||
| 675 | // insert into the sorted catalog. A free slot was verified above, so a failure here is a tree | ||
| 676 | // error, not a full catalog | ||
| 677 |
1/1✓ Branch 4 taken 6399 times.
|
6399 | bool inserted = this->insertEntry(entry); |
| 678 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6399 times.
|
6399 | if (!inserted) { |
| 679 | ✗ | this->log_WARNING_HI_DpInsertError(entry.record); | |
| 680 | ✗ | return ProcessFileStatus::QUIT; | |
| 681 | } | ||
| 682 | |||
| 683 | // increment our counters | ||
| 684 | 6399 | this->m_pendingFiles++; | |
| 685 | 6399 | this->m_pendingDpBytes += entry.record.get_size(); | |
| 686 | |||
| 687 |
1/1✓ Branch 5 taken 6399 times.
|
6399 | this->log_ACTIVITY_HI_DpFileAdded(canonicalFileName); |
| 688 | |||
| 689 | // No need to track iterator state - begin() always gives us the highest priority entry | ||
| 690 | // and we remove entries as we transmit them | ||
| 691 | |||
| 692 | 6399 | return ProcessFileStatus::SUCCESS; | |
| 693 | 6422 | } | |
| 694 | |||
| 695 | // ---------------------------------------------------------------------- | ||
| 696 | // DpStateEntry Comparison Ops | ||
| 697 | // ---------------------------------------------------------------------- | ||
| 698 | 1659980 | I8 DpCatalog::DpStateEntry::compareEntries(const DpStateEntry& left, const DpStateEntry& right) { | |
| 699 | // check priority. Lower is higher priority | ||
| 700 |
2/2✓ Branch 22 taken 606317 times.
✓ Branch 23 taken 1053663 times.
|
1659980 | if (left.record.get_priority() < right.record.get_priority()) { |
| 701 | 606317 | return -1; | |
| 702 |
2/2✓ Branch 22 taken 305819 times.
✓ Branch 23 taken 747844 times.
|
1053663 | } else if (left.record.get_priority() > right.record.get_priority()) { |
| 703 | 305819 | return 1; | |
| 704 | } | ||
| 705 | |||
| 706 | // check time. Older is higher priority | ||
| 707 |
2/2✓ Branch 22 taken 239314 times.
✓ Branch 23 taken 508530 times.
|
747844 | else if (left.record.get_tSec() < right.record.get_tSec()) { |
| 708 | 239314 | return -1; | |
| 709 |
2/2✓ Branch 22 taken 120057 times.
✓ Branch 23 taken 388473 times.
|
508530 | } else if (left.record.get_tSec() > right.record.get_tSec()) { |
| 710 | 120057 | return 1; | |
| 711 | } | ||
| 712 | |||
| 713 | // check subsecond time. Older is higher priority | ||
| 714 |
2/2✓ Branch 22 taken 2 times.
✓ Branch 23 taken 388471 times.
|
388473 | else if (left.record.get_tSub() < right.record.get_tSub()) { |
| 715 | 2 | return -1; | |
| 716 |
2/2✓ Branch 22 taken 1 times.
✓ Branch 23 taken 388470 times.
|
388471 | } else if (left.record.get_tSub() > right.record.get_tSub()) { |
| 717 | 1 | return 1; | |
| 718 | } | ||
| 719 | |||
| 720 | // check ID. Lower is higher priority | ||
| 721 |
2/2✓ Branch 22 taken 175473 times.
✓ Branch 23 taken 212997 times.
|
388470 | else if (left.record.get_id() < right.record.get_id()) { |
| 722 | 175473 | return -1; | |
| 723 |
2/2✓ Branch 22 taken 136639 times.
✓ Branch 23 taken 76358 times.
|
212997 | } else if (left.record.get_id() > right.record.get_id()) { |
| 724 | 136639 | return 1; | |
| 725 | } | ||
| 726 | |||
| 727 | // check directory. A file of the same name in two configured directories is two products, and the | ||
| 728 | // key includes the directory so that a priority change can never move one onto the other's key | ||
| 729 |
2/2✓ Branch 2 taken 4 times.
✓ Branch 3 taken 76354 times.
|
76358 | else if (left.dir < right.dir) { |
| 730 | 4 | return -1; | |
| 731 |
2/2✓ Branch 2 taken 2 times.
✓ Branch 3 taken 76352 times.
|
76354 | } else if (left.dir > right.dir) { |
| 732 | 2 | return 1; | |
| 733 | } | ||
| 734 | |||
| 735 | // all fields equal: the same product | ||
| 736 | else { | ||
| 737 | 76352 | return 0; | |
| 738 | } | ||
| 739 | } | ||
| 740 | |||
| 741 | 273006 | bool DpCatalog::DpStateEntry::hasIdentity(FwDpIdType id, U32 tSec, U32 tSub) const { | |
| 742 |
6/6✓ Branch 11 taken 8167 times.
✓ Branch 12 taken 264839 times.
✓ Branch 24 taken 6166 times.
✓ Branch 25 taken 2001 times.
✓ Branch 37 taken 6165 times.
✓ Branch 38 taken 1 times.
|
273006 | return (this->record.get_id() == id) && (this->record.get_tSec() == tSec) && (this->record.get_tSub() == tSub); |
| 743 | } | ||
| 744 | |||
| 745 | 523098 | bool DpCatalog::DpStateEntry::isSameProduct(const DpStateEntry& other) const { | |
| 746 |
4/4✓ Branch 2 taken 272967 times.
✓ Branch 3 taken 250131 times.
✓ Branch 4 taken 6151 times.
✓ Branch 5 taken 266816 times.
|
796065 | return (this->dir == other.dir) && |
| 747 | 796065 | this->hasIdentity(other.record.get_id(), other.record.get_tSec(), other.record.get_tSub()); | |
| 748 | } | ||
| 749 | |||
| 750 | 635129 | bool DpCatalog::DpStateEntry::operator==(const DpStateEntry& other) const { | |
| 751 | 635129 | return compareEntries(*this, other) == 0; | |
| 752 | } | ||
| 753 | 1 | bool DpCatalog::DpStateEntry::operator!=(const DpStateEntry& other) const { | |
| 754 | 1 | return compareEntries(*this, other) != 0; | |
| 755 | } | ||
| 756 | |||
| 757 | 1 | bool DpCatalog::DpStateEntry::operator>(const DpStateEntry& other) const { | |
| 758 | 1 | return compareEntries(*this, other) > 0; | |
| 759 | } | ||
| 760 | 1024849 | bool DpCatalog::DpStateEntry::operator<(const DpStateEntry& other) const { | |
| 761 | 1024849 | return compareEntries(*this, other) < 0; | |
| 762 | } | ||
| 763 | |||
| 764 | 67210 | bool DpCatalog::insertEntry(DpStateEntry& entry) { | |
| 765 | // Insert into the RedBlackTreeSet | ||
| 766 | // The tree maintains sorting by priority, time, ID, and directory via DpStateEntry comparison operators | ||
| 767 |
1/1✓ Branch 5 taken 67210 times.
|
67210 | Fw::Success status = this->m_dpCatalog.insert(entry); |
| 768 | 134420 | return (status == Fw::Success::SUCCESS); | |
| 769 | 67210 | } | |
| 770 | |||
| 771 | 6283 | void DpCatalog::sendNextEntry() { | |
| 772 | // Use xmit flag to break upon STOP_XMIT_CATALOG | ||
| 773 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 6283 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 6281 times.
|
6283 | if (this->m_xmitInProgress != true) { |
| 774 | 2 | return; | |
| 775 | } | ||
| 776 | // A send is still in flight (START_XMIT_CATALOG after a STOP, before the file completed): its | ||
| 777 | // fileDone resumes the walk, so do not re-send the entry that is still in the catalog (#5777) | ||
| 778 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 6281 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 6279 times.
|
6281 | if (this->m_hasCurrentXmit) { |
| 779 | 2 | return; | |
| 780 | } | ||
| 781 | |||
| 782 | // Look for the next entry to send | ||
| 783 |
1/1✓ Branch 2 taken 6279 times.
|
6279 | DpStateEntry entry; |
| 784 |
3/3✓ Branch 4 taken 6279 times.
✓ Branch 6 taken 157 times.
✓ Branch 7 taken 6122 times.
|
6279 | if (!this->findNextEntry(entry)) { |
| 785 | // if no entry found, we are done | ||
| 786 | 157 | this->m_xmitInProgress = false; | |
| 787 |
1/1✓ Branch 9 taken 157 times.
|
157 | this->log_ACTIVITY_HI_CatalogXmitCompleted(this->m_xmitBytes); |
| 788 |
2/2✓ Branch 5 taken 157 times.
✓ Branch 8 taken 157 times.
|
157 | this->dispatchWaitedResponse(Fw::CmdResponse::OK); |
| 789 | 157 | return; | |
| 790 | } | ||
| 791 | |||
| 792 | // Save current entry for fileDone_handler | ||
| 793 |
1/1✓ Branch 4 taken 6122 times.
|
6122 | this->m_currentXmitEntry = entry; |
| 794 | 6122 | this->m_hasCurrentXmit = true; | |
| 795 | |||
| 796 | // Build file name based on the found entry | ||
| 797 | Fw::FormatStatus formatStatus = | ||
| 798 |
1/1✓ Branch 16 taken 6122 times.
|
24488 | this->m_currXmitFileName.format(DP_FILENAME_FORMAT, this->m_directories[entry.dir].toChar(), |
| 799 | 18366 | entry.record.get_id(), entry.record.get_tSec(), entry.record.get_tSub()); | |
| 800 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6122 times.
|
6122 | if (formatStatus != Fw::FormatStatus::SUCCESS) { |
| 801 | ✗ | this->log_WARNING_HI_FileNameFormatError(this->m_currXmitFileName, | |
| 802 | static_cast<Fw::StringFormatStatus::T>(formatStatus)); | ||
| 803 | // No send is in flight, so no fileDone will arrive: abort the transmit | ||
| 804 | // rather than leaving it wedged in progress | ||
| 805 | ✗ | this->abortXmit(Fw::CmdResponse::EXECUTION_ERROR); | |
| 806 | ✗ | return; | |
| 807 | } | ||
| 808 |
1/1✓ Branch 11 taken 6122 times.
|
12244 | this->log_ACTIVITY_LO_SendingProduct(this->m_currXmitFileName, static_cast<U32>(entry.record.get_size()), |
| 809 | 6122 | entry.record.get_priority()); | |
| 810 |
1/1✓ Branch 9 taken 6122 times.
|
6122 | Svc::SendFileResponse resp = this->fileOut_out(0, this->m_currXmitFileName, this->m_currXmitFileName, 0, 0); |
| 811 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 6122 times.
|
6122 | if (resp.get_status() != Svc::SendFileStatus::STATUS_OK) { |
| 812 | ✗ | this->log_WARNING_HI_DpFileSendError(this->m_currXmitFileName, resp.get_status()); | |
| 813 | // A rejected send produces no fileDone callback: abort the transmit | ||
| 814 | // rather than leaving it wedged in progress | ||
| 815 | ✗ | this->abortXmit(Fw::CmdResponse::EXECUTION_ERROR); | |
| 816 | ✗ | return; | |
| 817 | } | ||
| 818 | // FileDownlink echoes this context in fileDone; it identifies this send (#5777) | ||
| 819 | 6122 | this->m_currXmitContext = resp.get_context(); | |
| 820 | 6279 | } // end sendNextEntry() | |
| 821 | |||
| 822 | static_assert(sizeof(FwDpPriorityType) <= sizeof(U32), | ||
| 823 | "DpRecord stores priority as U32; a wider FwDpPriorityType would be truncated in the catalog"); | ||
| 824 | |||
| 825 | 63404 | bool DpCatalog::findNextEntry(DpStateEntry& entry) { | |
| 826 | // Entries are ordered by ascending priority value (begin() returns the most urgent) and are removed | ||
| 827 | // as they are transmitted, so the next entry to send is the first one at or after m_xmitStartPriority. | ||
| 828 | // Entries before the range are skipped (not removed) so a later START_XMIT_CATALOG can still send | ||
| 829 | // them; once an entry past m_xmitEndPriority is reached nothing further can be in range. | ||
| 830 |
1/1✓ Branch 6 taken 63404 times.
|
63404 | const FwSizeType size = this->m_dpCatalog.getSize(); |
| 831 |
1/1✓ Branch 4 taken 63404 times.
|
63404 | typename Fw::RedBlackTreeSet<DpStateEntry, DP_MAX_FILES>::ConstIterator iter = this->m_dpCatalog.begin(); |
| 832 | // index gives the walk a fixed upper bound (catalog size); the iterator check is the real end condition | ||
| 833 |
12/17✓ Branch 1 taken 11 times.
✓ Branch 3 taken 62258 times.
✓ Branch 4 taken 1157 times.
✓ Branch 9 taken 62258 times.
✓ Branch 13 taken 62258 times.
✓ Branch 15 taken 62258 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 62258 times.
✓ Branch 18 taken 1157 times.
✓ Branch 20 taken 62258 times.
✓ Branch 21 taken 1157 times.
✓ Branch 23 taken 62258 times.
✓ Branch 24 taken 1157 times.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
|
63426 | for (FwSizeType index = 0; (index < size) && (iter != this->m_dpCatalog.end()); index++, ++iter) { |
| 834 |
1/1✓ Branch 1 taken 62258 times.
|
62258 | const FwDpPriorityType priority = (*iter).record.get_priority(); |
| 835 |
2/2✓ Branch 4 taken 11 times.
✓ Branch 5 taken 62247 times.
|
62258 | if (priority < this->m_xmitStartPriority) { |
| 836 | 11 | continue; | |
| 837 | } | ||
| 838 |
2/2✓ Branch 4 taken 9 times.
✓ Branch 5 taken 62238 times.
|
62247 | if (priority > this->m_xmitEndPriority) { |
| 839 | 9 | break; | |
| 840 | } | ||
| 841 |
2/2✓ Branch 1 taken 62238 times.
✓ Branch 5 taken 62238 times.
|
62238 | entry = *iter; |
| 842 | 62238 | return true; | |
| 843 | } | ||
| 844 | |||
| 845 | 1166 | return false; | |
| 846 | 63404 | } | |
| 847 | |||
| 848 | 3734 | bool DpCatalog::checkInit() { | |
| 849 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 3734 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 3732 times.
|
3734 | if (not this->m_initialized) { |
| 850 | 2 | this->log_WARNING_HI_ComponentNotInitialized(); | |
| 851 | 2 | return false; | |
| 852 |
1/2✗ Branch 4 not taken.
✓ Branch 5 taken 3732 times.
|
3732 | } else if (0 == this->m_numDpSlots) { |
| 853 | ✗ | this->log_WARNING_HI_ComponentNoMemory(); | |
| 854 | ✗ | return false; | |
| 855 | } | ||
| 856 | |||
| 857 | 3732 | return true; | |
| 858 | } | ||
| 859 | |||
| 860 | 662 | void DpCatalog::shutdown() { | |
| 861 | // only try to deallocate if both pointers are non-zero | ||
| 862 | // it's a way to more gracefully shut down if there are missing | ||
| 863 | // pointers | ||
| 864 |
2/4✓ Branch 4 taken 662 times.
✗ Branch 5 not taken.
✓ Branch 10 taken 662 times.
✗ Branch 11 not taken.
|
662 | if ((this->m_allocator != nullptr) and (this->m_memPtr != nullptr)) { |
| 865 | 662 | this->m_allocator->deallocate(this->m_allocatorId, this->m_memPtr); | |
| 866 | } | ||
| 867 | 662 | } | |
| 868 | |||
| 869 | // ---------------------------------------------------------------------- | ||
| 870 | // Handler implementations for user-defined typed input ports | ||
| 871 | // ---------------------------------------------------------------------- | ||
| 872 | |||
| 873 | 6132 | void DpCatalog ::fileDone_handler(FwIndexType portNum, const Svc::SendFileResponse& resp) { | |
| 874 | // Accept only the fileDone for the send in flight (matching FileDownlink context); anything | ||
| 875 | // else is a late callback from an abandoned send (#5777) and must not touch the current transmit | ||
| 876 |
7/8✗ Branch 3 not taken.
✓ Branch 4 taken 6132 times.
✓ Branch 5 taken 6126 times.
✓ Branch 6 taken 6 times.
✓ Branch 15 taken 11 times.
✓ Branch 16 taken 6115 times.
✓ Branch 17 taken 17 times.
✓ Branch 18 taken 6115 times.
|
6132 | if (!this->m_hasCurrentXmit || resp.get_context() != this->m_currXmitContext) { |
| 877 |
2/2✓ Branch 10 taken 17 times.
✓ Branch 18 taken 17 times.
|
17 | this->log_WARNING_LO_StaleFileDone(resp.get_context(), resp.get_status()); |
| 878 | 17 | return; | |
| 879 | } | ||
| 880 | |||
| 881 | // check file status | ||
| 882 |
2/2✓ Branch 4 taken 2 times.
✓ Branch 5 taken 6113 times.
|
6115 | if (resp.get_status() != Svc::SendFileStatus::STATUS_OK) { |
| 883 |
2/2✓ Branch 10 taken 2 times.
✓ Branch 17 taken 2 times.
|
2 | this->log_WARNING_HI_DpFileXmitError(this->m_currXmitFileName, resp.get_status()); |
| 884 |
2/2✓ Branch 5 taken 2 times.
✓ Branch 8 taken 2 times.
|
2 | this->abortXmit(Fw::CmdResponse::EXECUTION_ERROR); |
| 885 | 2 | return; | |
| 886 | } | ||
| 887 | |||
| 888 | // Reduce pending | ||
| 889 | 6113 | this->m_pendingDpBytes -= this->m_currentXmitEntry.record.get_size(); | |
| 890 | 6113 | this->m_pendingFiles--; | |
| 891 | // Log File Complete & pending | ||
| 892 |
1/1✓ Branch 16 taken 6113 times.
|
6113 | this->log_ACTIVITY_LO_ProductComplete(this->m_currXmitFileName, this->m_pendingFiles, this->m_pendingDpBytes); |
| 893 | |||
| 894 | // mark the entry as transmitted | ||
| 895 |
1/1✓ Branch 6 taken 6113 times.
|
6113 | this->m_currentXmitEntry.record.set_state(Fw::DpState::TRANSMITTED); |
| 896 | // update the transmitted state in the state file data, so a later rewrite of the state file | ||
| 897 | // keeps it (a full table is reported by the update), and in the state file | ||
| 898 |
1/1✓ Branch 5 taken 6113 times.
|
6113 | (void)this->updateStateFileData(this->m_currentXmitEntry); |
| 899 |
1/1✓ Branch 7 taken 6113 times.
|
6113 | this->appendFileState(this->m_currentXmitEntry); |
| 900 | // add the size | ||
| 901 | 6113 | this->m_xmitBytes += this->m_currentXmitEntry.record.get_size(); | |
| 902 | |||
| 903 | // Remove from catalog. The entry is located by its stable identity rather than by the copy kept | ||
| 904 | // for the send, whose sort key may be stale if the priority changed during the send. | ||
| 905 | // Not ground-reachable: only resetCatalog empties the set, and it also clears m_hasCurrentXmit (checked above) | ||
| 906 |
1/1✓ Branch 2 taken 6113 times.
|
6113 | DpStateEntry catalogEntry{}; |
| 907 |
1/1✓ Branch 5 taken 6113 times.
|
6113 | const DpCatalog_EntryLookupStatus found = this->findEntryByIdentity(this->m_currentXmitEntry, catalogEntry); |
| 908 | 6113 | FW_ASSERT(found == DpCatalog_EntryLookupStatus::FOUND, static_cast<FwAssertArgType>(found.e)); | |
| 909 | // catalogEntry is a copy of a set element, so its key is present | ||
| 910 |
1/1✓ Branch 4 taken 6113 times.
|
6113 | const Fw::Success status = this->m_dpCatalog.remove(catalogEntry); |
| 911 | 6113 | FW_ASSERT(status == Fw::Success::SUCCESS, static_cast<FwAssertArgType>(status)); | |
| 912 | |||
| 913 | 6113 | this->m_hasCurrentXmit = false; | |
| 914 | |||
| 915 | // send the next entry, if it exists | ||
| 916 |
1/1✓ Branch 4 taken 6113 times.
|
6113 | this->sendNextEntry(); |
| 917 | 6113 | } | |
| 918 | |||
| 919 | 1 | void DpCatalog ::pingIn_handler(FwIndexType portNum, U32 key) { | |
| 920 | // return code for health ping | ||
| 921 | 1 | this->pingOut_out(0, key); | |
| 922 | 1 | } | |
| 923 | |||
| 924 | 3391 | void DpCatalog ::addToCat_handler(FwIndexType portNum, | |
| 925 | const Fw::StringBase& fileName, | ||
| 926 | FwDpPriorityType priority, | ||
| 927 | FwSizeType size) { | ||
| 928 | // check initialization | ||
| 929 |
1/2✗ Branch 4 not taken.
✓ Branch 5 taken 3391 times.
|
3391 | if (not this->checkInit()) { |
| 930 | ✗ | return; | |
| 931 | } | ||
| 932 | |||
| 933 | // check that initialization got memory | ||
| 934 |
1/2✗ Branch 4 not taken.
✓ Branch 5 taken 3391 times.
|
3391 | if (0 == this->m_numDpSlots) { |
| 935 | ✗ | this->log_WARNING_HI_NoDpMemory(); | |
| 936 | ✗ | return; | |
| 937 | } | ||
| 938 | |||
| 939 | // Check the catalog has been built | ||
| 940 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 3391 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 3389 times.
|
3391 | if (not this->m_catalogBuilt) { |
| 941 | 2 | this->log_ACTIVITY_HI_NotLoaded(fileName); | |
| 942 | 2 | return; | |
| 943 | } | ||
| 944 | |||
| 945 | // Both of these are grabbed from the header | ||
| 946 | (void)priority; | ||
| 947 | (void)size; | ||
| 948 | |||
| 949 | // Since this is a runtime addition | ||
| 950 | // Check if file is in one of our directories | ||
| 951 |
2/2✓ Branch 8 taken 3389 times.
✓ Branch 12 taken 3389 times.
|
3389 | FwSizeType dir = this->determineDirectory(fileName); |
| 952 | |||
| 953 | // Not in one of our directories; skip this file | ||
| 954 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3389 times.
|
3389 | if (dir == DP_MAX_DIRECTORIES) { |
| 955 | ✗ | this->log_WARNING_HI_DirectoryNotManaged(fileName); | |
| 956 | ✗ | return; | |
| 957 | } | ||
| 958 | |||
| 959 |
2/2✓ Branch 8 taken 3389 times.
✓ Branch 12 taken 3389 times.
|
3389 | const ProcessFileStatus ret = processFile(fileName, dir); |
| 960 | |||
| 961 |
2/2✓ Branch 0 taken 3383 times.
✓ Branch 1 taken 6 times.
|
3389 | if (ret == ProcessFileStatus::SUCCESS) { |
| 962 | // If we already finished (or were stopped), resume only if m_remainActive and findNextEntry sees a | ||
| 963 | // pending entry (the new product or one left behind) inside the active priority range. Probing first | ||
| 964 | // avoids the CatalogXmitCompleted that sendNextEntry would report for an empty range. | ||
| 965 |
6/8✗ Branch 3 not taken.
✓ Branch 4 taken 3383 times.
✓ Branch 5 taken 15 times.
✓ Branch 6 taken 3368 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 15 times.
✓ Branch 12 taken 13 times.
✓ Branch 13 taken 2 times.
|
3383 | if (!this->m_xmitInProgress && this->m_remainActive) { |
| 966 |
1/1✓ Branch 2 taken 13 times.
|
13 | DpStateEntry nextEntry{}; |
| 967 |
3/3✓ Branch 4 taken 13 times.
✓ Branch 6 taken 12 times.
✓ Branch 7 taken 1 times.
|
13 | if (this->findNextEntry(nextEntry)) { |
| 968 | 12 | this->m_xmitInProgress = true; | |
| 969 |
1/1✓ Branch 4 taken 12 times.
|
12 | this->sendNextEntry(); |
| 970 | } | ||
| 971 | 13 | } | |
| 972 | // Otherwise, the fileDone of the file in flight invokes sendNextEntry, which finds the right file, | ||
| 973 | // or the product is transmitted by the next transmit command | ||
| 974 | |||
| 975 | // The state file is not rewritten here: a newly written product has no transmit state to | ||
| 976 | // record, and pruneAndWriteStateFile() would discard the TRANSMITTED records appended by | ||
| 977 | // fileDone since the catalog was built. | ||
| 978 | } | ||
| 979 | } | ||
| 980 | |||
| 981 | // ---------------------------------------------------------------------- | ||
| 982 | // Handler implementations for commands | ||
| 983 | // ---------------------------------------------------------------------- | ||
| 984 | |||
| 985 | 161 | void DpCatalog ::BUILD_CATALOG_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { | |
| 986 | // invoke helper | ||
| 987 |
2/2✓ Branch 6 taken 161 times.
✓ Branch 9 taken 161 times.
|
161 | this->cmdResponse_out(opCode, cmdSeq, this->doCatalogBuild()); |
| 988 | 161 | } | |
| 989 | |||
| 990 | 146 | void DpCatalog ::START_XMIT_CATALOG_cmdHandler(FwOpcodeType opCode, | |
| 991 | U32 cmdSeq, | ||
| 992 | const Fw::Wait& wait, | ||
| 993 | bool remainActive) { | ||
| 994 | 146 | this->startXmitCmd(opCode, cmdSeq, wait, remainActive, 0, std::numeric_limits<FwDpPriorityType>::max()); | |
| 995 | 146 | } | |
| 996 | |||
| 997 | 16 | void DpCatalog ::START_XMIT_CATALOG_WITH_PRIORITY_cmdHandler(FwOpcodeType opCode, | |
| 998 | U32 cmdSeq, | ||
| 999 | const Fw::Wait& wait, | ||
| 1000 | bool remainActive, | ||
| 1001 | FwDpPriorityType startPriority, | ||
| 1002 | FwDpPriorityType endPriority) { | ||
| 1003 | 16 | this->startXmitCmd(opCode, cmdSeq, wait, remainActive, startPriority, endPriority); | |
| 1004 | 16 | } | |
| 1005 | |||
| 1006 | 162 | void DpCatalog::startXmitCmd(FwOpcodeType opCode, | |
| 1007 | U32 cmdSeq, | ||
| 1008 | const Fw::Wait& wait, | ||
| 1009 | bool remainActive, | ||
| 1010 | FwDpPriorityType startPriority, | ||
| 1011 | FwDpPriorityType endPriority) { | ||
| 1012 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 161 times.
|
162 | if (startPriority > endPriority) { |
| 1013 |
1/1✓ Branch 5 taken 1 times.
|
1 | this->log_WARNING_LO_XmitPriorityRangeInvalid(startPriority, endPriority); |
| 1014 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
|
1 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR); |
| 1015 | 1 | return; | |
| 1016 | } | ||
| 1017 | 161 | this->m_remainActive = remainActive; | |
| 1018 | |||
| 1019 | // Arm the waited response before starting: an empty catalog completes the | ||
| 1020 | // transmit inside doCatalogXmit and must still answer a waited command | ||
| 1021 |
2/2✓ Branch 4 taken 76 times.
✓ Branch 5 taken 85 times.
|
161 | if (Fw::Wait::WAIT == wait) { |
| 1022 | 76 | this->m_xmitCmdWait = true; | |
| 1023 | 76 | this->m_xmitOpCode = opCode; | |
| 1024 | 76 | this->m_xmitCmdSeq = cmdSeq; | |
| 1025 | } | ||
| 1026 | |||
| 1027 |
1/1✓ Branch 2 taken 161 times.
|
161 | Fw::CmdResponse resp = this->doCatalogXmit(startPriority, endPriority); |
| 1028 | 161 | FW_ASSERT(resp.isValid(), static_cast<FwAssertArgType>(resp.e)); | |
| 1029 | |||
| 1030 |
2/2✓ Branch 2 taken 3 times.
✓ Branch 3 taken 158 times.
|
161 | if (resp != Fw::CmdResponse::OK) { |
| 1031 | 3 | this->m_xmitCmdWait = false; | |
| 1032 | 3 | this->m_xmitOpCode = 0; | |
| 1033 | 3 | this->m_xmitCmdSeq = 0; | |
| 1034 |
2/2✓ Branch 6 taken 3 times.
✓ Branch 9 taken 3 times.
|
3 | this->cmdResponse_out(opCode, cmdSeq, resp); |
| 1035 |
2/2✓ Branch 4 taken 83 times.
✓ Branch 5 taken 75 times.
|
158 | } else if (Fw::Wait::NO_WAIT == wait) { |
| 1036 |
2/2✓ Branch 6 taken 83 times.
✓ Branch 9 taken 83 times.
|
83 | this->cmdResponse_out(opCode, cmdSeq, resp); |
| 1037 | } | ||
| 1038 | 161 | } | |
| 1039 | |||
| 1040 | 161 | Fw::CmdResponse DpCatalog::doCatalogXmit(FwDpPriorityType startPriority, FwDpPriorityType endPriority) { | |
| 1041 | 161 | FW_ASSERT(startPriority <= endPriority, static_cast<FwAssertArgType>(startPriority), | |
| 1042 | static_cast<FwAssertArgType>(endPriority)); | ||
| 1043 | // check initialization | ||
| 1044 |
2/2✓ Branch 4 taken 1 times.
✓ Branch 5 taken 160 times.
|
161 | if (not this->checkInit()) { |
| 1045 | 1 | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 1046 | } | ||
| 1047 | |||
| 1048 | // check that initialization got memory | ||
| 1049 |
1/2✗ Branch 4 not taken.
✓ Branch 5 taken 160 times.
|
160 | if (0 == this->m_numDpSlots) { |
| 1050 | ✗ | this->log_WARNING_HI_NoDpMemory(); | |
| 1051 | ✗ | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 1052 | } | ||
| 1053 | |||
| 1054 | // make sure a downlink is not in progress | ||
| 1055 |
2/4✗ Branch 3 not taken.
✓ Branch 4 taken 160 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 160 times.
|
160 | if (this->m_xmitInProgress) { |
| 1056 | ✗ | this->log_WARNING_LO_DpXmitInProgress(); | |
| 1057 | ✗ | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 1058 | } | ||
| 1059 | |||
| 1060 | // Check the catalog has been built | ||
| 1061 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 160 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 158 times.
|
160 | if (not this->m_catalogBuilt) { |
| 1062 | 2 | this->log_WARNING_HI_XmitUnbuiltCatalog(); | |
| 1063 | 2 | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 1064 | } | ||
| 1065 | |||
| 1066 | // start transmission; a START that resumes a send left in flight by STOP keeps the | ||
| 1067 | // session's byte tally, so CatalogXmitCompleted reports the whole session | ||
| 1068 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 158 times.
✓ Branch 5 taken 156 times.
✓ Branch 6 taken 2 times.
|
158 | if (!this->m_hasCurrentXmit) { |
| 1069 | 156 | this->m_xmitBytes = 0; | |
| 1070 | } | ||
| 1071 | 158 | this->m_xmitStartPriority = startPriority; | |
| 1072 | 158 | this->m_xmitEndPriority = endPriority; | |
| 1073 | 158 | this->log_ACTIVITY_HI_CatalogXmitRangeStarted(startPriority, endPriority); | |
| 1074 | 158 | this->m_xmitInProgress = true; | |
| 1075 | // Step 3b - search for and send first entry | ||
| 1076 | 158 | this->sendNextEntry(); | |
| 1077 | 158 | return Fw::CmdResponse::OK; | |
| 1078 | } | ||
| 1079 | |||
| 1080 | 10 | void DpCatalog ::STOP_XMIT_CATALOG_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { | |
| 1081 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 9 times.
|
10 | if (not this->m_xmitInProgress) { |
| 1082 | 1 | this->log_WARNING_LO_XmitNotActive(); | |
| 1083 | // benign error, so don't fail the command | ||
| 1084 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
|
1 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); |
| 1085 | } else { | ||
| 1086 | 9 | this->log_ACTIVITY_HI_CatalogXmitStopped(this->m_xmitBytes); | |
| 1087 | // Disarm xmitInProgress so sendNextEntry stops; keep hasCurrentXmit so the | ||
| 1088 | // in-flight file's fileDone is still recorded (the context check rejects any other) | ||
| 1089 | 9 | this->m_xmitInProgress = false; | |
| 1090 | // Respond to original cmd to start xmit | ||
| 1091 | // (if we haven't already) | ||
| 1092 |
2/2✓ Branch 5 taken 9 times.
✓ Branch 8 taken 9 times.
|
9 | this->dispatchWaitedResponse(Fw::CmdResponse::OK); |
| 1093 | |||
| 1094 | // Respond to this command | ||
| 1095 |
2/2✓ Branch 6 taken 9 times.
✓ Branch 9 taken 9 times.
|
9 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); |
| 1096 | } | ||
| 1097 | 10 | } | |
| 1098 | |||
| 1099 | 6 | void DpCatalog ::CLEAR_CATALOG_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { | |
| 1100 | // Dropping the send in flight closes the transmit session here, as STOP does, so a waited | ||
| 1101 | // START_XMIT_CATALOG is answered now and the next BUILD/START is not refused as in progress | ||
| 1102 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 5 times.
|
6 | if (this->m_xmitInProgress) { |
| 1103 |
2/2✓ Branch 5 taken 1 times.
✓ Branch 8 taken 1 times.
|
1 | this->abortXmit(Fw::CmdResponse::EXECUTION_ERROR); |
| 1104 | } | ||
| 1105 | 6 | this->log_ACTIVITY_HI_CatalogCleared(this->m_pendingFiles, this->m_pendingDpBytes); | |
| 1106 | 6 | this->resetCatalog(); | |
| 1107 | 6 | this->resetStateFileData(); | |
| 1108 | |||
| 1109 |
2/2✓ Branch 6 taken 6 times.
✓ Branch 9 taken 6 times.
|
6 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); |
| 1110 | 6 | } | |
| 1111 | |||
| 1112 | 169 | void DpCatalog ::dispatchWaitedResponse(Fw::CmdResponse response) { | |
| 1113 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 169 times.
✓ Branch 5 taken 75 times.
✓ Branch 6 taken 94 times.
|
169 | if (this->m_xmitCmdWait) { |
| 1114 |
2/2✓ Branch 6 taken 75 times.
✓ Branch 17 taken 75 times.
|
75 | this->cmdResponse_out(this->m_xmitOpCode, this->m_xmitCmdSeq, response); |
| 1115 | |||
| 1116 | // Prevent a Duplicate Cmd Response | ||
| 1117 | 75 | this->m_xmitCmdWait = false; | |
| 1118 | 75 | this->m_xmitOpCode = 0; | |
| 1119 | 75 | this->m_xmitCmdSeq = 0; | |
| 1120 | } | ||
| 1121 | 169 | } | |
| 1122 | |||
| 1123 | 3 | void DpCatalog ::abortXmit(Fw::CmdResponse response) { | |
| 1124 | 3 | this->m_hasCurrentXmit = false; | |
| 1125 | 3 | this->m_xmitInProgress = false; | |
| 1126 |
2/2✓ Branch 5 taken 3 times.
✓ Branch 8 taken 3 times.
|
3 | this->dispatchWaitedResponse(response); |
| 1127 | 3 | } | |
| 1128 | |||
| 1129 | 21 | void DpCatalog ::SET_DP_PRIORITY_cmdHandler(FwOpcodeType opCode, | |
| 1130 | U32 cmdSeq, | ||
| 1131 | FwDpIdType id, | ||
| 1132 | U32 tSec, | ||
| 1133 | U32 tSub, | ||
| 1134 | FwDpPriorityType priority) { | ||
| 1135 |
3/3✓ Branch 4 taken 21 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 20 times.
|
21 | if (not this->checkInit()) { |
| 1136 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
|
1 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR); |
| 1137 | 1 | return; | |
| 1138 | } | ||
| 1139 | |||
| 1140 |
1/1✓ Branch 2 taken 20 times.
|
20 | DpStateEntry entry{}; |
| 1141 |
3/3✓ Branch 2 taken 20 times.
✓ Branch 11 taken 6 times.
✓ Branch 12 taken 14 times.
|
20 | if (this->findProductEntry(id, tSec, tSub, entry) == DpCatalog_EntryLookupStatus::NOT_FOUND) { |
| 1142 |
1/1✓ Branch 5 taken 6 times.
|
6 | this->log_WARNING_HI_DpNotFound(id, tSec, tSub); |
| 1143 |
2/2✓ Branch 6 taken 6 times.
✓ Branch 9 taken 6 times.
|
6 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR); |
| 1144 | 6 | return; | |
| 1145 | } | ||
| 1146 | |||
| 1147 |
1/1✓ Branch 2 taken 14 times.
|
14 | const DpCatalog_PriorityChangeStatus status = this->setDpPriority(entry, priority); |
| 1148 |
4/4✓ Branch 5 taken 2 times.
✓ Branch 6 taken 12 times.
✓ Branch 8 taken 14 times.
✓ Branch 11 taken 14 times.
|
28 | this->cmdResponse_out(opCode, cmdSeq, |
| 1149 | 14 | (status == DpCatalog_PriorityChangeStatus::NOT_RECORDED) ? Fw::CmdResponse::EXECUTION_ERROR | |
| 1150 | : Fw::CmdResponse::OK); | ||
| 1151 | 20 | } | |
| 1152 | |||
| 1153 | 14 | DpCatalog_PriorityChangeStatus DpCatalog ::setDpPriority(DpStateEntry& entry, FwDpPriorityType priority) { | |
| 1154 | 14 | const FwDpIdType id = entry.record.get_id(); | |
| 1155 | 14 | const U32 tSec = entry.record.get_tSec(); | |
| 1156 | 14 | const U32 tSub = entry.record.get_tSub(); | |
| 1157 | 14 | const FwDpPriorityType oldPriority = entry.record.get_priority(); | |
| 1158 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 13 times.
|
14 | if (priority == oldPriority) { |
| 1159 |
1/1✓ Branch 5 taken 1 times.
|
1 | this->log_ACTIVITY_HI_DpPriorityUnchanged(id, tSec, tSub, priority); |
| 1160 |
1/1✓ Branch 1 taken 1 times.
|
1 | return DpCatalog_PriorityChangeStatus::UNCHANGED; |
| 1161 | } | ||
| 1162 | |||
| 1163 | // Priority is part of the sort key, so the entry is re-linked by removing and re-inserting it. | ||
| 1164 | // Only this entry moves, and every send restarts the walk at begin(), so a transmit in | ||
| 1165 | // progress follows the new order from its next send | ||
| 1166 | // entry is a copy of a set element, so its key is present | ||
| 1167 |
1/1✓ Branch 5 taken 13 times.
|
13 | Fw::Success status = this->m_dpCatalog.remove(entry); |
| 1168 | 13 | FW_ASSERT(status == Fw::Success::SUCCESS, static_cast<FwAssertArgType>(status)); | |
| 1169 |
1/1✓ Branch 6 taken 13 times.
|
13 | entry.record.set_priority(priority); |
| 1170 | // the removal freed a node, and the key (which includes the full product identity) is held by no | ||
| 1171 | // other entry, so the insert cannot fail or collide | ||
| 1172 |
2/2✓ Branch 5 taken 13 times.
✓ Branch 10 taken 13 times.
|
13 | status = this->m_dpCatalog.insert(entry); |
| 1173 | 13 | FW_ASSERT(status == Fw::Success::SUCCESS, static_cast<FwAssertArgType>(status)); | |
| 1174 | // The send in flight is not affected; its copy is kept current so that the record written on | ||
| 1175 | // completion carries the priority the product had (fileDone finds the catalog entry by identity) | ||
| 1176 |
7/8✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 10 times.
✓ Branch 12 taken 2 times.
✓ Branch 13 taken 1 times.
✓ Branch 14 taken 2 times.
✓ Branch 15 taken 11 times.
|
13 | if (this->m_hasCurrentXmit && this->m_currentXmitEntry.isSameProduct(entry)) { |
| 1177 |
1/1✓ Branch 6 taken 2 times.
|
2 | this->m_currentXmitEntry.record.set_priority(priority); |
| 1178 | } | ||
| 1179 |
1/1✓ Branch 5 taken 13 times.
|
13 | this->log_ACTIVITY_HI_DpPrioritySet(id, tSec, tSub, oldPriority, priority); |
| 1180 | |||
| 1181 | // Record the new priority with the product's state, as completion does, so that a rewrite of the | ||
| 1182 | // state file keeps it across a rebuild or restart. Nothing else depends on this record: a runtime | ||
| 1183 | // addToCat recognizes the product by identity, not by priority (processFile) | ||
| 1184 |
1/1✓ Branch 3 taken 13 times.
|
13 | const DpCatalog_StateFileUpdateStatus updateStatus = this->updateStateFileData(entry); |
| 1185 |
3/3✓ Branch 6 taken 13 times.
✓ Branch 8 taken 6 times.
✓ Branch 9 taken 7 times.
|
13 | if (this->m_stateFile.length() == 0) { |
| 1186 |
1/1✓ Branch 1 taken 6 times.
|
6 | return DpCatalog_PriorityChangeStatus::CHANGED; |
| 1187 | } | ||
| 1188 |
2/2✓ Branch 2 taken 1 times.
✓ Branch 3 taken 6 times.
|
7 | if (updateStatus == DpCatalog_StateFileUpdateStatus::FULL) { |
| 1189 |
1/1✓ Branch 1 taken 1 times.
|
1 | return DpCatalog_PriorityChangeStatus::NOT_RECORDED; |
| 1190 | } | ||
| 1191 |
1/1✓ Branch 2 taken 6 times.
|
6 | const DpCatalog_StateFileWriteStatus writeStatus = this->pruneAndWriteStateFile(); |
| 1192 | 6 | return (writeStatus == DpCatalog_StateFileWriteStatus::WRITTEN) ? DpCatalog_PriorityChangeStatus::CHANGED | |
| 1193 |
3/3✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 6 times.
|
6 | : DpCatalog_PriorityChangeStatus::NOT_RECORDED; |
| 1194 | 13 | } | |
| 1195 | |||
| 1196 | 12517 | DpCatalog_EntryLookupStatus DpCatalog ::findEntryByIdentity(const DpStateEntry& product, DpStateEntry& entry) const { | |
| 1197 | // The sort key includes the priority, which SET_DP_PRIORITY changes, so the lookup is by the | ||
| 1198 | // identity fields alone; the walk is bounded by the catalog capacity | ||
| 1199 |
1/1✓ Branch 4 taken 12517 times.
|
12517 | for (Fw::RedBlackTreeSet<DpStateEntry, DP_MAX_FILES>::ConstIterator iter = this->m_dpCatalog.begin(); |
| 1200 |
5/5✓ Branch 1 taken 166652 times.
✓ Branch 7 taken 179169 times.
✓ Branch 11 taken 179169 times.
✓ Branch 15 taken 172769 times.
✓ Branch 16 taken 6400 times.
|
345821 | iter != this->m_dpCatalog.end(); ++iter) { |
| 1201 |
3/3✓ Branch 1 taken 172769 times.
✓ Branch 5 taken 6117 times.
✓ Branch 6 taken 166652 times.
|
172769 | if ((*iter).isSameProduct(product)) { |
| 1202 |
2/2✓ Branch 1 taken 6117 times.
✓ Branch 5 taken 6117 times.
|
6117 | entry = *iter; |
| 1203 |
1/1✓ Branch 1 taken 6117 times.
|
6117 | return DpCatalog_EntryLookupStatus::FOUND; |
| 1204 | } | ||
| 1205 | 12517 | } | |
| 1206 | 6400 | return DpCatalog_EntryLookupStatus::NOT_FOUND; | |
| 1207 | } | ||
| 1208 | |||
| 1209 | 20 | DpCatalog_EntryLookupStatus DpCatalog ::findProductEntry(FwDpIdType id, U32 tSec, U32 tSub, DpStateEntry& entry) const { | |
| 1210 | // The command names the product by id and time tag. The sort key includes the priority, which the | ||
| 1211 | // command changes, so the lookup is a walk by the identity fields, bounded by the catalog capacity | ||
| 1212 |
1/1✓ Branch 4 taken 20 times.
|
20 | for (Fw::RedBlackTreeSet<DpStateEntry, DP_MAX_FILES>::ConstIterator iter = this->m_dpCatalog.begin(); |
| 1213 |
5/5✓ Branch 1 taken 25 times.
✓ Branch 7 taken 45 times.
✓ Branch 11 taken 45 times.
✓ Branch 15 taken 39 times.
✓ Branch 16 taken 6 times.
|
70 | iter != this->m_dpCatalog.end(); ++iter) { |
| 1214 |
3/3✓ Branch 1 taken 39 times.
✓ Branch 5 taken 14 times.
✓ Branch 6 taken 25 times.
|
39 | if ((*iter).hasIdentity(id, tSec, tSub)) { |
| 1215 |
2/2✓ Branch 1 taken 14 times.
✓ Branch 5 taken 14 times.
|
14 | entry = *iter; |
| 1216 |
1/1✓ Branch 1 taken 14 times.
|
14 | return DpCatalog_EntryLookupStatus::FOUND; |
| 1217 | } | ||
| 1218 | 20 | } | |
| 1219 | 6 | return DpCatalog_EntryLookupStatus::NOT_FOUND; | |
| 1220 | } | ||
| 1221 | |||
| 1222 | } // namespace Svc | ||
| 1223 |