int vrt_producer_flush(struct vrt_producer *p) { struct vrt_value *v; if (p->last_produced_id == p->last_claimed_id) { /* We don't have any queue entries that we've claimed but haven't used, * so there's nothing to flush. */ return 0; } /* Claim a value to fill in a FLUSH control message. */ rii_check(vrt_producer_claim_raw(p->queue, p)); clog_trace("<%s> Flush %d", p->name, p->last_produced_id); v = vrt_queue_get(p->queue, p->last_produced_id); v->special = VRT_VALUE_FLUSH; /* If we've claimed more value than we've produced, fill in the * remainder with holes. */ if (vrt_mod_lt(p->last_produced_id, p->last_claimed_id)) { vrt_value_id i; clog_trace("<%s> Holes %d-%d", p->name, p->last_produced_id + 1, p->last_claimed_id); for (i = p->last_produced_id + 1; vrt_mod_le(i, p->last_claimed_id); i++) { struct vrt_value *v = vrt_queue_get(p->queue, i); v->id = i; v->special = VRT_VALUE_HOLE; } p->last_produced_id = p->last_claimed_id; } /* Then publish the whole chunk. */ return p->publish(p->queue, p, p->last_claimed_id); }
int main(int argc, char *argv[]) { int level = CLOG_DEFAULT; const char *lname = "DEFAULT"; clog_init(stdout, level, CLOG_DEFAULT_TS_FMT); if(argc == 2) { if(!strcmp("FATAL", argv[1])) { clog_set_level(level = CLOG_FATAL); lname = "FATAL"; } if(!strcmp("ERROR", argv[1])) { clog_set_level(level = CLOG_ERROR); lname = "ERROR"; } if(!strcmp("WARN", argv[1])) { clog_set_level(level = CLOG_WARN); lname = "WARN"; } if(!strcmp("INFO", argv[1])) { clog_set_level(level = CLOG_INFO); lname = "INFO"; } if(!strcmp("DEBUG", argv[1])) { clog_set_level(level = CLOG_DEBUG); lname = "DEBUG"; } if(!strcmp("TRACE", argv[1])) { clog_set_level(level = CLOG_TRACE); lname = "TRACE"; } } fprintf(stdout, "--- %s ---\n", lname); clog_fatal("this is %s log", "fatal"); clog_error("this is %s log", "error"); clog_warn("this is %s log", "warn"); clog_info("this is %s log", "info"); clog_debug("this is %s log", "debug"); clog_trace("this is %s log", "trace"); return 0; }
static int vrt_publish_multi_threaded(struct vrt_queue *q, struct vrt_producer *p, vrt_value_id last_published_id) { bool first = true; vrt_value_id expected_cursor; vrt_value_id current_cursor; /* If there are multiple publisherthen we have to wait until all * of the values before the chunk that we claimed have been * published. (If we don't, there will be a hole in the sequence of * published records.) */ expected_cursor = last_published_id - p->batch_size; current_cursor = vrt_queue_get_cursor(q); clog_debug("<%s> Wait for value %d to be published", p->name, expected_cursor); while (vrt_mod_lt(current_cursor, expected_cursor)) { clog_trace("<%s> Last published value is %d (wait)", p->name, current_cursor); rii_check(vrt_yield_strategy_yield (p->yield, first, q->name, p->name)); first = false; current_cursor = vrt_queue_get_cursor(q); } clog_debug("<%s> Last published value is %d", p->name, current_cursor); clog_debug("<%s> Signal publication of value %d (multi-threaded)", p->name, last_published_id); vrt_queue_set_cursor(q, last_published_id); return 0; }
/* Waits for the slot given by the producer's last_claimed_id to become * free. (This happens when every consumer has finished processing the * previous value that would've used the same slot in the ring buffer. */ static int vrt_wait_for_slot(struct vrt_queue *q, struct vrt_producer *p) { bool first = true; vrt_value_id wrapped_id = p->last_claimed_id - vrt_queue_size(q); if (vrt_mod_lt(q->last_consumed_id, wrapped_id)) { clog_debug("<%s> Wait for value %d to be consumed", p->name, wrapped_id); vrt_value_id minimum = vrt_queue_find_last_consumed_id(q); while (vrt_mod_lt(minimum, wrapped_id)) { clog_trace("<%s> Last consumed value is %d (wait)", p->name, minimum); p->yield_count++; rii_check(vrt_yield_strategy_yield (p->yield, first, q->name, p->name)); first = false; minimum = vrt_queue_find_last_consumed_id(q); } p->batch_count++; q->last_consumed_id = minimum; clog_debug("<%s> Last consumed value is %d", p->name, minimum); } return 0; }
int vrt_producer_skip(struct vrt_producer *p) { struct vrt_value *v; clog_trace("<%s> Skip %d", p->name, p->last_produced_id); v = vrt_queue_get(p->queue, p->last_produced_id); v->special = VRT_VALUE_HOLE; return vrt_producer_publish(p); }
static int vrt_claim_multi_threaded(struct vrt_queue *q, struct vrt_producer *p) { /* If there are multiple producerwe have to use an atomic * increment to claim the next batch of records. */ p->last_claimed_id = vrt_padded_int_atomic_add(&q->last_claimed_id, p->batch_size); p->last_produced_id = p->last_claimed_id - p->batch_size; if (p->batch_size == 1) { clog_trace("<%s> Claim value %d (multi-threaded)", p->name, p->last_claimed_id); } else { clog_trace("<%s> Claim values %d-%d (multi-threaded)", p->name, p->last_produced_id + 1, p->last_claimed_id); } /* Then wait until the slots for these new values are free. */ return vrt_wait_for_slot(q, p); }
static int vrt_claim_single_threaded(struct vrt_queue *q, struct vrt_producer *p) { /* If there's only a single producer, we can just grab the next * batch of values in sequence. */ p->last_claimed_id += p->batch_size; if (p->batch_size == 1) { clog_trace("<%s> Claim value %d (single-threaded)", p->name, p->last_claimed_id); } else { clog_trace("<%s> Claim values %d-%d (single-threaded)", p->name, p->last_claimed_id - p->batch_size + 1, p->last_claimed_id); } /* But we do have to wait until the slots for these new values are * free. */ return vrt_wait_for_slot(q, p); }
int vrt_producer_publish(struct vrt_producer *p) { if (p->last_produced_id == p->last_claimed_id) { return p->publish(p->queue, p, p->last_claimed_id); } else { clog_trace("<%s> Wait to publish %d until end of batch (at %d)", p->name, p->last_produced_id, p->last_claimed_id); return 0; } }
/* Claims the next ID that this producer can fill in. The new value's * ID will be stored in p->last_produced_id. You can get the value * itself using vrt_queue_get. */ static int vrt_producer_claim_raw(struct vrt_queue *q, struct vrt_producer *p) { if (p->last_produced_id == p->last_claimed_id) { rii_check(p->claim(q, p)); } p->last_produced_id++; clog_trace("<%s> Claimed value %d (%d is available)\n", p->name, p->last_produced_id, p->last_claimed_id); return 0; }
struct vrt_producer * vrt_producer_new(const char *name, unsigned int batch_size, struct vrt_queue *q) { struct vrt_producer *p; unsigned int maximum_batch_size; p = cork_new(struct vrt_producer); memset(p, 0, sizeof(struct vrt_producer)); p->name = cork_strdup(name); ei_check(vrt_queue_add_producer(q, p)); if (batch_size == 0) { batch_size = DEFAULT_BATCH_SIZE; } maximum_batch_size = vrt_queue_size(q) / 4; if (batch_size > maximum_batch_size) { batch_size = maximum_batch_size; } clog_trace("<%s> Batch size is %u", name, batch_size); p->last_produced_id = starting_value; p->last_claimed_id = starting_value; p->batch_size = batch_size; p->yield = NULL; p->batch_count = 0; p->yield_count = 0; return p; error: if (p->name != NULL) { cork_strfree(p->name); } cork_delete(struct vrt_producer, p); return NULL; }
static struct bz_version * bz_version_from_rpm_any(const char *rpm_version) { int cs; const char *p = rpm_version; const char *pe = strchr(rpm_version, '\0'); const char *eof = pe; struct bz_version *version; enum bz_version_part_kind kind; const char *start; struct cork_buffer buf = CORK_BUFFER_INIT(); clog_trace("Parse any RPM version \"%s\"", rpm_version); version = bz_version_new(); #line 560 "libbuzzy/distro/rpm.c" static const int rpm_version_any_start = 1; static const int rpm_version_any_en_main = 1; #line 566 "libbuzzy/distro/rpm.c" { cs = rpm_version_any_start; } #line 571 "libbuzzy/distro/rpm.c" { if ( p == pe ) goto _test_eof; switch ( cs ) { case 1: if ( 48 <= (*p) && (*p) <= 57 ) goto tr0; goto st0; st0: cs = 0; goto _out; tr0: #line 272 "libbuzzy/distro/rpm.c.rl" { kind = BZ_VERSION_RELEASE; start = p; clog_trace(" Create new release version part"); } goto st2; tr4: #line 290 "libbuzzy/distro/rpm.c.rl" { size_t size = p - start; clog_trace(" String value: %.*s", (int) size, start); ei_check(bz_version_add_part(version, kind, start, size)); } #line 272 "libbuzzy/distro/rpm.c.rl" { kind = BZ_VERSION_RELEASE; start = p; clog_trace(" Create new release version part"); } goto st2; st2: if ( ++p == pe ) goto _test_eof2; case 2: #line 610 "libbuzzy/distro/rpm.c" switch( (*p) ) { case 43: goto tr2; case 45: goto tr3; case 46: goto tr2; case 95: goto tr2; } if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) goto tr4; } else if ( (*p) > 90 ) { if ( 97 <= (*p) && (*p) <= 122 ) goto tr5; } else goto tr5; goto st0; tr2: #line 290 "libbuzzy/distro/rpm.c.rl" { size_t size = p - start; clog_trace(" String value: %.*s", (int) size, start); ei_check(bz_version_add_part(version, kind, start, size)); } goto st3; st3: if ( ++p == pe ) goto _test_eof3; case 3: #line 638 "libbuzzy/distro/rpm.c" switch( (*p) ) { case 43: goto st3; case 46: goto st3; case 95: goto st3; } if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) goto tr7; } else if ( (*p) > 90 ) { if ( 97 <= (*p) && (*p) <= 122 ) goto tr8; } else goto tr8; goto st0; tr7: #line 272 "libbuzzy/distro/rpm.c.rl" { kind = BZ_VERSION_RELEASE; start = p; clog_trace(" Create new release version part"); } goto st4; tr18: #line 290 "libbuzzy/distro/rpm.c.rl" { size_t size = p - start; clog_trace(" String value: %.*s", (int) size, start); ei_check(bz_version_add_part(version, kind, start, size)); } #line 272 "libbuzzy/distro/rpm.c.rl" { kind = BZ_VERSION_RELEASE; start = p; clog_trace(" Create new release version part"); } goto st4; st4: if ( ++p == pe ) goto _test_eof4; case 4: #line 679 "libbuzzy/distro/rpm.c" switch( (*p) ) { case 43: goto tr2; case 45: goto tr3; case 46: goto tr2; case 95: goto tr2; } if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) goto st4; } else if ( (*p) > 90 ) { if ( 97 <= (*p) && (*p) <= 122 ) goto tr5; } else goto tr5; goto st0; tr3: #line 290 "libbuzzy/distro/rpm.c.rl" { size_t size = p - start; clog_trace(" String value: %.*s", (int) size, start); ei_check(bz_version_add_part(version, kind, start, size)); } goto st5; st5: if ( ++p == pe ) goto _test_eof5; case 5: #line 707 "libbuzzy/distro/rpm.c" switch( (*p) ) { case 48: goto st6; case 49: goto tr11; } if ( 50 <= (*p) && (*p) <= 57 ) goto tr12; goto st0; st6: if ( ++p == pe ) goto _test_eof6; case 6: if ( (*p) == 46 ) goto st7; goto st0; st7: if ( ++p == pe ) goto _test_eof7; case 7: if ( 48 <= (*p) && (*p) <= 57 ) goto tr14; goto st0; tr21: #line 290 "libbuzzy/distro/rpm.c.rl" { size_t size = p - start; clog_trace(" String value: %.*s", (int) size, start); ei_check(bz_version_add_part(version, kind, start, size)); } #line 272 "libbuzzy/distro/rpm.c.rl" { kind = BZ_VERSION_RELEASE; start = p; clog_trace(" Create new release version part"); } goto st10; tr12: #line 284 "libbuzzy/distro/rpm.c.rl" { kind = BZ_VERSION_POSTRELEASE; start = p; clog_trace(" Create new postrelease version part"); } goto st10; tr14: #line 278 "libbuzzy/distro/rpm.c.rl" { kind = BZ_VERSION_PRERELEASE; start = p; clog_trace(" Create new prerelease version part"); } goto st10; st10: if ( ++p == pe ) goto _test_eof10; case 10: #line 763 "libbuzzy/distro/rpm.c" switch( (*p) ) { case 43: goto tr20; case 46: goto tr20; case 95: goto tr20; } if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) goto tr21; } else if ( (*p) > 90 ) { if ( 97 <= (*p) && (*p) <= 122 ) goto tr22; } else goto tr22; goto st0; tr20: #line 290 "libbuzzy/distro/rpm.c.rl" { size_t size = p - start; clog_trace(" String value: %.*s", (int) size, start); ei_check(bz_version_add_part(version, kind, start, size)); } goto st8; st8: if ( ++p == pe ) goto _test_eof8; case 8: #line 790 "libbuzzy/distro/rpm.c" switch( (*p) ) { case 43: goto st8; case 46: goto st8; case 95: goto st8; } if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) goto tr16; } else if ( (*p) > 90 ) { if ( 97 <= (*p) && (*p) <= 122 ) goto tr17; } else goto tr17; goto st0; tr16: #line 272 "libbuzzy/distro/rpm.c.rl" { kind = BZ_VERSION_RELEASE; start = p; clog_trace(" Create new release version part"); } goto st11; tr24: #line 290 "libbuzzy/distro/rpm.c.rl" { size_t size = p - start; clog_trace(" String value: %.*s", (int) size, start); ei_check(bz_version_add_part(version, kind, start, size)); } #line 272 "libbuzzy/distro/rpm.c.rl" { kind = BZ_VERSION_RELEASE; start = p; clog_trace(" Create new release version part"); } goto st11; st11: if ( ++p == pe ) goto _test_eof11; case 11: #line 831 "libbuzzy/distro/rpm.c" switch( (*p) ) { case 43: goto tr20; case 46: goto tr20; case 95: goto tr20; } if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) goto st11; } else if ( (*p) > 90 ) { if ( 97 <= (*p) && (*p) <= 122 ) goto tr22; } else goto tr22; goto st0; tr17: #line 272 "libbuzzy/distro/rpm.c.rl" { kind = BZ_VERSION_RELEASE; start = p; clog_trace(" Create new release version part"); } goto st12; tr22: #line 290 "libbuzzy/distro/rpm.c.rl" { size_t size = p - start; clog_trace(" String value: %.*s", (int) size, start); ei_check(bz_version_add_part(version, kind, start, size)); } #line 272 "libbuzzy/distro/rpm.c.rl" { kind = BZ_VERSION_RELEASE; start = p; clog_trace(" Create new release version part"); } goto st12; st12: if ( ++p == pe ) goto _test_eof12; case 12: #line 872 "libbuzzy/distro/rpm.c" switch( (*p) ) { case 43: goto tr20; case 46: goto tr20; case 95: goto tr20; } if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) goto tr24; } else if ( (*p) > 90 ) { if ( 97 <= (*p) && (*p) <= 122 ) goto st12; } else goto st12; goto st0; tr11: #line 284 "libbuzzy/distro/rpm.c.rl" { kind = BZ_VERSION_POSTRELEASE; start = p; clog_trace(" Create new postrelease version part"); } goto st13; st13: if ( ++p == pe ) goto _test_eof13; case 13: #line 899 "libbuzzy/distro/rpm.c" switch( (*p) ) { case 43: goto tr20; case 46: goto tr20; case 95: goto tr20; } if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) goto tr21; } else if ( (*p) > 90 ) { if ( 97 <= (*p) && (*p) <= 122 ) goto tr22; } else goto tr22; goto st0; tr8: #line 272 "libbuzzy/distro/rpm.c.rl" { kind = BZ_VERSION_RELEASE; start = p; clog_trace(" Create new release version part"); } goto st9; tr5: #line 290 "libbuzzy/distro/rpm.c.rl" { size_t size = p - start; clog_trace(" String value: %.*s", (int) size, start); ei_check(bz_version_add_part(version, kind, start, size)); } #line 272 "libbuzzy/distro/rpm.c.rl" { kind = BZ_VERSION_RELEASE; start = p; clog_trace(" Create new release version part"); } goto st9; st9: if ( ++p == pe ) goto _test_eof9; case 9: #line 940 "libbuzzy/distro/rpm.c" switch( (*p) ) { case 43: goto tr2; case 45: goto tr3; case 46: goto tr2; case 95: goto tr2; } if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) goto tr18; } else if ( (*p) > 90 ) { if ( 97 <= (*p) && (*p) <= 122 ) goto st9; } else goto st9; goto st0; } _test_eof2: cs = 2; goto _test_eof; _test_eof3: cs = 3; goto _test_eof; _test_eof4: cs = 4; goto _test_eof; _test_eof5: cs = 5; goto _test_eof; _test_eof6: cs = 6; goto _test_eof; _test_eof7: cs = 7; goto _test_eof; _test_eof10: cs = 10; goto _test_eof; _test_eof8: cs = 8; goto _test_eof; _test_eof11: cs = 11; goto _test_eof; _test_eof12: cs = 12; goto _test_eof; _test_eof13: cs = 13; goto _test_eof; _test_eof9: cs = 9; goto _test_eof; _test_eof: {} if ( p == eof ) { switch ( cs ) { case 10: case 11: case 12: #line 290 "libbuzzy/distro/rpm.c.rl" { size_t size = p - start; clog_trace(" String value: %.*s", (int) size, start); ei_check(bz_version_add_part(version, kind, start, size)); } break; #line 984 "libbuzzy/distro/rpm.c" } } _out: {} } #line 337 "libbuzzy/distro/rpm.c.rl" /* A hack to suppress some unused variable warnings */ (void) rpm_version_any_en_main; if (CORK_UNLIKELY(cs < #line 998 "libbuzzy/distro/rpm.c" 10 #line 342 "libbuzzy/distro/rpm.c.rl" )) { goto error; } bz_version_finalize(version); cork_buffer_done(&buf); return version; error: cork_buffer_done(&buf); bz_version_free(version); return NULL; }
/* Retrieves the next value from the consumer's queue. When this * returns c->current_id will be the ID of the next value. You can * retrieve the value using vrt_queue_get. */ static int vrt_consumer_next_raw(struct vrt_queue *q, struct vrt_consumer *c) { /* We've just finished processing the current_id'th value. */ vrt_value_id last_consumed_id = c->current_id++; /* If we know there are values available that we haven't yet * consumed, go ahead and return one. */ if (vrt_mod_le(c->current_id, c->last_available_id)) { clog_trace("<%s> Next value is %d (already available)", c->name, c->current_id); return 0; } /* We've run out of values that we know can been processed. Notify * the world how much we've processed so far. */ clog_debug("<%s> Signal consumption of %d", c->name, last_consumed_id); vrt_consumer_set_cursor(c, last_consumed_id); /* Check to see if there are any more values that we can process. */ if (cork_array_is_empty(&c->dependencies)) { bool first = true; vrt_value_id last_available_id; clog_debug("<%s> Wait for value %d", c->name, c->current_id); /* If we don't have any dependencies check the queue itself to see how * many values have been published. */ last_available_id = vrt_queue_get_cursor(q); while (vrt_mod_le(last_available_id, last_consumed_id)) { clog_trace("<%s> Last available value is %d (wait)", c->name, last_available_id); c->yield_count++; rii_check(vrt_yield_strategy_yield (c->yield, first, q->name, c->name)); first = false; last_available_id = vrt_queue_get_cursor(q); } c->last_available_id = last_available_id; clog_debug("<%s> Last available value is %d", c->name, last_available_id); } else { bool first = true; vrt_value_id last_available_id; clog_debug("<%s> Wait for value %d from dependencies", c->name, c->current_id); /* If there are dependencies we can only process what they've *all* * finished processing. */ last_available_id = vrt_consumer_find_last_dependent_id(c); while (vrt_mod_le(last_available_id, last_consumed_id)) { clog_trace("<%s> Last available value is %d (wait)", c->name, last_available_id); c->yield_count++; rii_check(vrt_yield_strategy_yield (c->yield, first, q->name, c->name)); first = false; last_available_id = vrt_consumer_find_last_dependent_id(c); } c->last_available_id = last_available_id; clog_debug("<%s> Last available value is %d", c->name, last_available_id); } c->batch_count++; /* Once we fall through to here, we know that there are additional * values that we can process. */ clog_trace("<%s> Next value is %d", c->name, c->current_id); return 0; }