exit:
if (halt) {
DEBUG_PRINTF("callback requested to terminate matches\n");
- ci->broken = BROKEN_FROM_USER;
+ ci->status |= STATUS_TERMINATED;
return MO_HALT_MATCHING;
}
to_offset, flags, ci->userContext);
if (halt) {
DEBUG_PRINTF("callback requested to terminate matches\n");
- ci->broken = BROKEN_FROM_USER;
+ ci->status |= STATUS_TERMINATED;
return MO_HALT_MATCHING;
}
exit:
if (halt) {
DEBUG_PRINTF("callback requested to terminate matches\n");
- ci->broken = BROKEN_FROM_USER;
+ ci->status |= STATUS_TERMINATED;
return MO_HALT_MATCHING;
}
if (halt) {
DEBUG_PRINTF("callback requested to terminate matches\n");
- ci->broken = BROKEN_FROM_USER;
+ ci->status |= STATUS_TERMINATED;
return MO_HALT_MATCHING;
}
}
exit:;
- u8 dummy_delay_mask = 0;
- if (cleanUpDelayed(length, 0, tctxt, &dummy_delay_mask)
- == HWLM_TERMINATE_MATCHING) {
+ if (cleanUpDelayed(length, 0, scratch) == HWLM_TERMINATE_MATCHING) {
return;
}
hwlmExec(etable, eod_data, eod_len, adj, roseCallback, tctxt, tctxt->groups);
// We may need to fire delayed matches
- u8 dummy_delay_mask = 0;
- return cleanUpDelayed(0, offset, tctxt, &dummy_delay_mask);
+ return cleanUpDelayed(0, offset, scratch);
}
static rose_inline
void init_rstate(const struct RoseEngine *t, char *state) {
// Set runtime state: we take our initial groups from the RoseEngine.
DEBUG_PRINTF("setting initial groups to 0x%016llx\n", t->initialGroups);
- struct RoseRuntimeState *rstate = getRuntimeState(state);
storeGroups(t, state, t->initialGroups);
- rstate->flags = 0;
- rstate->broken = NOT_BROKEN;
}
static really_inline
}
static really_inline
-hwlmcb_rv_t cleanUpDelayed(size_t length, u64a offset, struct RoseContext *tctxt,
- u8 *status) {
- if (can_stop_matching(tctxtToScratch(tctxt))) {
+hwlmcb_rv_t cleanUpDelayed(size_t length, u64a offset,
+ struct hs_scratch *scratch) {
+ if (can_stop_matching(scratch)) {
return HWLM_TERMINATE_MATCHING;
}
+ struct RoseContext *tctxt = &scratch->tctxt;
if (flushQueuedLiterals(tctxt, length + offset)
== HWLM_TERMINATE_MATCHING) {
return HWLM_TERMINATE_MATCHING;
if (tctxt->filledDelayedSlots) {
DEBUG_PRINTF("dirty\n");
- *status |= DELAY_FLOAT_DIRTY;
+ scratch->core_info.status |= STATUS_DELAY_DIRTY;
} else {
- *status &= ~DELAY_FLOAT_DIRTY;
+ scratch->core_info.status &= ~STATUS_DELAY_DIRTY;
}
tctxt->filledDelayedSlots = 0;
struct hs_scratch *scratch) {
struct core_info *ci = &scratch->core_info;
if (isAllExhausted(t, ci->exhaustionVector)) {
- if (!ci->broken) {
- ci->broken = BROKEN_EXHAUSTED;
- }
+ ci->status |= STATUS_EXHAUSTED;
scratch->tctxt.groups = 0;
DEBUG_PRINTF("all exhausted, termination requested\n");
return HWLM_TERMINATE_MATCHING;
RoseStateOffsets *so) {
u32 curr_offset = 0;
- // First, runtime state (stores per-stream state, like whether we need a
+ // First, runtime status (stores per-stream state, like whether we need a
// delay rebuild or have been told to halt matching.)
- curr_offset += sizeof(RoseRuntimeState);
+ curr_offset += sizeof(u8);
// Role state storage.
curr_offset += mmbit_size(rolesWithStateCount);
&stateOffsets);
scatter_plan_raw state_scatter;
- buildStateScatterPlan(sizeof(RoseRuntimeState), bc.numStates,
+ buildStateScatterPlan(sizeof(u8), bc.numStates,
activeLeftCount, rosePrefixCount, stateOffsets,
cc.streaming, activeArrayCount, outfixBeginQueue,
outfixEndQueue, &state_scatter);
t->historyRequired);
fprintf(f, " - exhaustion vector : %u bytes\n", (t->ekeyCount + 7) / 8);
fprintf(f, " - role state mmbit : %u bytes\n", t->stateSize);
- fprintf(f, " - runtime state : %zu bytes\n", sizeof(RoseRuntimeState));
fprintf(f, " - floating matcher : %u bytes\n", t->floatingStreamState);
fprintf(f, " - active array : %u bytes\n",
mmbit_size(t->activeArrayCount));
#define MAX_DELAY (DELAY_SLOT_COUNT - 1)
#define DELAY_MASK (DELAY_SLOT_COUNT - 1)
-#define DELAY_FLOAT_DIRTY (1U << 7) /* delay literal matched in history */
-
// Direct report stuff
#define LITERAL_DR_FLAG (1U << 31)
#define LITERAL_MDR_FLAG ((1U << 30) | (1U << 31))
*
* State not covered by this structure includes:
*
- * -# the RoseRuntimeState structure
+ * -# the first byte, containing the status bitmask
* -# the role state multibit
*/
struct RoseStateOffsets {
struct scatter_full_plan state_init;
};
-// Rose runtime state
-struct RoseRuntimeState {
- u8 flags; /* high bit true if delay rebuild needed */
- u8 broken; /* user has requested that we stop matching */
-};
-
struct ALIGN_CL_DIRECTIVE anchored_matcher_info {
u32 next_offset; /* relative to this, 0 for end */
u32 state_offset; /* relative to anchorState */
#define rose_inline really_inline
-/** \brief Fetch runtime state ptr. */
-static really_inline
-struct RoseRuntimeState *getRuntimeState(char *state) {
- struct RoseRuntimeState *rs = (struct RoseRuntimeState *)(state);
- assert(ISALIGNED_N(rs, 8));
- return rs;
-}
-
static really_inline
const void *getByOffset(const struct RoseEngine *t, u32 offset) {
assert(offset < t->size);
static really_inline
void *getRoleState(char *state) {
- return state + sizeof(struct RoseRuntimeState);
+ return state + sizeof(u8); // status flags
}
/** \brief Fetch the active array for suffix nfas. */
static rose_inline
void ensureStreamNeatAndTidy(const struct RoseEngine *t, char *state,
struct hs_scratch *scratch, size_t length,
- u64a offset, u8 delay_rb_status) {
+ u64a offset) {
struct RoseContext *tctxt = &scratch->tctxt;
if (roseCatchUpTo(t, state, length + scratch->core_info.buf_offset, scratch,
roseFlushLastByteHistory(t, state, offset + length, tctxt);
tctxt->lastEndOffset = offset + length;
storeGroups(t, state, tctxt->groups);
- struct RoseRuntimeState *rstate = getRuntimeState(state);
- rstate->flags = delay_rb_status;
}
static really_inline
const u8 *buf = scratch->core_info.hbuf + scratch->core_info.hlen - len;
DEBUG_PRINTF("BEGIN FLOATING REBUILD over %zu bytes\n", len);
+ scratch->core_info.status &= ~STATUS_DELAY_DIRTY;
+
hwlmExec(ftable, buf, len, 0, roseDelayRebuildCallback, scratch,
scratch->tctxt.groups);
assert(!can_stop_matching(scratch));
}
char *state = scratch->core_info.state;
- struct RoseRuntimeState *rstate = getRuntimeState(state);
struct RoseContext *tctxt = &scratch->tctxt;
tctxt->mpv_inactive = 0;
streamInitSufPQ(t, state, scratch);
}
- u8 delay_rb_status = rstate->flags;
-
u32 alen = t->anchoredDistance > offset ?
MIN(length + offset, t->anchoredDistance) - offset : 0;
size_t hlength = scratch->core_info.hlen;
- char rebuild = hlength && (delay_rb_status & DELAY_FLOAT_DIRTY)
- && (t->maxFloatingDelayedMatch == ROSE_BOUND_INF
- || offset < t->maxFloatingDelayedMatch);
+ char rebuild = hlength &&
+ (scratch->core_info.status & STATUS_DELAY_DIRTY) &&
+ (t->maxFloatingDelayedMatch == ROSE_BOUND_INF ||
+ offset < t->maxFloatingDelayedMatch);
DEBUG_PRINTF("**rebuild %hhd status %hhu mfdm %u, offset %llu\n",
- rebuild, delay_rb_status, t->maxFloatingDelayedMatch,
- offset);
+ rebuild, scratch->core_info.status,
+ t->maxFloatingDelayedMatch, offset);
if (!flen) {
if (rebuild) { /* rebuild floating delayed match stuff */
flush_delay_and_exit:
DEBUG_PRINTF("flushing floating\n");
- if (cleanUpDelayed(length, offset, tctxt, &delay_rb_status)
- == HWLM_TERMINATE_MATCHING) {
+ if (cleanUpDelayed(length, offset, scratch) == HWLM_TERMINATE_MATCHING) {
return;
}
exit:
DEBUG_PRINTF("CLEAN UP TIME\n");
if (!can_stop_matching(scratch)) {
- ensureStreamNeatAndTidy(t, state, scratch, length, offset,
- delay_rb_status);
+ ensureStreamNeatAndTidy(t, state, scratch, length, offset);
}
- DEBUG_PRINTF("DONE STREAMING SCAN, dirty = %hhu\n", delay_rb_status);
+ DEBUG_PRINTF("DONE STREAMING SCAN, status = %u\n",
+ scratch->core_info.status);
return;
}
void populateCoreInfo(struct hs_scratch *s, const struct RoseEngine *rose,
char *state, match_event_handler onEvent, void *userCtx,
const char *data, size_t length, const u8 *history,
- size_t hlen, u64a offset, UNUSED unsigned int flags) {
+ size_t hlen, u64a offset, u8 status,
+ UNUSED unsigned int flags) {
assert(rose);
s->core_info.userContext = userCtx;
s->core_info.userCallback = onEvent ? onEvent : null_onEvent;
s->core_info.state = state; /* required for chained queues + evec */
s->core_info.exhaustionVector = state + rose->stateOffsets.exhausted;
- s->core_info.broken = NOT_BROKEN;
+ s->core_info.status = status;
s->core_info.buf = (const u8 *)data;
s->core_info.len = length;
s->core_info.hbuf = history;
s->deduper.som_log_dirty = 1; /* som logs have not been cleared */
}
-/** \brief Query whether this stream is broken.
- *
- * A broken stream is one on which scanning has stopped, either because the
- * user has told us to (via the return value from a match callback) or because
- * we have exhausted all reports.
- *
- * \return NOT_BROKEN, BROKEN_FROM_USER or BROKEN_EXHAUSTED.
- */
+#define STATUS_VALID_BITS \
+ (STATUS_TERMINATED | STATUS_EXHAUSTED | STATUS_DELAY_DIRTY)
+
+/** \brief Retrieve status bitmask from stream state. */
static really_inline
-u8 getBroken(const char *state) {
- const struct RoseRuntimeState *ts = (const void *)state;
- assert(ts->broken == NOT_BROKEN || ts->broken == BROKEN_FROM_USER
- || ts->broken == BROKEN_EXHAUSTED);
- return ts->broken;
+u8 getStreamStatus(const char *state) {
+ u8 status = *(const u8 *)state;
+ assert((status & ~STATUS_VALID_BITS) == 0);
+ return status;
}
-/** \brief Mark this stream with the given broken flag.
- *
- * Possible values: NOT_BROKEN, BROKEN_FROM_USER, BROKEN_EXHAUSTED.
- */
+/** \brief Store status bitmask to stream state. */
static really_inline
-void setBroken(char *state, u8 broken) {
- DEBUG_PRINTF("set broken=%d\n", broken);
- assert(broken == NOT_BROKEN || broken == BROKEN_FROM_USER
- || broken == BROKEN_EXHAUSTED);
- struct RoseRuntimeState *ts = (void *)state;
- ts->broken = broken;
+void setStreamStatus(char *state, u8 status) {
+ assert((status & ~STATUS_VALID_BITS) == 0);
+ *(u8 *)state = status;
}
static really_inline
/* populate core info in scratch */
populateCoreInfo(scratch, rose, scratch->bstate, onEvent, userCtx, data,
- length, NULL, 0, 0, flags);
+ length, NULL, 0, 0, 0, flags);
clearEvec(scratch->core_info.exhaustionVector, rose);
char *state = getMultiState(s);
+ setStreamStatus(state, 0);
roseInitState(rose, state);
clearEvec((char *)state + rose->stateOffsets.exhausted, rose);
static really_inline
void rawEodExec(hs_stream_t *id, hs_scratch_t *scratch) {
const struct RoseEngine *rose = id->rose;
- u8 broken = scratch->core_info.broken;
- if (broken) {
+ if (can_stop_matching(scratch)) {
DEBUG_PRINTF("stream already broken\n");
- assert(broken == BROKEN_FROM_USER || broken == BROKEN_EXHAUSTED);
return;
}
static never_inline
void soleOutfixEodExec(hs_stream_t *id, hs_scratch_t *scratch) {
const struct RoseEngine *t = id->rose;
- u8 broken = scratch->core_info.broken;
- if (broken) {
+ if (can_stop_matching(scratch)) {
DEBUG_PRINTF("stream already broken\n");
- assert(broken == BROKEN_FROM_USER || broken == BROKEN_EXHAUSTED);
return;
}
const struct RoseEngine *rose = id->rose;
char *state = getMultiState(id);
+ u8 status = getStreamStatus(state);
- if (getBroken(state)) {
+ if (status == STATUS_TERMINATED || status == STATUS_EXHAUSTED) {
DEBUG_PRINTF("stream is broken, just freeing storage\n");
return;
}
populateCoreInfo(scratch, rose, state, onEvent, context, NULL, 0,
getHistory(state, rose, id->offset),
- getHistoryAmount(rose, id->offset), id->offset, 0);
+ getHistoryAmount(rose, id->offset), id->offset, status, 0);
if (rose->somLocationCount) {
loadSomFromStream(scratch, id->offset);
int halt = flushStoredSomMatches(scratch, ~0ULL);
if (halt) {
DEBUG_PRINTF("told to stop matching\n");
- scratch->core_info.broken = BROKEN_FROM_USER;
- DEBUG_PRINTF("broken = %hhd\n", scratch->core_info.broken);
+ scratch->core_info.status |= STATUS_TERMINATED;
}
}
}
void rawStreamExec(struct hs_stream *stream_state, struct hs_scratch *scratch) {
assert(stream_state);
assert(scratch);
-
- assert(!getBroken(getMultiState(stream_state)));
+ assert(!can_stop_matching(scratch));
DEBUG_PRINTF("::: streaming rose ::: offset = %llu len = %zu\n",
stream_state->offset, scratch->core_info.len);
if (!told_to_stop_matching(scratch) &&
isAllExhausted(rose, scratch->core_info.exhaustionVector)) {
DEBUG_PRINTF("stream exhausted\n");
- scratch->core_info.broken = BROKEN_EXHAUSTED;
+ scratch->core_info.status = STATUS_EXHAUSTED;
}
}
struct hs_scratch *scratch) {
assert(stream_state);
assert(scratch);
+ assert(!can_stop_matching(scratch));
char *state = getMultiState(stream_state);
- assert(!getBroken(state));
const struct RoseEngine *rose = stream_state->rose;
const struct HWLM *ftable = getFLiteralMatcher(rose);
if (!told_to_stop_matching(scratch) &&
isAllExhausted(rose, scratch->core_info.exhaustionVector)) {
DEBUG_PRINTF("stream exhausted\n");
- scratch->core_info.broken = BROKEN_EXHAUSTED;
+ scratch->core_info.status |= STATUS_EXHAUSTED;
}
}
struct hs_scratch *scratch) {
assert(stream_state);
assert(scratch);
+ assert(!can_stop_matching(scratch));
const struct RoseEngine *t = stream_state->rose;
assert(t->outfixEndQueue == 1);
if (nfaQueueExec(q->nfa, q, scratch->core_info.len)) {
nfaQueueCompressState(nfa, q, scratch->core_info.len);
} else if (!told_to_stop_matching(scratch)) {
- scratch->core_info.broken = BROKEN_EXHAUSTED;
+ scratch->core_info.status |= STATUS_EXHAUSTED;
}
}
const struct RoseEngine *rose = id->rose;
char *state = getMultiState(id);
- u8 broken = getBroken(state);
- if (broken) {
+ u8 status = getStreamStatus(state);
+ if (status & (STATUS_TERMINATED | STATUS_EXHAUSTED)) {
DEBUG_PRINTF("stream is broken, halting scan\n");
- if (broken == BROKEN_FROM_USER) {
+ if (status & STATUS_TERMINATED) {
return HS_SCAN_TERMINATED;
} else {
- assert(broken == BROKEN_EXHAUSTED);
return HS_SUCCESS;
}
}
// cases here.
if (unlikely(length == 0)) {
DEBUG_PRINTF("zero length block\n");
- assert(getBroken(state) != BROKEN_FROM_USER);
return HS_SUCCESS;
}
u32 historyAmount = getHistoryAmount(rose, id->offset);
populateCoreInfo(scratch, rose, state, onEvent, context, data, length,
getHistory(state, rose, id->offset), historyAmount,
- id->offset, flags);
+ id->offset, status, flags);
assert(scratch->core_info.hlen <= id->offset
&& scratch->core_info.hlen <= rose->historyRequired);
if (!id->offset && rose->boundary.reportZeroOffset) {
DEBUG_PRINTF("zero reports\n");
processReportList(rose, rose->boundary.reportZeroOffset, 0, scratch);
- broken = scratch->core_info.broken;
- if (unlikely(broken)) {
+ if (unlikely(can_stop_matching(scratch))) {
DEBUG_PRINTF("stream is broken, halting scan\n");
- setBroken(state, broken);
- if (broken == BROKEN_FROM_USER) {
+ setStreamStatus(state, scratch->core_info.status);
+ if (told_to_stop_matching(scratch)) {
return HS_SCAN_TERMINATED;
} else {
- assert(broken == BROKEN_EXHAUSTED);
+ assert(scratch->core_info.status & STATUS_EXHAUSTED);
return HS_SUCCESS;
}
}
if (rose->hasSom && !told_to_stop_matching(scratch)) {
int halt = flushStoredSomMatches(scratch, ~0ULL);
if (halt) {
- scratch->core_info.broken = BROKEN_FROM_USER;
+ scratch->core_info.status |= STATUS_TERMINATED;
}
}
+ setStreamStatus(state, scratch->core_info.status);
+
if (likely(!can_stop_matching(scratch))) {
- maintainHistoryBuffer(id->rose, getMultiState(id), data, length);
+ maintainHistoryBuffer(rose, state, data, length);
id->offset += length; /* maintain offset */
if (rose->somLocationCount) {
storeSomToStream(scratch, id->offset);
}
} else if (told_to_stop_matching(scratch)) {
- setBroken(state, BROKEN_FROM_USER);
return HS_SCAN_TERMINATED;
- } else { /* exhausted */
- setBroken(state, BROKEN_EXHAUSTED);
}
return HS_SUCCESS;
u32 qm_size; /**< current size of the priority queue */
};
+/** \brief Status flag: user requested termination. */
+#define STATUS_TERMINATED (1U << 0)
-/** \brief Value indicating a stream is active (not broken). */
-#define NOT_BROKEN 0
+/** \brief Status flag: all possible matches on this stream have
+ * been raised (i.e. all its exhaustion keys are on.) */
+#define STATUS_EXHAUSTED (1U << 1)
-/** \brief Value indicating that the user has requested that matching be
- * terminated. */
-#define BROKEN_FROM_USER 1
-
-/** \brief Value indicating that all possible matches on this stream have been
- * raised (i.e. all its exhaustion keys are on.) */
-#define BROKEN_EXHAUSTED 2
+/** \brief Status flag: Rose requires rebuild as delay literal matched in
+ * history. */
+#define STATUS_DELAY_DIRTY (1U << 2)
/** \brief Core information about the current scan, used everywhere. */
struct core_info {
const struct RoseEngine *rose;
char *state; /**< full stream state */
char *exhaustionVector; /**< pointer to evec for this stream */
- char broken; /**< user told us to stop, or exhausted */
const u8 *buf; /**< main scan buffer */
size_t len; /**< length of main scan buffer in bytes */
const u8 *hbuf; /**< history buffer */
size_t hlen; /**< length of history buffer in bytes. */
u64a buf_offset; /**< stream offset, for the base of the buffer */
+ u8 status; /**< stream status bitmask, using STATUS_ flags above */
};
/** \brief Rose state information. */
static really_inline
char told_to_stop_matching(const struct hs_scratch *scratch) {
- return scratch->core_info.broken == BROKEN_FROM_USER;
+ return scratch->core_info.status & STATUS_TERMINATED;
}
static really_inline
char can_stop_matching(const struct hs_scratch *scratch) {
- return scratch->core_info.broken != NOT_BROKEN;
+ return scratch->core_info.status & (STATUS_TERMINATED | STATUS_EXHAUSTED);
}
#ifdef __cplusplus
int halt = ci->userCallback(onmatch, from_offset, offset, flags,
ci->userContext);
if (halt) {
- ci->broken = BROKEN_FROM_USER;
+ ci->status |= STATUS_TERMINATED;
return 1;
}
}