Fix ovnisort with flush events
Sort the events in the sorting region before injecting them back in the stream. This solves the problem with flush events OF[ and OF].
This commit is contained in:
		
							parent
							
								
									929af74d3f
								
							
						
					
					
						commit
						5a9086e6d1
					
				| @ -7,8 +7,9 @@ | ||||
|  * we go back until we find a suitable position and start injecting the events | ||||
|  * in order. | ||||
|  * | ||||
|  * The events inside a unsorted region must be ordered. And the number of events | ||||
|  * that we will look back is limited by N. | ||||
|  * The events inside a unsorted region may not be ordered, they will be sorted | ||||
|  * by qsort() first. The number of events that we will look back is limited by | ||||
|  * N. | ||||
|  */ | ||||
| 
 | ||||
| #include <fcntl.h> | ||||
| @ -78,8 +79,6 @@ find_destination(struct ring *r, uint64_t clock) | ||||
| { | ||||
| 	ssize_t nback = 0; | ||||
| 
 | ||||
| 	UNUSED(nback); | ||||
| 
 | ||||
| 	ssize_t start = r->tail - 1 >= 0 ? r->tail - 1 : r->size - 1; | ||||
| 	ssize_t end = r->head - 1 >= 0 ? r->head - 1 : r->size - 1; | ||||
| 	uint64_t last_clock = 0; | ||||
| @ -125,50 +124,130 @@ ends_unsorted_region(struct ovni_ev *ev) | ||||
| 	return ev->header.model == 'O' && ev->header.category == 'U' && ev->header.value == ']'; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| sort_buf(uint8_t *src, uint8_t *buf, int64_t bufsize, | ||||
| 		uint8_t *srcbad, uint8_t *srcnext) | ||||
| static uint64_t | ||||
| find_min_clock(uint8_t *src, uint8_t *end) | ||||
| { | ||||
| 	int64_t injected = 0; | ||||
| 
 | ||||
| 	UNUSED(injected); | ||||
| 
 | ||||
| 	uint8_t *p = src; | ||||
| 	uint8_t *q = srcbad; | ||||
| 	struct ovni_ev *ev0 = (struct ovni_ev *) p; | ||||
| 	uint64_t min_clock = ev0->header.clock; | ||||
| 
 | ||||
| 	while (1) { | ||||
| 		struct ovni_ev *ep = (struct ovni_ev *) p; | ||||
| 		struct ovni_ev *eq = (struct ovni_ev *) q; | ||||
| 		struct ovni_ev *ev = NULL; | ||||
| 
 | ||||
| 		int64_t evsize = 0; | ||||
| 
 | ||||
| 		if (p < srcbad && ep->header.clock < eq->header.clock) { | ||||
| 			ev = ep; | ||||
| 			evsize = ovni_ev_size(ev); | ||||
| 			p += evsize; | ||||
| 		} else { | ||||
| 			ev = eq; | ||||
| 			evsize = ovni_ev_size(ev); | ||||
| 			q += evsize; | ||||
| 		} | ||||
| 
 | ||||
| 		if ((uint8_t *) ev == srcnext) | ||||
| 		if (p >= end) | ||||
| 			break; | ||||
| 
 | ||||
| 		if ((uint8_t *) ev > srcnext) | ||||
| 			die("exceeded srcnext while sorting"); | ||||
| 		struct ovni_ev *ev = (struct ovni_ev *) p; | ||||
| 		if (ev->header.clock < min_clock) | ||||
| 			min_clock = ev->header.clock; | ||||
| 
 | ||||
| 		if (bufsize < evsize) | ||||
| 			die("no space left in the sort buffer"); | ||||
| 
 | ||||
| 		memcpy(buf, ev, evsize); | ||||
| 		buf += evsize; | ||||
| 		bufsize -= evsize; | ||||
| 		injected++; | ||||
| 		p += ovni_ev_size(ev); | ||||
| 	} | ||||
| 
 | ||||
| 	dbg("injected %ld events in the past", injected); | ||||
| 	return min_clock; | ||||
| } | ||||
| 
 | ||||
| static long | ||||
| count_events(uint8_t *src, uint8_t *end) | ||||
| { | ||||
| 	uint8_t *p = src; | ||||
| 	long n = 0; | ||||
| 
 | ||||
| 	while (1) { | ||||
| 		if (p >= end) | ||||
| 			break; | ||||
| 
 | ||||
| 		struct ovni_ev *ev = (struct ovni_ev *) p; | ||||
| 		p += ovni_ev_size(ev); | ||||
| 		n++; | ||||
| 	} | ||||
| 
 | ||||
| 	return n; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| index_events(struct ovni_ev **table, long n, uint8_t *buf) | ||||
| { | ||||
| 	uint8_t *p = buf; | ||||
| 
 | ||||
| 	for (long i = 0; i < n; i++) { | ||||
| 		table[i] = (struct ovni_ev *) p; | ||||
| 		p += ovni_ev_size(table[i]); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| write_events(struct ovni_ev **table, long n, uint8_t *buf) | ||||
| { | ||||
| 	for (long i = 0; i < n; i++) { | ||||
| 		struct ovni_ev *ev = table[i]; | ||||
| 		size_t size = ovni_ev_size(ev); | ||||
| 		memcpy(buf, ev, size); | ||||
| 		buf += size; | ||||
| 
 | ||||
| 		dbg("injected event %c%c%c at %ld", | ||||
| 				ev->header.model, | ||||
| 				ev->header.category, | ||||
| 				ev->header.value, | ||||
| 				ev->header.clock); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| cmp_ev(const void *a, const void *b) | ||||
| { | ||||
| 	struct ovni_ev **pev1 = (struct ovni_ev **) a; | ||||
| 	struct ovni_ev **pev2 = (struct ovni_ev **) b; | ||||
| 
 | ||||
| 	struct ovni_ev *ev1 = *pev1; | ||||
| 	struct ovni_ev *ev2 = *pev2; | ||||
| 
 | ||||
| 	int64_t clock1 = ev1->header.clock; | ||||
| 	int64_t clock2 = ev2->header.clock; | ||||
| 
 | ||||
| 	if (clock1 < clock2) | ||||
| 		return -1; | ||||
| 	if (clock1 > clock2) | ||||
| 		return +1; | ||||
| 	else | ||||
| 		return 0; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| sort_buf(uint8_t *src, uint8_t *buf, int64_t bufsize) | ||||
| { | ||||
| 	struct ovni_ev *ev = (struct ovni_ev *) src; | ||||
| 
 | ||||
| 	dbg("first event before sorting %c%c%c at %ld", | ||||
| 			ev->header.model, | ||||
| 			ev->header.category, | ||||
| 			ev->header.value, | ||||
| 			ev->header.clock); | ||||
| 
 | ||||
| 	/* Create a copy of the array */ | ||||
| 	uint8_t *buf2 = malloc(bufsize); | ||||
| 	if (buf2 == NULL) | ||||
| 		die("malloc failed:"); | ||||
| 
 | ||||
| 	memcpy(buf2, src, bufsize); | ||||
| 
 | ||||
| 	long n = count_events(buf2, buf2 + bufsize); | ||||
| 	struct ovni_ev **table = calloc(n, sizeof(struct ovni_ev *)); | ||||
| 	if (table == NULL) | ||||
| 		die("calloc failed:"); | ||||
| 
 | ||||
| 	index_events(table, n, buf2); | ||||
| 	qsort(table, n, sizeof(struct ovni_ev *), cmp_ev); | ||||
| 	write_events(table, n, buf); | ||||
| 
 | ||||
| 	dbg("first event after sorting %c%c%c at %ld", | ||||
| 			ev->header.model, | ||||
| 			ev->header.category, | ||||
| 			ev->header.value, | ||||
| 			ev->header.clock); | ||||
| 
 | ||||
| 	free(table); | ||||
| 	free(buf2); | ||||
| 
 | ||||
| 	dbg("sorted %ld events", n); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| @ -190,14 +269,21 @@ write_stream(int fd, void *base, void *dst, const void *src, size_t size) | ||||
| static int | ||||
| execute_sort_plan(struct sortplan *sp) | ||||
| { | ||||
| 	uint64_t clock0 = sp->bad0->header.clock; | ||||
| 	dbg("attempt to sort: start clock %ld", sp->bad0->header.clock); | ||||
| 
 | ||||
| 	/* Cannot sort in one pass; just fail for now */ | ||||
| 	int64_t i0 = find_destination(sp->r, sp->bad0->header.clock); | ||||
| 	if (i0 < 0) { | ||||
| 		err("cannot find destination for region starting at clock %ld", | ||||
| 				sp->bad0->header.clock); | ||||
| 	uint64_t min_clock = find_min_clock((void *) sp->bad0, (void *) sp->next); | ||||
| 
 | ||||
| 	if (min_clock < clock0) { | ||||
| 		clock0 = min_clock; | ||||
| 		dbg("region not sorted, using min clock=%ld", clock0); | ||||
| 	} | ||||
| 
 | ||||
| 	/* Cannot sort in one pass; just fail for now */ | ||||
| 	int64_t i0 = find_destination(sp->r, clock0); | ||||
| 	if (i0 < 0) { | ||||
| 		err("cannot find destination for region starting at clock %ld", clock0); | ||||
| 		err("consider increasing the look back size with -n"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| @ -214,11 +300,8 @@ execute_sort_plan(struct sortplan *sp) | ||||
| 	if (!buf) | ||||
| 		die("malloc failed:"); | ||||
| 
 | ||||
| 	sort_buf((uint8_t *) first, buf, bufsize, | ||||
| 			(uint8_t *) sp->bad0, (uint8_t *) sp->next); | ||||
| 	sort_buf((uint8_t *) first, buf, bufsize); | ||||
| 
 | ||||
| 	/* Copy the sorted events back into the stream buffer */ | ||||
| 	memcpy(first, buf, bufsize); | ||||
| 	write_stream(sp->fd, sp->base, first, buf, bufsize); | ||||
| 
 | ||||
| 	free(buf); | ||||
| @ -448,6 +531,9 @@ main(int argc, char *argv[]) | ||||
| { | ||||
| 	progname_set("ovnisort"); | ||||
| 
 | ||||
| 	if (getenv("OVNI_DEBUG") != NULL) | ||||
| 		enable_debug(); | ||||
| 
 | ||||
| 	parse_args(argc, argv); | ||||
| 
 | ||||
| 	struct trace *trace = calloc(1, sizeof(struct trace)); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user