static int fast_books_recover(struct fast_book_set *set) { struct fast_book *book; struct fast_feed *feed; int i; retry: set->inc_gap_mode = false; set->inc_msg_num = 0; for (i = 0; i < set->inc_feeds_num; i++) { feed = set->inc_feeds + i; feed->recv_num = 0; } for (i = 0; i < set->books_num; i++) { book = set->books + i; book_clear_flags(book, FAST_BOOK_ACTIVE); } for (i = 0; i < set->books_num; i++) { book = set->books + i; if (!book_has_flags(book, FAST_BOOK_SUBSCRIBED)) continue; if (fast_books_join(set, book)) goto retry; } return 0; }
static int apply_snapshot(struct fast_book_set *set, struct fast_book *dst, struct fast_message *msg) { struct fast_sequence *seq; struct fast_field *field; struct fast_message *md; struct fast_book *book; int i; field = fast_get_field(msg, "SecurityID"); if (!field || field_state_empty(field)) goto fail; book = fast_book_find(set, field->uint_value); if (!book || book_has_flags(book, FAST_BOOK_ACTIVE)) goto done; if (dst && dst->secid != book->secid) goto done; field = fast_get_field(msg, "MDEntries"); if (!field || field_state_empty(field)) goto fail; seq = field->ptr_value; if (field_state_empty(&seq->length)) goto fail; field = fast_get_field(msg, "RptSeq"); if (!field || field_state_empty(field)) goto fail; book->rptseq = field->uint_value; book_clear_flags(book, FAST_BOOK_EMPTY); book_add_mask(set, book); for (i = 1; i <= seq->length.uint_value; i++) { md = seq->elements + i; if (md_snapshot(book, md)) goto fail; } if (!fast_book_is_valid(book)) { if (!book_has_flags(book, FAST_BOOK_EMPTY)) goto fail; } else { book_add_flags(book, FAST_BOOK_ACTIVE); } done: return 0; fail: return -1; }
static int fast_books_join(struct fast_book_set *set, struct fast_book *book) { struct fast_message *inc_buf = NULL; struct fast_message *tmp_buf; struct fast_field *field; struct fast_message *msg; unsigned long size = 32; unsigned long pos = 0; u64 last_msg_seq_num; u64 msg_seq_num = 0; unsigned long i; if (fast_feed_open(set->snp_feeds)) goto fail; inc_buf = calloc(size, sizeof(struct fast_message)); if (!inc_buf) goto fail; book_clear_flags(book, FAST_BOOK_ACTIVE); while (!book_has_flags(book, FAST_BOOK_ACTIVE)) { if (next_increment(set, &msg)) goto fail; if (!msg) continue; if (apply_increment(set, NULL, msg)) goto fail; if (pos >= size) { size *= 2; tmp_buf = realloc(inc_buf, size * sizeof(struct fast_message)); if (!tmp_buf) goto fail; inc_buf = tmp_buf; } if (fast_message_copy(inc_buf + pos, msg)) { goto fail; } else pos++; if (!msg_seq_num) { field = fast_get_field(msg, "MsgSeqNum"); if (!field || field_state_empty(field)) goto fail; msg_seq_num = field->uint_value; } if (next_snapshot(set, &msg)) goto fail; if (!msg) continue; field = fast_get_field(msg, "LastMsgSeqNumProcessed"); if (!field || field_state_empty(field)) goto fail; last_msg_seq_num = field->uint_value; if (last_msg_seq_num < msg_seq_num) continue; if (apply_snapshot(set, book, msg)) goto fail; } if (!pos) goto fail; for (i = 0; i < pos; i++) { msg = inc_buf + i; field = fast_get_field(msg, "MsgSeqNum"); if (!field || field_state_empty(field)) goto fail; msg_seq_num = field->uint_value; if (msg_seq_num <= last_msg_seq_num) continue; if (apply_increment(set, book, msg)) goto fail; } if (fast_feed_close(set->snp_feeds)) goto fail; fast_message_free(inc_buf, pos); return 0; fail: fast_feed_close(set->snp_feeds); fast_message_free(inc_buf, pos); return -1; }
static int fast_books_join(struct fast_book_set *set, struct fast_book *book) { struct fast_message *inc_msg = NULL; struct fast_message *snp_msg = NULL; bool snp_received = false; struct fast_field *field; struct fast_book *sbook; struct ob_level *level; struct ob_order order; u64 last_msg_seq_num; u64 msg_num_init = 0; u64 msg_num_cur = 0; GList *list; if (fast_feed_open(set->snp_feeds)) goto fail; book_clear_flags(book, FAST_BOOK_ACTIVE); book_add_flags(book, FAST_BOOK_JOIN); while (!book_has_flags(book, FAST_BOOK_ACTIVE)) { if (next_increment(set, &inc_msg)) goto fail; if (inc_msg) { if (apply_increment(set, NULL, inc_msg)) goto fail; field = fast_get_field(inc_msg, "MsgSeqNum"); if (!field || field_state_empty(field)) goto fail; msg_num_cur = field->uint_value; if (!msg_num_init) msg_num_init = msg_num_cur; } if (!snp_received) { if (next_snapshot(set, &snp_msg)) goto fail; } if (snp_msg) { field = fast_get_field(snp_msg, "SecurityID"); if (field) { if (field_state_empty(field)) goto fail; sbook = fast_book_by_id(set, field->uint_value); if (!sbook || book->secid != sbook->secid) continue; } else { field = fast_get_field(snp_msg, "Symbol"); if (!field || field_state_empty(field)) goto fail; sbook = fast_book_by_symbol(set, field->string_value); if (!sbook || strcmp(sbook->symbol, book->symbol)) continue; } field = fast_get_field(snp_msg, "LastMsgSeqNumProcessed"); if (!field || field_state_empty(field)) goto fail; last_msg_seq_num = field->uint_value; if (!msg_num_init) continue; if (last_msg_seq_num < msg_num_init) continue; snp_received = true; if (last_msg_seq_num > msg_num_cur) continue; if (apply_snapshot(set, book, snp_msg)) goto fail; if (book_has_flags(book, FAST_BOOK_EMPTY)) snp_received = false; } } order.buy = false; list = g_list_first(book->ob.glasks); while (list) { level = g_list_nth_data(list, 0); list = g_list_next(list); if (!level->size) { order.price = level->price; if (ob_level_delete(&book->ob, &order)) goto fail; } } order.buy = true; list = g_list_first(book->ob.glbids); while (list) { level = g_list_nth_data(list, 0); list = g_list_next(list); if (!level->size) { order.price = level->price; if (ob_level_delete(&book->ob, &order)) goto fail; } } book_clear_flags(book, FAST_BOOK_JOIN); if (fast_feed_close(set->snp_feeds)) goto fail; return 0; fail: fast_feed_close(set->snp_feeds); return -1; }
static int apply_snapshot(struct fast_book_set *set, struct fast_book *dst, struct fast_message *msg) { struct fast_sequence *seq; struct fast_field *field; struct fast_message *md; struct fast_book *book; int i; field = fast_get_field(msg, "SecurityID"); if (field) { if (field_state_empty(field)) goto fail; book = fast_book_by_id(set, field->uint_value); if (!book || book_has_flags(book, FAST_BOOK_ACTIVE)) goto done; if (!book_has_flags(book, FAST_BOOK_JOIN)) goto done; if (dst && dst->secid != book->secid) goto done; } else { field = fast_get_field(msg, "Symbol"); if (!field || field_state_empty(field)) goto fail; book = fast_book_by_symbol(set, field->string_value); if (!book || book_has_flags(book, FAST_BOOK_ACTIVE)) goto done; if (!book_has_flags(book, FAST_BOOK_JOIN)) goto done; if (dst && strncmp(book->symbol, dst->symbol, strlen(dst->symbol))) goto done; } field = fast_get_field(msg, "MDEntries"); if (!field) { field = fast_get_field(msg, "GroupMDEntries"); } if (!field || field_state_empty(field)) goto fail; seq = field->ptr_value; if (field_state_empty(&seq->length)) goto fail; if (!seq->length.uint_value) goto done; md = seq->elements; field = fast_get_field(md, "TradingSessionID"); if (field) { if (field_state_empty(field)) goto fail; if (strncmp(book->session, field->string_value, strlen(book->session))) goto done; } field = fast_get_field(msg, "RptSeq"); if (!field || field_state_empty(field)) goto fail; book->snpseq = field->uint_value; book_clear_flags(book, FAST_BOOK_EMPTY); book_add_mask(set, book); for (i = 1; i <= seq->length.uint_value; i++) { md = seq->elements + i; if (md_snapshot(book, md)) goto fail; } if (!book_has_flags(book, FAST_BOOK_EMPTY)) book_add_flags(book, FAST_BOOK_ACTIVE); done: return 0; fail: return -1; }