Browse files

Fixing bugs and cleaning the pool queue code.

  • Loading branch information...
1 parent c395d9d commit f3a55fbaa6fcce4e67126a60c392356149692e8f Nick committed Feb 2, 2010
Showing with 337 additions and 230 deletions.
  1. +14 −5 src/barbershop.c
  2. +1 −13 src/barbershop.h
  3. +226 −123 src/scores.c
  4. +35 −17 src/scores.h
  5. +61 −72 tests/check_barbershop.c
View
19 src/barbershop.c
@@ -104,19 +104,28 @@ void on_read(int fd, short ev, void *arg) {
Position lookup = Find( item_id, items );
if (lookup == NULL) {
items = Insert(item_id, score, items);
- scores = AddScoreToPool(scores, score, item_id);
+ scores = promoteItem(scores, score, item_id, -1);
app_stats.items += 1;
app_stats.items_gc += 1;
} else {
int old_score = lookup->score;
- lookup->score += score;
- scores = PurgeThenAddScoreToPool(scores, lookup->score, item_id, old_score);
+ if (old_score == -1) {
+ lookup->score = 1;
+ } else {
+ lookup->score += score;
+ }
+ scores = promoteItem(scores, lookup->score, item_id, old_score);
}
app_stats.updates += 1;
reply(fd, "OK\r\n");
} else if (ntokens == 2 && strcmp(tokens[COMMAND_TOKEN].value, "next") == 0) {
- int next = GetNextItem(scores);
+ int next = -1;
+ scores = NextItem(scores, next);
if (next != -1) {
+ Position lookup = Find( next, items );
+ if (lookup != NULL) {
+ lookup->score = -1;
+ }
app_stats.items_gc -= 1;
}
char msg[32];
@@ -170,7 +179,7 @@ void on_accept(int fd, short ev, void *arg) {
int main(int argc, char **argv) {
items = MakeEmpty(NULL);
- scores = PrepScoreBucket(NULL);
+ scores = NULL;
time(&app_stats.started_at);
app_stats.version = "00.01.00";
View
14 src/barbershop.h
@@ -40,25 +40,13 @@ struct TreeNode {
SearchTree right;
};
-struct member_el {
- int item;
- MemberBucket next;
-};
-
-struct bucket_el {
- int score;
- int count;
- MemberBucket members;
- ScoreBucket next;
-};
-
typedef struct token_s {
char *value;
size_t length;
} token_t;
SearchTree items;
-ScoreBucket scores;
+PoolNode *scores;
static size_t tokenize_command(char *command, token_t *tokens, const size_t max_tokens);
void on_read(int fd, short ev, void *arg);
View
349 src/scores.c
@@ -26,150 +26,253 @@ THE SOFTWARE.
#include <stdlib.h>
#include <stdio.h>
-struct member_el {
- int item;
- MemberBucket next;
-};
-
-struct bucket_el {
- int score;
- int count;
- MemberBucket members;
- ScoreBucket next;
-};
-
-int GetNextItem(ScoreBucket head) {
- if (head == NULL) { return -1; }
- if (head->count > 0) {
- // This shouldn't be a two step process, O(n^2) -> 0(n)
- MemberBucket last = ReturnLastMember(head->members);
- head->members = DeleteMember(head->members, last->item);
- // If the pool has no members, decr pools_gc stats to reflect
- // non-garbage collected pool counts.
- if (head->members == NULL) {
- app_stats.pools_gc -= 1;
+PoolNode *pool_create(int score) {
+ PoolNode *node;
+ if (! (node = malloc(sizeof(PoolNode)))) {
+ return NULL;
+ }
+ node->score = score;
+ node->count = 0;
+ node->members = NULL;
+ node->next = NULL;
+ return node;
+}
+
+// XXX: Unused, to be removed.
+PoolNode *pool_insert_after(PoolNode *node, int score) {
+ PoolNode *newnode;
+ newnode = pool_create(score);
+ newnode->next = node->next;
+ node->next = newnode;
+ return newnode;
+}
+
+PoolNode *pool_push(PoolNode *list, int score) {
+ PoolNode *newnode;
+ newnode = pool_create(score);
+ newnode->next = list;
+ return newnode;
+}
+
+int pool_remove(PoolNode *list, PoolNode *node) {
+ while (list->next && list->next != node) {
+ list = list->next;
+ }
+ if (list->next) {
+ list->next = node->next;
+ free(node);
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+int pool_foreach(PoolNode *node, int(*func)(int, MemberNode*)) {
+ while (node) {
+ if (func(node->score, node->members) != 0) {
+ return -1;
}
- head->count -= 1;
- int item_id = last->item;
- free(last);
- return item_id;
- }
- return GetNextItem(head->next);
-}
-
-ScoreBucket PurgeThenAddScoreToPool(ScoreBucket bucket, int score, int item_id, int old_score) {
- ScoreBucket lookup = doesPoolExist(bucket, old_score);
- lookup->members = DeleteMember(lookup->members, item_id);
- assert(IsScoreMember(lookup->members, item_id) == 0);
- lookup->count -= 1;
- if (lookup->members == NULL) {
- app_stats.pools_gc -= 1;
- }
- return AddScoreToPool(bucket, score, item_id);
-}
-
-// TODO: This should be a self-sorting linked-list. All new pools
-// should be injected to retain uniqueness and order.
-ScoreBucket AddScoreToPool(ScoreBucket bucket, int score, int item_id) {
- printf("Adding %d to pool %d\n", item_id, score);
- ScoreBucket lookup = doesPoolExist(bucket, score);
- if (lookup == NULL) {
- ScoreBucket head = initScorePool(score, item_id);
- assert(IsScoreMember(head->members, item_id) == 1);
- head->next = bucket;
- return head;
- }
- lookup = AddScoreMember(lookup, item_id);
- assert(IsScoreMember(lookup->members, item_id) == 1);
- return lookup;
-}
-
-// TODO: Look into merging this into `AddScoreMember/2`
-ScoreBucket initScorePool(int score, int item_id) {
- ScoreBucket head = malloc(sizeof(ScoreBucket));
- if (head == NULL ) {
- exit(1);
+ node = node->next;
+ }
+ return 0;
+}
+
+PoolNode *pool_find(PoolNode *node, int(*func)(int, MemberNode*,void*), void *data) {
+ while (node) {
+ if (func(node->score, node->members, data) > 0) {
+ return node;
+ }
+ node = node->next;
+ }
+ return NULL;
+}
+
+MemberNode *member_create(int item) {
+ MemberNode *node;
+ if (! (node = malloc(sizeof(MemberNode)))) {
+ return NULL;
+ }
+ node->item = item;
+ node->next = NULL;
+ return node;
+}
+
+MemberNode *member_push(MemberNode *list, int item) {
+ MemberNode *newnode;
+ newnode = member_create(item);
+ newnode->next = list;
+ return newnode;
+}
+
+int member_remove(MemberNode *list, MemberNode *node) {
+ while (list->next && list->next != node) {
+ list = list->next;
+ }
+ if (list->next) {
+ list->next = node->next;
+ free(node);
+ return 0;
} else {
- MemberBucket member = malloc(sizeof(MemberBucket));
- member->item = item_id;
- member->next = NULL;
- head->members = member;
- head->score = score;
- head->count = 1;
- // Do it here we we can effectively see if the pool should be
- // created for the first time but may not have for one reason
- // or another.
- app_stats.pools += 1;
- app_stats.pools_gc += 1;
- return head;
+ return -1;
+ }
+}
+
+int member_foreach(MemberNode *node, int(*func)(int)) {
+ while (node) {
+ if (func(node->item) != 0) {
+ return -1;
+ }
+ node = node->next;
+ }
+ return 0;
+}
+
+MemberNode *member_find(MemberNode *node, int(*func)(int, void*), void *data) {
+ while (node) {
+ if (func(node->item, data) > 0) {
+ return node;
+ }
+ node = node->next;
}
return NULL;
}
-ScoreBucket AddScoreMember(ScoreBucket bucket, int item) {
- if (IsScoreMember(bucket->members, item)) {
- return bucket;
- }
- MemberBucket member = malloc(sizeof(MemberBucket));
- if (member == NULL ) {
- exit(1);
- } else {
- member->next = bucket->members;
- member->item = item;
- bucket->members = member;
- bucket->count += 1;
- return bucket;
- }
- return NULL;
+MemberNode *member_last(MemberNode *node) {
+ while (node) {
+ if (node->next == NULL) {
+ return node;
+ }
+ node = node->next;
+ }
+ return NULL;
}
-ScoreBucket PrepScoreBucket(ScoreBucket bucket) {
- if (bucket != NULL) {
- free(bucket);
- }
- return NULL;
+int find_by_score(int score, MemberNode *members, void *query) {
+ // printf("find_by_score(%d, NULL, %d)\n", score, query);
+ return score == query;
}
-int IsScoreMember(MemberBucket head, int item) {
- if (head == NULL) { return 0; }
- if (head->item == item) {return 1; }
- return IsScoreMember(head->next, item);
+int find_item(int item, void *query) {
+ // printf("find_item(%d, %d)\n", item, query);
+ return item == query;
}
-ScoreBucket doesPoolExist(ScoreBucket bucket, int score) {
- if (bucket == NULL) { return NULL; }
- if (bucket->score == score) { return bucket; }
- return doesPoolExist(bucket->next, score);
+int pool_print(int score, MemberNode *members) {
+ printf("Pool %d\n", score);
+ member_foreach(members, member_print);
+ return 0;
}
-void DumpScores(ScoreBucket head) {
- if (head == NULL) { return; }
- printf("Score %d (%d)", head->score, head->count);
- DumpMembers(head->members);
- printf("\n");
- DumpScores(head->next);
+int member_print(int item) {
+ printf(" -> item %d\n", item);
+ return 0;
}
-void DumpMembers(MemberBucket head) {
- if (head == NULL) { return; }
- printf(" %d", head->item);
- DumpMembers(head->next);
+int preparePromotion(PoolNode *list, int item, int score) {
+ // printf("preparePromotion called.\n");
+ PoolNode *listMatch;
+ if ((listMatch = pool_find(list, find_by_score, (void*)score))) {
+ // printf(" => found pool with score %d\n", score);
+ MemberNode *memberMatch;
+ if ((memberMatch = member_find(listMatch->members, find_item, (void*)item))) {
+ // printf(" => found member %d in pool %d\n", item, score);
+ listMatch->count--;
+ member_remove(listMatch->members, memberMatch);
+ return 1;
+ }
+ }
+ return 0;
}
-MemberBucket DeleteMember(MemberBucket head, int item) {
- if (head == NULL) { return NULL; }
- if (head->item == item) {
- return head->next;
+PoolNode *promoteItem(PoolNode *list, int score, int item, int old_score) {
+ if (old_score != -1) {
+ preparePromotion(list, item, old_score);
+ }
+ // printf("promoteItem called.\n");
+ if (list == NULL) {
+ // printf(" -> list is NULL\n");
+ PoolNode *newPool;
+ newPool = pool_create(score);
+ // printf(" -> Created newPool (score=%d)\n", newPool->score);
+ MemberNode *newMember;
+ newMember = member_create(item);
+ // printf(" -> Created newMember (item=%d)\n", newMember->item);
+ newPool->members = newMember;
+ newPool->count++;
+ return newPool;
+ }
+ PoolNode *listMatch;
+ // printf(" -> looking for score %d.\n", score);
+ if ((listMatch = pool_find(list, find_by_score, (void*)score))) {
+ // printf(" -> score pool exists (score=%d)\n", listMatch->score);
+ MemberNode *memberMatch;
+ if ((memberMatch = member_find(listMatch->members, find_item, (void*)item))) {
+ // printf(" -> item exists in pool\n");
+ } else {
+ // printf(" -> item does not exist in pool\n");
+ assert(listMatch != NULL);
+ assert(listMatch->members != NULL);
+ listMatch->members = member_push(listMatch->members, item);
+ // printf(" -> new member created (item=%d)\n", listMatch->members->item);
+ listMatch->count++;
+ // printf(" -> pool %d has %d members\n", listMatch->score, listMatch->count);
+ }
+ return list;
} else {
- head->next = DeleteMember(head->next, item);
+ // Score pool doesn't exist
+ // printf(" -> score pool doesn't exist\n");
+ PoolNode *newPool;
+ newPool = pool_create(score);
+ // printf(" -> Created newPool (score=%d)\n", newPool->score);
+ MemberNode *newMember;
+ newMember = member_create(item);
+ // printf(" -> Created newMember (item=%d)\n", newMember->item);
+ newPool->members = newMember;
+ newPool->count++;
+ newPool->next = list;
+ return newPool;
}
- return head;
+ return NULL;
}
-MemberBucket ReturnLastMember(MemberBucket head) {
- assert(head != NULL);
- if (head->next == NULL) {
- return head;
+// int NextItem(PoolNode *list) {
+// if (! list) { return -1; }
+// while (list->next && list->count > 0) {
+// list = list->next;
+// }
+// if (list != NULL && list->members != NULL) {
+// MemberNode *last = member_last(list->members);
+// int item_id = last->item;
+// list->count--;
+// if (list->members == 1) {
+// free(last);
+// list->members = NULL;
+// } else {
+// member_remove(list->members, last);
+// }
+// return item_id;
+// } else{
+// return -1;
+// }
+// }
+
+PoolNode *NextItem(PoolNode *list, int *next_item) {
+ if (list == NULL) { next_item = -1; return list; }
+ while (list->next && list->count == 0) {
+ list = list->next;
}
- return ReturnLastMember(head->next);
+ if (list != NULL && list->members != NULL) {
+ printf("We got this far ...\n");
+ MemberNode *last = member_last(list->members);
+ next_item = last->item;
+ printf("and now ...\n");
+ member_remove(list->members, next_item);
+ printf("and now ...\n");
+ if (list->members != NULL) { printf("first member item is %d\n", list->members->item); }
+ printf("count at %d\n", list->count);
+ list->count--;
+ return list;
+ }
+ return list;
}
+
View
52 src/scores.h
@@ -23,22 +23,40 @@ THE SOFTWARE.
#ifndef __SCORES_H__
#define __SCORES_H__
-struct member_el;
-struct bucket_el;
-typedef struct member_el *MemberBucket;
-typedef struct bucket_el *ScoreBucket;
-
-ScoreBucket PurgeThenAddScoreToPool(ScoreBucket bucket, int score, int item_id, int old_score);
-ScoreBucket AddScoreToPool(ScoreBucket bucket, int score, int item_id);
-ScoreBucket initScorePool(int score, int item_id);
-ScoreBucket AddScoreMember(ScoreBucket bucket, int item);
-ScoreBucket PrepScoreBucket(ScoreBucket bucket);
-int IsScoreMember(MemberBucket head, int item);
-ScoreBucket doesPoolExist(ScoreBucket bucket, int score);
-void DumpScores(ScoreBucket head);
-void DumpMembers(MemberBucket head);
-MemberBucket DeleteMember(MemberBucket head, int item);
-int GetNextItem(ScoreBucket head);
-MemberBucket ReturnLastMember(MemberBucket head);
+typedef struct node_member {
+ int item;
+ struct node_member *next;
+} MemberNode;
+
+typedef struct node_pool {
+ int score;
+ struct node_member *members;
+ int count;
+ struct node_pool *next;
+} PoolNode;
+
+PoolNode *pool_create(int score);
+PoolNode *pool_insert_after(PoolNode *node, int score);
+PoolNode *pool_push(PoolNode *list, int score);
+int pool_remove(PoolNode *list, PoolNode *node);
+int pool_foreach(PoolNode *node, int(*func)(int, MemberNode*));
+PoolNode *pool_find(PoolNode *node, int(*func)(int, MemberNode*,void*), void *data);
+
+MemberNode *member_create(int item);
+MemberNode *member_push(MemberNode *list, int item);
+int member_remove(MemberNode *list, MemberNode *node);
+int member_foreach(MemberNode *node, int(*func)(int));
+MemberNode *member_find(MemberNode *node, int(*func)(int, void*), void *item);
+MemberNode *member_last(MemberNode *node);
+
+int find_by_score(int score, MemberNode *members, void *query);
+int find_item(int item, void *query);
+
+int pool_print(int score, MemberNode *members);
+int member_print(int item);
+
+int preparePromotion(PoolNode *list, int item, int score);
+PoolNode *promoteItem(PoolNode *list, int score, int item, int old_score);
+PoolNode *NextItem(PoolNode *list, int *next_item);
#endif
View
133 tests/check_barbershop.c
@@ -4,87 +4,76 @@
#include <assert.h>
#include "../src/scores.h"
-struct member_el {
- int item;
- MemberBucket next;
-};
-
-struct bucket_el {
- int score;
- int count;
- MemberBucket members;
- ScoreBucket next;
-};
-
-START_TEST (test_scores_empty) {
- ScoreBucket bucket_a = PrepScoreBucket(NULL);
- fail_unless(bucket_a == NULL, "empty buckets aren't anything.");
- fail_unless(GetNextItem(bucket_a) == -1, "Empty buckets return no items.");
+START_TEST (test_pools_empty) {
+ PoolNode *a = NULL;
+ fail_unless(a == NULL, "empty pools are NULL.");
+ int next;
+ a = NextItem(a, &next);
+ fail_unless(next == -1, "Empty buckets return no items.");
} END_TEST
// Assert that counts are maintained while adding.
-START_TEST (test_scores_add) {
- ScoreBucket bucket_b = PrepScoreBucket(NULL);
- bucket_b = AddScoreToPool(bucket_b, 1, 5000);
- fail_unless(bucket_b->score == 1, "Adding items to buckets is reflected in the bucket score.");
- fail_unless(bucket_b->count == 1, "Adding items to buckets is reflected in the bucket count.");
- fail_unless(IsScoreMember(bucket_b->members, 5000) == 1, "Item 5000 is in bucket_b.");
- fail_unless(IsScoreMember(bucket_b->members, 5001) == 0, "Item 5001 is not in bucket_b.");
- fail_unless(GetNextItem(bucket_b) == 5000, "Next returns item 5000.");
- fail_unless(IsScoreMember(bucket_b->members, 5000) == 0, "Item 5000 was pulled from bucket_b.");
- fail_unless(bucket_b->members == NULL, "has no members");
- fail_unless(bucket_b->count == 0, "has count of 0");
- fail_unless(bucket_b->next == NULL, "next goes nowhere.");
-} END_TEST
-
-// Assert insert order is maintained.
-START_TEST (test_scores_add_several) {
- ScoreBucket bucket_c = PrepScoreBucket(NULL);
- bucket_c = AddScoreToPool(bucket_c, 1, 5000);
- bucket_c = AddScoreToPool(bucket_c, 1, 5001);
- bucket_c = AddScoreToPool(bucket_c, 1, 5002);
- fail_if(bucket_c->members == NULL, "has members");
- fail_unless(bucket_c->count == 3, "has count of 3");
- fail_unless(GetNextItem(bucket_c) == 5000, "Next returns item 5000.");
- fail_unless(GetNextItem(bucket_c) == 5001, "Next returns item 5001.");
- fail_unless(GetNextItem(bucket_c) == 5002, "Next returns item 5002.");
- fail_unless(bucket_c->members == NULL, "has no members left");
- fail_unless(bucket_c->count == 0, "has count of 0");
-} END_TEST
-
-// Assert promoting ensures accurate counts and membership
-START_TEST (test_scores_promote) {
- ScoreBucket bucket_d = PrepScoreBucket(NULL);
- bucket_d = AddScoreToPool(bucket_d, 1, 5000);
- fail_unless(bucket_d->count == 1, "bucket_d[0] has one item");
- fail_unless(bucket_d->score == 1, "bucket_d[0] score is 1");
- bucket_d = PurgeThenAddScoreToPool(bucket_d, 2, 5000, 1);
-
- fail_unless(IsScoreMember(bucket_d->members, 5000) == 1, "bucket_d[0] has item 5000");
-
- printf("Dumping score buckets:\n");
- DumpScores(bucket_d);
-
- fail_unless(bucket_d->count == 1, "bucket_d[1] has one item");
- fail_unless(bucket_d->next->count == 0, "bucket_d[0] has no items");
- fail_unless(bucket_d->score == 2, "bucket_d[0] score is 2");
- bucket_d = AddScoreToPool(bucket_d, 1, 5001);
- fail_unless(bucket_d->next->count == 1, "bucket_d[1] has one item");
-
- fail_unless(GetNextItem(bucket_d) == 5000, "Next returns item 5000.");
- fail_unless(GetNextItem(bucket_d) == 5001, "Next returns item 5001.");
+START_TEST (test_pools_add) {
+ PoolNode *head_b = NULL;
+ int next = -1;
+ head_b = promoteItem(head_b, 1, 5000, -1);
+ fail_if(head_b->score != 1);
+ fail_if(head_b->count != 1);
+ head_b = NextItem(head_b, &next);
+ printf("next %d\n", next);
+ fail_unless(next == 5000);
+ pool_foreach(head_b, pool_print);
+ fail_if(head_b->score != 1);
+ fail_if(head_b->count != 0);
+ head_b = NextItem(head_b, &next);
+ printf("next %d\n", next);
+ fail_unless(next == -1);
+ fail_if(head_b->score != 1);
+ fail_if(head_b->count != 0);
} END_TEST
+//
+// // Assert insert order is maintained.
+// START_TEST (test_pools_add_several) {
+// PoolNode *head_c = NULL;
+// head_c = promoteItem(head_c, 1, 5000, -1);
+// fail_if(head_c->score != 1);
+// fail_if(head_c->count != 1);
+// head_c = promoteItem(head_c, 1, 5001, -1);
+// fail_if(head_c->count != 2);
+// head_c = promoteItem(head_c, 1, 5002, -1);
+// fail_if(head_c->score != 1);
+// fail_if(head_c->count != 3);
+// fail_unless(NextItem(head_c) == 5000);
+// fail_if(head_c->count != 2);
+// fail_unless(NextItem(head_c) == 5001);
+// fail_if(head_c->count != 1);
+// fail_unless(NextItem(head_c) == 5002);
+// fail_if(head_c->count != 0);
+// } END_TEST
+//
+// // Assert promoting ensures accurate counts and membership
+// START_TEST (test_pools_promote) {
+// PoolNode *head_d = NULL;
+// head_d = promoteItem(head_d, 1, 5000, -1);
+// head_d = promoteItem(head_d, 1, 5001, -1);
+// head_d = promoteItem(head_d, 2, 5000, 1);
+// head_d = promoteItem(head_d, 3, 5000, 2);
+// fail_if(head_d->score != 3);
+// fail_if(head_d->count != 1);
+// fail_if(head_d->next->score != 2);
+// fail_if(head_d->next->count != 0);
+// fail_if(head_d->next->next->score != 1);
+// fail_if(head_d->next->next->count != 1);
+// } END_TEST
Suite * barbershop_suite(void) {
Suite *s = suite_create("Barbershop");
-
TCase *tc_core = tcase_create("Core");
- // tcase_add_test(tc_core, test_scores_empty);
- // tcase_add_test(tc_core, test_scores_add);
- // tcase_add_test(tc_core, test_scores_add_several);
- tcase_add_test(tc_core, test_scores_promote);
+ tcase_add_test(tc_core, test_pools_empty);
+ tcase_add_test(tc_core, test_pools_add);
+ // tcase_add_test(tc_core, test_pools_add_several);
+ // tcase_add_test(tc_core, test_pools_promote);
suite_add_tcase(s, tc_core);
-
return s;
}

0 comments on commit f3a55fb

Please sign in to comment.