From e8ea672d6a845dbade71af9594232d1dd335af55 Mon Sep 17 00:00:00 2001 From: Matt Liberty Date: Wed, 14 Feb 2024 11:21:14 -0500 Subject: [PATCH] Fixed FSR summary reconstruction on truncation #10 --- CHANGELOG.md | 3 +- example/generate.py | 10 ++- example/jls/info.c | 7 +- include_prv/jls/core.h | 2 + src/core.c | 156 ++++++++++++++++++++++------------------- src/reader.c | 11 ++- src/track.c | 110 +++++++++++++++-------------- src/wr_fsr.c | 26 +++---- test/repair_test.c | 5 +- 9 files changed, 187 insertions(+), 143 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56a4207..4406286 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,10 @@ This file contains the list of changes made to the JLS project. ## 0.9.2 -2024 Feb 12 [in progress] +2024 Feb 14 * Fixed index error in file repair operation. +* Fixed FSR summary reconstruction on truncation #10 ## 0.9.1 diff --git a/example/generate.py b/example/generate.py index 9476710..c236060 100644 --- a/example/generate.py +++ b/example/generate.py @@ -39,6 +39,8 @@ def parser(): p.add_argument('--sample_decimate_factor', type=int, default=1000, help='The samples per summary entry.') p.add_argument('--entries_per_summary', type=int, default=20000, help='The entries per summary chunk.') p.add_argument('--summary_decimate_factor', type=int, default=100, help='The summaries per summary entry.') + p.add_argument('--skip_close', action='store_true', help='Skip cleanly closing the file to test recovery.') + p.add_argument('--sample_id_offset', type=int, default=0, help='The starting sample_id offset.') p.add_argument('--add', action='append', help='The waveform definition to add, which is one of:' @@ -118,8 +120,9 @@ def run(): # Write to file y_len = len(x) - sample_id = 0 - with Writer(args.filename) as wr: + sample_id = args.sample_id_offset + wr = Writer(args.filename) + try: wr.source_def_from_struct(source) wr.signal_def_from_struct(signal) wr.user_data(0, 'string user data at start') @@ -135,6 +138,9 @@ def run(): x += 1.0 # increment wr.user_data(42, b'binary data') wr.user_data(43, {'my': 'data', 'json': [1, 2, 3]}) + finally: + if not args.skip_close: + wr.close() if __name__ == "__main__": diff --git a/example/jls/info.c b/example/jls/info.c index f74dc73..bdd4dc9 100644 --- a/example/jls/info.c +++ b/example/jls/info.c @@ -120,9 +120,12 @@ int on_info(struct app_s * self, int argc, char * argv[]) { if (chunks) { struct jls_raw_s * raw; - ROE(jls_raw_open(&raw, path, "r")); + int32_t rc = jls_raw_open(&raw, path, "r"); + if (rc && (rc != JLS_ERROR_TRUNCATED)) { + printf("Could not open for reading chunks\n"); + return rc; + } - int32_t rc = 0; struct jls_chunk_header_s hdr; /* diff --git a/include_prv/jls/core.h b/include_prv/jls/core.h index 3d60223..e0582ac 100644 --- a/include_prv/jls/core.h +++ b/include_prv/jls/core.h @@ -237,6 +237,8 @@ int32_t jls_core_scan_initial(struct jls_core_s * self); int32_t jls_core_sources(struct jls_core_s * self, struct jls_source_def_s ** sources, uint16_t * count); int32_t jls_core_signals(struct jls_core_s * self, struct jls_signal_def_s ** signals, uint16_t * count); int32_t jls_core_signal(struct jls_core_s * self, uint16_t signal_id, struct jls_signal_def_s * signal); +int32_t jls_core_fsr_sample_buffer_alloc(struct jls_core_fsr_s * self); +void jls_core_fsr_sample_buffer_free(struct jls_core_fsr_s * self); int32_t jls_core_fsr_seek(struct jls_core_s * self, uint16_t signal_id, uint8_t level, int64_t sample_id); int32_t jls_core_fsr_length(struct jls_core_s * self, uint16_t signal_id, int64_t * samples); int32_t jls_core_fsr(struct jls_core_s * self, uint16_t signal_id, int64_t start_sample_id, diff --git a/src/core.c b/src/core.c index a20d923..5e5c5bc 100644 --- a/src/core.c +++ b/src/core.c @@ -381,6 +381,14 @@ int32_t jls_core_wr_summary(struct jls_core_s * self, uint16_t signal_id, enum j chunk.offset = jls_raw_chunk_tell(self->raw); // write + if (JLS_LOG_CHECK_STATIC(JLS_LOG_LEVEL_DEBUG3)) { + struct jls_payload_header_s * hdr = (struct jls_payload_header_s *) payload; + JLS_LOGD3("wr_summary(signal_id=%d, level=%d, timestamp=%" PRIi64 ", entries=%" PRIu32 + ") => offset=%" PRIi64, + (int) signal_id, (int) level, + hdr->timestamp, hdr->entry_count, + jls_raw_chunk_tell(self->raw)); + } ROE(jls_raw_wr(self->raw, &chunk.hdr, payload)); ROE(jls_core_update_item_head(self, &track->summary_head[level], &chunk)); return 0; @@ -796,9 +804,12 @@ int32_t jls_core_fsr_length(struct jls_core_s * self, uint16_t signal_id, int64_ int64_t * offsets = self->signal_info[signal_id].tracks[JLS_TRACK_TYPE_FSR].head_offsets; int level = JLS_SUMMARY_LEVEL_COUNT - 1; for (; level >= 0; --level) { - if (offsets[level]) { - offset = offsets[level]; + offset = offsets[level]; + if (offset && (0 == jls_raw_chunk_seek(self->raw, offset))) { break; + } else { + offset = 0; + offsets[level] = 0; } } if (!offset) { @@ -1215,103 +1226,106 @@ int32_t jls_core_repair_fsr(struct jls_core_s * self, uint16_t signal_id) { struct jls_core_track_s * track = &signal_info->tracks[JLS_SIGNAL_TYPE_FSR]; track->parent = signal_info; - JLS_LOGI("repair signal_id %d", (int) signal_id); - // find first non-empty level int64_t * offsets = signal_info->tracks[JLS_TRACK_TYPE_FSR].head_offsets; int level = JLS_SUMMARY_LEVEL_COUNT - 1; for (; (level > 0); --level) { if (offsets[level]) { - break; + if (0 == jls_raw_chunk_seek(self->raw, offsets[level])) { + break; + } else { + offsets[level] = 0; + } } } - int64_t offset_next = 0; - int64_t offset_this = 0; - int64_t offset = 0; - bool skip_this = false; - bool skip_next = false; - - for (; level > 0; --level) { - JLS_LOGI("repair signal_id %d, level %d", (int) signal_id, (int) level); - offset = offset_next ? offset_next : offsets[level]; - skip_next = offset_next; - offset_next = 0; - offset_this = 0; - jls_core_fsr_summary_level_alloc(signal_info->track_fsr, level); - struct jls_core_fsr_level_s * lvl = signal_info->track_fsr->level[level]; - - while (offset) { - offset_this = offset; - skip_this = skip_next; - skip_next = false; - JLS_LOGI("repair signal_id %d, level %d, offset %" PRIi64 " %s", - (int) signal_id, (int) level, offset, skip_this ? "skip" : ""); - // read index and summary chunks - if (jls_raw_chunk_seek(self->raw, offset)) { - break; - } - if (jls_core_rd_chunk(self)) { - break; - } - track->index_head[level] = self->chunk_cur; + int64_t offset_index_next = 0; + int64_t offset = offsets[level]; + struct jls_core_chunk_s index_head; - memcpy(lvl->index, self->buf->start, self->chunk_cur.hdr.payload_length); - signal_info->tracks[JLS_TRACK_TYPE_FSR].index_head[level] = self->chunk_cur; - offset = self->chunk_cur.hdr.item_next; + jls_core_fsr_summary_level_alloc(signal_info->track_fsr, level); + struct jls_core_fsr_level_s * lvl = signal_info->track_fsr->level[level]; + bool skip_summary = false; - if (jls_core_rd_chunk(self)) { - break; - } - track->summary_head[level] = self->chunk_cur; + while (level > 0) { + JLS_LOGI("repair_fsr signal_id %d, level %d, offset %" PRIi64, (int) signal_id, (int) level, offset); - memcpy(lvl->summary, self->buf->start, self->chunk_cur.hdr.payload_length); - signal_info->tracks[JLS_TRACK_TYPE_FSR].summary_head[level] = self->chunk_cur; + if (jls_core_rd_chunk(self)) { // read index + break; + } + index_head = self->chunk_cur; + memcpy(lvl->index, self->buf->start, self->chunk_cur.hdr.payload_length); - struct jls_fsr_index_s * r = lvl->index; - if (r->header.entry_size_bits != (sizeof(r->offsets[0]) * 8)) { - JLS_LOGE("invalid FSR index entry size: %d bits", (int) r->header.entry_size_bits); - return JLS_ERROR_PARAMETER_INVALID; - } - size_t sz = sizeof(r->header) + r->header.entry_count * sizeof(r->offsets[0]); - if (sz > self->buf->length) { - JLS_LOGE("invalid payload length"); - return JLS_ERROR_PARAMETER_INVALID; - } + if (jls_core_rd_chunk(self)) { // read summary + break; + } + track->index_head[level] = index_head; + offset_index_next = index_head.hdr.item_next; + track->summary_head[level] = self->chunk_cur; + memcpy(lvl->summary, self->buf->start, self->chunk_cur.hdr.payload_length); - jls_raw_seek_end(self->raw); - if (!skip_this) { - if (jls_core_fsr_summaryN(signal_info->track_fsr, level + 1, offset_this)) { - JLS_LOGW("could not create summary - repair may not work"); - } - } + struct jls_fsr_index_s * r = lvl->index; + if (r->header.entry_size_bits != (sizeof(r->offsets[0]) * 8)) { + JLS_LOGE("invalid FSR index entry size: %d bits", (int) r->header.entry_size_bits); + return JLS_ERROR_PARAMETER_INVALID; + } + size_t sz = sizeof(r->header) + r->header.entry_count * sizeof(r->offsets[0]); + if (sz > self->buf->length) { + JLS_LOGE("invalid payload length"); + return JLS_ERROR_PARAMETER_INVALID; + } + + jls_raw_seek_end(self->raw); + if (!skip_summary && jls_core_fsr_summaryN(signal_info->track_fsr, level + 1, offset)) { + JLS_LOGE("repair_fsr signal_id %d could not create summary - cannot repair this track", (int) signal_id); + } + skip_summary = false; + if ((offset_index_next > 0) && (0 == jls_raw_chunk_seek(self->raw, offset_index_next))) { + offset = offset_index_next; + } else { + skip_summary = true; + --level; if (r->header.entry_count > 0) { - offset_next = r->offsets[r->header.entry_count - 1]; + offset = r->offsets[r->header.entry_count - 1]; + lvl->index->header.entry_count = 0; + lvl->summary->header.entry_count = 0; + if (0 != jls_raw_chunk_seek(self->raw, offset)) { + JLS_LOGE("Could not seek to lower-level index. Cannot repair."); + break; + } + } else { + JLS_LOGE("Empty index. Cannot repair."); + return JLS_ERROR_NOT_SUPPORTED; } - lvl->index->header.entry_count = 0; - lvl->summary->header.entry_count = 0; } } // update level 0 (data) - offset = offset_next ? offset_next : offsets[0]; - skip_next = offset_next; + jls_core_fsr_sample_buffer_alloc(signal_info->track_fsr); while (offset) { - if (jls_core_rd_chunk(self)) { + if (jls_raw_chunk_seek(self->raw, offset) || jls_core_rd_chunk(self)) { break; } - if (!skip_next) { - if (jls_core_fsr_summary1(signal_info->track_fsr, offset)) { - JLS_LOGW("could not create summary - repair may not work"); - } + memcpy(signal_info->track_fsr->data, self->buf->start, self->buf->length); + JLS_LOGI("repair_fsr signal_id %d, level %d, offset %" PRIi64 " sample_id %" PRIi64 " to %" PRIi64 " data[0]=%f", + (int) signal_id, (int) level, offset, + signal_info->track_fsr->data->header.timestamp, + signal_info->track_fsr->data->header.timestamp + signal_info->track_fsr->data->header.entry_count, + signal_info->track_fsr->data->data[0]); + signal_info->track_fsr->data_length = signal_info->track_fsr->data->header.entry_count; + + if (!skip_summary && jls_core_fsr_summary1(signal_info->track_fsr, offset)) { + JLS_LOGW("could not create summary - repair may not work"); } - skip_next = false; + skip_summary = false; offset = self->chunk_cur.hdr.item_next; } + jls_core_fsr_sample_buffer_free(signal_info->track_fsr); - JLS_LOGI("repair signal_id %d finalizing", (int) signal_id); + JLS_LOGI("repair_fsr signal_id %d finalizing", (int) signal_id); jls_raw_seek_end(self->raw); + ROE(jls_fsr_close(signal_info->track_fsr)); signal_info->track_fsr = NULL; return 0; diff --git a/src/reader.c b/src/reader.c index 31f8822..997abce 100644 --- a/src/reader.c +++ b/src/reader.c @@ -124,6 +124,15 @@ int32_t jls_rd_open(struct jls_rd_s ** instance, const char * path) { jls_track_repair_pointers(&signal_info->tracks[track_idx]); } } + } + + GOE(jls_core_scan_fsr_sample_id(core)); + + for (uint16_t signal_idx = 0; signal_idx < JLS_SIGNAL_COUNT; ++signal_idx) { + struct jls_core_signal_s * signal_info = &core->signal_info[signal_idx]; + if (signal_info->signal_def.signal_id != signal_idx) { + continue; + } if (signal_info->signal_def.signal_type == JLS_SIGNAL_TYPE_FSR) { GOE(jls_core_repair_fsr(core, signal_idx)); @@ -238,7 +247,7 @@ static inline void f64_to_stats(struct jls_statistics_s * stats, const double * static int32_t rd_stats_chunk(struct jls_core_s * self, uint16_t signal_id, uint8_t level) { ROE(jls_core_rd_chunk(self)); if (JLS_TAG_TRACK_FSR_SUMMARY != self->chunk_cur.hdr.tag) { - JLS_LOGW("unexpected chunk tag %d", (int) self->chunk_cur.hdr.tag); + JLS_LOGW("unexpected chunk tag %d at %" PRIi64, (int) self->chunk_cur.hdr.tag, self->chunk_cur.offset); return JLS_ERROR_IO; } uint16_t metadata = (signal_id & SIGNAL_MASK) | (((uint16_t) level) << 12); diff --git a/src/track.c b/src/track.c index b5eb13f..12cfb47 100644 --- a/src/track.c +++ b/src/track.c @@ -81,88 +81,92 @@ int32_t jls_track_repair_pointers(struct jls_core_track_s * track) { int signal_id = (int) signal->signal_def.signal_id; JLS_LOGI("repair signal %d, track %d", signal_id, (int) track->track_type); - struct jls_core_chunk_s index_chunk; - struct jls_core_chunk_s summary_chunk; + struct jls_core_chunk_s index_chunk = {.offset=0}; + struct jls_core_chunk_s index_chunk_next = {.offset=0}; + struct jls_core_chunk_s summary_chunk = {.offset=0}; // find first non-empty level int64_t * offsets = track->head_offsets; int level = JLS_SUMMARY_LEVEL_COUNT - 1; for (; (level > 0); --level) { if (offsets[level]) { - break; + if (0 == jls_raw_chunk_seek(raw, offsets[level])) { + break; + } else { + offsets[level] = 0; + track->index_head[level].offset = 0; + track->summary_head[level].offset = 0; + track->head_offsets[level] = 0; + } } } - int64_t offset_next = 0; - int64_t offset = 0; - bool skip_this = false; - bool skip_next = false; - - for (; level > 0; --level) { - JLS_LOGI("repair signal %d, track %d, level %d", signal_id, (int) track->track_type, level); - offset = offset_next ? offset_next : offsets[level]; - skip_next = offset_next; - offset_next = 0; - index_chunk.offset = 0; - summary_chunk.offset = 0; - int counter = 0; - - while (offset) { - skip_this = skip_next; - skip_next = false; - JLS_LOGI("repair signal_id %d, level %d, offset %" PRIi64 " %s", - (int) signal_id, (int) level, offset, skip_this ? "skip" : ""); - // read index and summary chunks - if (jls_raw_chunk_seek(raw, offset)) { - break; - } - if (jls_core_rd_chunk(core)) { - break; - } - track->index_head[level] = core->chunk_cur; - offset = core->chunk_cur.hdr.item_next; - int64_t offset_next_tmp = offset_next; + int64_t offset = offsets[level]; + int64_t offset_descend_next = 0; + int64_t offset_descend = 0; + while (level > 0) { + JLS_LOGI("repair signal_id %d track %d, level %d, offset %" PRIi64, + (int) signal_id, (int) track->track_type, (int) level, offset); + bool descend = false; + if (jls_raw_chunk_seek(raw, offset) || jls_core_rd_chunk(core)) { // index + descend = true; + } else { + index_chunk_next = core->chunk_cur; + offset_descend_next = 0; if (JLS_TRACK_TYPE_FSR == track->track_type) { struct jls_fsr_index_s * r = (struct jls_fsr_index_s *) core->buf->start; if (r->header.entry_count > 0) { - offset_next_tmp = r->offsets[r->header.entry_count - 1]; + offset_descend_next = r->offsets[r->header.entry_count - 1]; } } else { struct jls_index_s * r = (struct jls_index_s *) core->buf->start; if (r->header.entry_count > 0) { - offset_next_tmp = r->entries[r->header.entry_count - 1].offset; + offset_descend_next = r->entries[r->header.entry_count - 1].offset; } } - if (jls_core_rd_chunk(core)) { - break; + descend = true; + } else { + index_chunk = index_chunk_next; + summary_chunk = core->chunk_cur; + offset = index_chunk.hdr.item_next; // next index + offset_descend = offset_descend_next; + track->index_head[level].offset = index_chunk.offset; + track->summary_head[level].offset = summary_chunk.offset; } - track->summary_head[level] = core->chunk_cur; - - index_chunk = track->index_head[level]; - summary_chunk = track->summary_head[level]; - offset_next = offset_next_tmp; - ++counter; } - if (counter == 0) { - offsets[level] = 0; - track->index_head[level].offset = 0; - track->summary_head[level].offset = 0; - } else { - index_chunk.hdr.item_next = 0; - jls_core_update_chunk_header(core, &index_chunk); - summary_chunk.hdr.item_next = 0; - jls_core_update_chunk_header(core, &summary_chunk); + if (descend || (0 == offset)) { + if (offset_descend && index_chunk.offset && summary_chunk.offset) { + JLS_LOGI("descend signal_id %d track %d, level %d, offset %" PRIi64, + (int) signal_id, (int) track->track_type, (int) level, offset_descend); + index_chunk.hdr.item_next = 0; + summary_chunk.hdr.item_next = 0; + jls_core_update_chunk_header(core, &index_chunk); + jls_core_update_chunk_header(core, &summary_chunk); + offset = offset_descend; + } else { + JLS_LOGI("restart signal_id %d track %d, level %d, offset %" PRIi64, + (int) signal_id, (int) track->track_type, (int) level, offsets[level - 1]); + track->index_head[level].offset = 0; + track->summary_head[level].offset = 0; + track->head_offsets[level] = 0; + offset = offsets[level - 1]; + } + index_chunk.offset = 0; + summary_chunk.offset = 0; + offset_descend = 0; + --level; } } // update level 0 (data) - offset = offset_next ? offset_next : offsets[0]; struct jls_core_chunk_s data_chunk = {.offset=0}; while (offset) { - if (jls_core_rd_chunk(core)) { + JLS_LOGI("repair signal_id %d track %d, level %d, offset %" PRIi64, + (int) signal_id, (int) track->track_type, (int) level, offset); + if (jls_raw_chunk_seek(raw, offset) || jls_core_rd_chunk(core)) { if (data_chunk.offset) { data_chunk.hdr.item_next = 0; jls_core_update_chunk_header(core, &summary_chunk); diff --git a/src/wr_fsr.c b/src/wr_fsr.c index 2f7d7e8..f5ff422 100644 --- a/src/wr_fsr.c +++ b/src/wr_fsr.c @@ -46,7 +46,7 @@ static inline uint8_t summary_entry_size(struct jls_core_fsr_s * self) { } } -static int32_t sample_buffer_alloc(struct jls_core_fsr_s * self) { +int32_t jls_core_fsr_sample_buffer_alloc(struct jls_core_fsr_s * self) { size_t sample_buffer_sz = sizeof(struct jls_payload_header_s) + (sample_size_bits(self) * self->parent->signal_def.samples_per_data) / 8; self->data = malloc(sample_buffer_sz); if (!self->data) { @@ -67,7 +67,7 @@ static int32_t sample_buffer_alloc(struct jls_core_fsr_s * self) { return 0; } -static void sample_buffer_free(struct jls_core_fsr_s * self) { +void jls_core_fsr_sample_buffer_free(struct jls_core_fsr_s * self) { if (self->data) { free(self->data); self->data = NULL; @@ -221,14 +221,7 @@ static int32_t wr_summary(struct jls_core_fsr_s * self, uint8_t level) { p_start, payload_len)); ROE(jls_core_fsr_summaryN(self, level + 1, pos_next)); - // compute new timestamp for that level - int64_t skip = dst->summary_entries * self->parent->signal_def.sample_decimate_factor; - for (uint8_t lvl = 2; lvl <= level; ++lvl) { - skip *= self->parent->signal_def.summary_decimate_factor; - } - dst->index->header.timestamp += skip; dst->index->header.entry_count = 0; - dst->summary->header.timestamp += skip; dst->summary->header.entry_count = 0; return 0; } @@ -264,7 +257,7 @@ int32_t jls_fsr_close(struct jls_core_fsr_s * self) { JLS_LOGE("wr_data returned %" PRIi32, rc); } JLS_LOGD1("%d sample_buffer free %p", (int) self->parent->signal_def.signal_id, (void *) self->data); - sample_buffer_free(self); + jls_core_fsr_sample_buffer_free(self); } for (size_t i = 1; i < JLS_SUMMARY_LEVEL_COUNT; ++i) { @@ -356,7 +349,12 @@ int32_t jls_core_fsr_summaryN(struct jls_core_fsr_s * self, uint8_t level, int64 dst = self->level[level]; } - JLS_LOGD2("jls_core_fsr_summaryN %d: %" PRIu32 " %" PRIi64, (int) level, dst->index->header.entry_count, pos); + JLS_LOGD2("jls_core_fsr_summaryN %d: entries=%" PRIu32 ", offset=%" PRIi64 ", sample_id=%" PRIi64, + (int) level, dst->index->header.entry_count, pos, dst->index->header.timestamp); + if (0 == dst->index->header.entry_count) { + dst->index->header.timestamp = src->index->header.timestamp; + dst->summary->header.timestamp = src->summary->header.timestamp; + } dst->index->offsets[dst->index->header.entry_count++] = pos; uint32_t summaries_per = (uint32_t) (src->summary->header.entry_count / self->parent->signal_def.summary_decimate_factor); @@ -392,6 +390,10 @@ int32_t jls_core_fsr_summary1(struct jls_core_fsr_s * self, int64_t pos) { double * data = self->data_f64; // JLS_LOGI("1 add %" PRIi64 " @ %" PRIi64 " %p", pos, dst->index->offset, &dst->index->data[dst->index->offset]); + if (0 == dst->index->header.entry_count) { + dst->index->header.timestamp = self->data->header.timestamp; + dst->summary->header.timestamp = self->data->header.timestamp; + } dst->index->offsets[dst->index->header.entry_count++] = pos; uint32_t summaries_per = (uint32_t) (self->data->header.entry_count / self->parent->signal_def.sample_decimate_factor); @@ -502,7 +504,7 @@ int32_t jls_wr_fsr_data(struct jls_core_fsr_s * self, int64_t sample_id, const v } if (!self->data) { - ROE(sample_buffer_alloc(self)); + ROE(jls_core_fsr_sample_buffer_alloc(self)); self->sample_id_offset = sample_id; // can be nonzero self->data->header.timestamp = sample_id; } diff --git a/test/repair_test.c b/test/repair_test.c index 491dd90..b300c82 100644 --- a/test/repair_test.c +++ b/test/repair_test.c @@ -209,13 +209,14 @@ static void test_truncate_summary(void **state) { assert_int_equal(sample_count, samples); assert_int_equal(0, jls_rd_fsr_statistics(rd, 5, 0, sample_count, data, 1)); assert_float_equal(signal_mean, data[0], 1e-9); + jls_rd_close(rd); remove(filename); } static void test_truncate_samples(void **state) { (void) state; int64_t sample_count = WINDOW_SIZE * 1000; - int64_t sample_count_truncated = 0x1e780; + int64_t sample_count_truncated = 127920; double signal_mean = 0.0; float * signal = gen_truncate(sample_count, 3500000, GEN_CLOSE); @@ -231,6 +232,7 @@ static void test_truncate_samples(void **state) { assert_int_equal(0, jls_rd_fsr_length(rd, 5, &samples)); assert_int_equal(sample_count_truncated, samples); assert_int_equal(0, jls_rd_fsr_statistics(rd, 5, 0, sample_count_truncated, data, 1)); + jls_rd_close(rd); assert_float_equal(signal_mean, data[0], 1e-9); remove(filename); } @@ -255,6 +257,7 @@ static void test_truncate_samples_unclosed(void **state) { assert_int_equal(sample_count_truncated, samples); assert_int_equal(0, jls_rd_fsr_statistics(rd, 5, 0, sample_count_truncated, data, 1)); assert_float_equal(signal_mean, data[0], 1e-9); + jls_rd_close(rd); remove(filename); }