void lease_add(Lease *lease) { List *exits = lease->wavefront; assert(!lease->isexit || null(exits)); hash_set(lease_by_root_pathname, lease->pathname, lease); for ( ; !null(exits); exits = cdr(exits)) { Lease *exit = car(exits); assert(exit->isexit); hash_set(lease_by_root_pathname, exit->pathname, exit); } lease->lastchange = now_double(); }
Lease *lease_new(char *pathname, Address *addr, int isexit, Claim *claim, int readonly) { Lease *l = GC_NEW(Lease); assert(l != NULL); l->wait_for_update = NULL; l->inflight = 0; l->changeinprogress = 0; l->changeexits = NULL; l->changefids = NULL; l->pathname = pathname; l->addr = addr; l->wavefront = NULL; l->isexit = isexit; if (isexit) { l->claim = NULL; l->fids = NULL; l->claim_cache = NULL; l->dir_cache = NULL; } else { l->claim = claim; l->claim->lease = l; l->fids = hash_create(LEASE_FIDS_HASHTABLE_SIZE, (Hashfunc) fid_hash, (Cmpfunc) fid_cmp); l->claim_cache = hash_create( LEASE_CLAIM_HASHTABLE_SIZE, (Hashfunc) string_hash, (Cmpfunc) strcmp); l->dir_cache = hash_create( LEASE_DIR_HASHTABLE_SIZE, (Hashfunc) dir_block_hash, (Cmpfunc) dir_block_cmp); } l->readonly = readonly; l->lastchange = now_double(); return l; }
void lease_remove(Lease *lease) { assert(null(lease->wavefront)); assert(lease->fids == NULL || hash_count(lease->fids) == 0); assert(null(lease->changeexits)); assert(null(lease->changefids)); if (lease->isexit) { lease_unlink_exit(lease); } else { claim_clear_descendents(lease->claim); lease_clear_dir_cache(lease); } hash_remove(lease_by_root_pathname, lease->pathname); lease->pathname = NULL; lease->addr = NULL; lease->claim = NULL; lease->lastchange = now_double(); }
void lease_merge_exit(Worker *worker, Lease *parent, Lease *child) { Claim *claim; assert(parent->wait_for_update == worker && child->wait_for_update == worker); assert(parent->inflight == 0 && child->inflight == 0); assert(!child->isexit && !parent->isexit); /* assert(!parent->readonly); assert(!child->readonly); */ /* prevent lookups on the old lease */ hash_remove(lease_by_root_pathname, child->pathname); /* find the immediate parent and add this child */ claim = claim_find(worker, dirname(child->pathname)); assert(claim != NULL && claim->lease == parent); claim_link_child(claim, child->claim); /* merge the fids */ hash_apply(child->fids, (void (*)(void *, void *, void *)) hash_set, parent->fids); child->fids = NULL; /* merge the claim cache */ hash_apply(child->claim_cache, (void (*)(void *, void *, void *)) lease_merge_iter_claim_cache, parent); child->claim_cache = NULL; /* merge the dir cache */ hash_apply(child->dir_cache, (void (*)(void *, void *, void *)) lease_merge_iter_dir_cache, parent); child->dir_cache = NULL; /* merge in the wavefront */ for ( ; !null(child->wavefront); child->wavefront = cdr(child->wavefront)) lease_link_exit((Lease *) car(child->wavefront)); parent->lastchange = now_double(); }
int main(int argc, char **argv) { test_state tstate = {0}; nitro_queue_t *q = nitro_queue_new(0, test_state_callback, &tstate); TEST("new non-null", q); nitro_frame_t *hello = nitro_frame_new_copy( "hello", 6); nitro_queue_push(q, hello, 1); TEST("queue went contents", tstate.got_state_change && tstate.state_was == NITRO_QUEUE_STATE_CONTENTS); tstate.got_state_change = 0; nitro_frame_t *back = nitro_queue_pull(q, 1); TEST("got frame back", back == hello); TEST("queue went empty", tstate.got_state_change && tstate.state_was == NITRO_QUEUE_STATE_EMPTY); tstate.got_state_change = 0; /* Ordering */ nitro_frame_t *world = nitro_frame_new_copy( "world", 6); nitro_queue_push(q, hello, 1); nitro_queue_push(q, world, 1); back = nitro_queue_pull(q, 1); TEST("got hello (ordering)", back == hello); back = nitro_queue_pull(q, 1); TEST("got world (ordering)", back == world); nitro_queue_destroy(q); q = nitro_queue_new(0, test_state_callback, &tstate); /* Wrapping */ TEST("pre-wrapping empty queue", nitro_queue_count(q) == 0); TEST("pre-wrapping internal assumption", q->size == 1024); int i; for (i=0; i < 1023; i++) { nitro_frame_t *hcopy = nitro_frame_copy_partial(hello, NULL); nitro_queue_push(q, hcopy, 1); back = nitro_queue_pull(q, 1); assert(back == hcopy); nitro_frame_destroy(back); } nitro_queue_push(q, hello, 1); nitro_queue_push(q, world, 1); TEST("wrapping internals, wrap occurred", q->tail < q->head); back = nitro_queue_pull(q, 1); TEST("got hello (wrapping)", back == hello); back = nitro_queue_pull(q, 1); TEST("got world (wrapping)", back == world); TEST("wrapping internals, wrap back to even", q->tail == q->head); /* Destroy with frames in */ my_frame_data dt = {0}; nitro_frame_destroy(world); world = nitro_frame_new( "hello", 6, my_free, &dt); nitro_queue_push(q, world, 1); TEST("delete outstanding.. not deleted", dt.done == 0); nitro_queue_destroy(q); TEST("post-queue-delete.. frame free", dt.done); nitro_frame_destroy(hello); /* Queue count */ q = nitro_queue_new(0, test_state_callback, &tstate); hello = nitro_frame_new_copy("hello", 6); for (i=0; i < 313; i++) { back = nitro_frame_copy_partial(hello, NULL); nitro_queue_push(q, back, 1); } nitro_frame_destroy(hello); TEST("count basic", nitro_queue_count(q) == 313); /* resize */ nitro_queue_destroy(q); q = nitro_queue_new(0, test_state_callback, &tstate); assert(q->size == 1024); /* get the alignment off */ for (i=0; i < 100; i++) { nitro_queue_push(q, nitro_frame_new_copy((void*)&i, sizeof(int)), 1); } for (i=0; i < 100; i++) { back = nitro_queue_pull(q, 1); nitro_frame_destroy(back); } TEST("resize misalign reset", nitro_queue_count(q) == 0 && q->head > q->q); /* okay, now cause resize */ for (i=0; i < 1050; i++) { nitro_queue_push(q, nitro_frame_new_copy((void*)&i, sizeof(int)), 1); } TEST("was resized", q->size > 1024); for (i=0; i < 1050; i++) { back = nitro_queue_pull(q, 1); if ( *((int*)nitro_frame_data(back)) != i) break; nitro_frame_destroy(back); } TEST("order after resize", i == 1050); nitro_queue_destroy(q); /* Test queue moving */ /* move 0 -> 0 */ q = nitro_queue_new(0, test_state_callback, &tstate); nitro_queue_t *dst = nitro_queue_new(0, test_state_callback, &tstate); nitro_queue_move( q, dst); TEST("move(0->0) src empty", nitro_queue_count(q) == 0); TEST("move(0->0) dest empty", nitro_queue_count(dst) == 0); /* move N -> 0 */ for (i=0; i < 5; i++) { nitro_queue_push(q, nitro_frame_new_copy( (void *)&i, sizeof(int)), 1); } TEST("load 5 into src", nitro_queue_count(q) == 5); nitro_queue_move(q, dst); TEST("move(0->0) src empty", nitro_queue_count(q) == 0); TEST("move(0->0) dest 5", nitro_queue_count(dst) == 5); for (i=0; i < 5; i++) { back = nitro_queue_pull(dst, 1); if ( *((int*)nitro_frame_data(back)) != i) break; nitro_frame_destroy(back); } TEST("order after move", i == 5); nitro_queue_destroy(q); nitro_queue_destroy(dst); /* move with fractional wraparound, ugly copies */ q = nitro_queue_new(0, test_state_callback, &tstate); dst = nitro_queue_new(0, test_state_callback, &tstate); for (i=0; i < 300; i++) { nitro_queue_push(q, nitro_frame_new_copy( (void *)&i, sizeof(int)), 1); } for (i=0; i < 300; i++) { nitro_frame_destroy(nitro_queue_pull(q, 1)); } for (i=0; i < 700; i++) { nitro_queue_push(q, nitro_frame_new_copy( (void *)&i, sizeof(int)), 1); } for (i=0; i < 324; i++) { nitro_queue_push(dst, nitro_frame_new_copy( (void *)&i, sizeof(int)), 1); } for (i=0; i < 324; i++) { nitro_frame_destroy(nitro_queue_pull(dst, 1)); } for (i=0; i < 324; i++) { nitro_queue_push(dst, nitro_frame_new_copy( (void *)&i, sizeof(int)), 1); } TEST("(ugly move) count 700 src", nitro_queue_count(q) == 700); TEST("(ugly move) count 324 dst", nitro_queue_count(dst) == 324); nitro_queue_move(q, dst); TEST("(ugly move post) count 0 src", nitro_queue_count(q) == 0); TEST("(ugly move post) count 1024 dst", nitro_queue_count(dst) == 1024); assert(dst->size == 1024); /* no resizing! */ TEST("(ugly move post) head == tail", dst->head == dst->tail); for (i=0; i < 324; i++) { back = nitro_queue_pull(dst, 1); if ( *((int*)nitro_frame_data(back)) != i) break; nitro_frame_destroy(back); } TEST("(ugly move post) first 324 still there", i == 324); for (i=0; i < 700; i++) { back = nitro_queue_pull(dst, 1); if ( *((int*)nitro_frame_data(back)) != i) break; nitro_frame_destroy(back); } TEST("(ugly move post) appended 700 there", i == 700); TEST("(ugly move post) dst emptied", nitro_queue_count(dst) == 0); nitro_queue_destroy(q); nitro_queue_destroy(dst); /* move with resize */ q = nitro_queue_new(0, test_state_callback, &tstate); dst = nitro_queue_new(0, test_state_callback, &tstate); for (i=0; i < 1000; i++) { nitro_queue_push(q, nitro_frame_new_copy( (void *)&i, sizeof(int)), 1); } for (i=0; i < 324; i++) { nitro_queue_push(dst, nitro_frame_new_copy( (void *)&i, sizeof(int)), 1); } TEST("(resize move) count 1000 src", nitro_queue_count(q) == 1000); TEST("(resize move) count 324 dst", nitro_queue_count(dst) == 324); assert(dst->size == 1024); nitro_queue_move(q, dst); TEST("(resize post-move) size dst is sum", nitro_queue_count(dst) == 1324); assert(dst->size > 1024); for (i=0; i < 324; i++) { back = nitro_queue_pull(dst, 1); if ( *((int*)nitro_frame_data(back)) != i) break; nitro_frame_destroy(back); } TEST("(resize post-move) first 324 still there", i == 324); for (i=0; i < 1000; i++) { back = nitro_queue_pull(dst, 1); if ( *((int*)nitro_frame_data(back)) != i) break; nitro_frame_destroy(back); } TEST("(resize post-move) appended 1000 there", i == 1000); TEST("(resize post-move) dst cleared", nitro_queue_count(dst) == 0); nitro_queue_destroy(q); nitro_queue_destroy(dst); /* Capacity tests */ q = nitro_queue_new(5, test_state_callback, &tstate); for (i=0; i < 5; i++) { nitro_queue_push(q, nitro_frame_new_copy( (void *)&i, sizeof(int)), 1); } double d1 = now_double(); pthread_t t1; pthread_create(&t1, NULL, take_item, (void*)q); nitro_queue_push(q, nitro_frame_new_copy( (void *)&i, sizeof(int)), 1); double d2 = now_double(); TEST("(capacity) got blocked on push", (d2 - d1 > 0.7) && (d2 - d1 < 1.5)); for (i=1; i < 6; i++) { back = nitro_queue_pull(q, 1); if ( *((int*)nitro_frame_data(back)) != i) break; nitro_frame_destroy(back); } TEST("(capacity) have rest", i == 6); TEST("(capacity) emptied", nitro_queue_count(q) == 0); pthread_t t2; d1 = now_double(); pthread_create(&t2, NULL, put_item, (void*)q); back = nitro_queue_pull(q, 1); d2 = now_double(); TEST("(capacity) got blocked on empty pull", (d2 - d1 > 0.7) && (d2 - d1 < 1.5)); TEST("(capacity) empty pull got right frame", *((int*)nitro_frame_data(back)) == 1337); nitro_frame_destroy(back); nitro_queue_destroy(q); void *unused; pthread_join(t1, &unused); pthread_join(t2, &unused); /* Consume */ q = nitro_queue_new(0, test_state_callback, &tstate); gframe = nitro_frame_new_copy("hello", 6); /* Traditional test */ d1 = now_double(); for (i=0; i < CONSUME_COUNT; i++) { nitro_queue_push(q, nitro_frame_copy_partial(gframe, NULL), 1); } d2 = now_double(); char buf[50]; snprintf(buf, 50, "(consume-manual) in %.4f", d2 - d1); TEST(buf, nitro_queue_count(q) == CONSUME_COUNT); nitro_queue_destroy(q); // vs consume i = 0; q = nitro_queue_new(0, test_state_callback, &tstate); d1 = now_double(); nitro_queue_consume(q, make_frames, (void *)&i); d2 = now_double(); snprintf(buf, 50, "(consume-stream) in %.4f", d2 - d1); TEST(buf, nitro_queue_count(q) == CONSUME_COUNT); nitro_queue_destroy(q); nitro_frame_destroy(gframe); /* Write to file */ q = nitro_queue_new(0, test_state_callback, &tstate); for (i=0; i < 50000; i++) { nitro_queue_push(q, nitro_frame_new_copy( "dog", 3), 1); } int ps[2]; int r = pipe(ps); assert(!r); int pread = ps[0]; int pwrite = ps[1]; int flag = 1; r = ioctl(pread, FIONBIO, &flag); assert(r == 0); r = ioctl(pwrite, FIONBIO, &flag); assert(r == 0); int bytes = 0; int total = 0; nitro_frame_t *remain = NULL; pthread_t reader; char out[550000]; pipe_pass pp = {out, pread}; pthread_create(&reader, NULL, pipe_consume, &pp); do { errno = 0; if (bytes > 0) total += bytes; bytes = nitro_queue_fd_write( q, pwrite, remain, &remain); } while (bytes > 0 || errno == EAGAIN || errno == EWOULDBLOCK); if (bytes < 0) { perror("write to pipe:"); assert(bytes == 0); } TEST("(fd write) correct write byte count", total == 550000); void *t_ret; /* wait for reader to finish */ pthread_join(reader, &t_ret); char *ptr = out; nitro_protocol_header target_head = { 1, 0, 0, 0, 3}; for (i=0; i < 50000; i++) { if (memcmp(ptr, &target_head, sizeof(target_head)) || memcmp(ptr + sizeof(target_head), "dog", 3)) { break; } ptr += 11; } TEST("(fd write) read data was correct", ptr == out + 550000); close(pwrite); close(pread); nitro_queue_destroy(q); SUMMARY(0); return 1; }
/* -*- Mode: C; tab-width: 8; c-basic-offset: 2; indent-tabs-mode: nil; -*- */ #include "chaosutil.h" static double samples[10000000]; static size_t sample_count = 0; /* Given command-line parameters <S>, <T>, <D> and <L>: Spins the CPU on a single thread until L microseconds have elapsed. The test fails if, at some point starting between S and T microseconds, we fail to be scheduled for D microseconds */ int main(__attribute__((unused)) int argc, char** argv) { double start = now_double(); double S = atoi(argv[1]) / 1000000.0 + start; double T = atoi(argv[2]) / 1000000.0 + start; double D = atoi(argv[3]) / 1000000.0; double L = atoi(argv[4]) / 1000000.0 + start; int k = 0; double last = 0; atomic_printf("Critical range is %f to %f\n", S, T); while (1) { int i; double t; for (i = 0; i < 10000; ++i) { k += i * i; } t = now_double(); samples[sample_count++] = t;