int main(int argc, char *argv[]) { char *password = fsp_argv_password(&argc, argv); int flags = 0, many = 0, all = 0; int seg = 0; /* deliberately using signed type */ fs_rid_vector *mrids= NULL, *srids= NULL, *prids= NULL, *orids= NULL; fs_rid_vector **result = NULL; if (argc < 7) { fprintf(stderr, "%s revision %s\n", argv[0], FS_FRONTEND_VER); fprintf(stderr, "Usage: %s <kbname> { many | all | seg# } <flags>\n", argv[0]); fprintf(stderr, " mrid-file srid-file prid-file orid-file [offset limit]\n"); fprintf(stderr, "For flags use FS_BIND_... symbols or a numeric value\n"); fprintf(stderr, "RID files are one RID per line\n"); exit(1); } char *kbname = argv[1]; if (!strcasecmp(argv[2], "many")) { many = 1; } else if (!strcasecmp(argv[2], "all")) { all = 1; } else { seg = atoi(argv[2]); } int param = 3; flags = strtol(argv[param], NULL, 0); if (flags == 0) { /* symbolic flags, hopefully */ while (param < argc) { const int len = sizeof(flag_name) / sizeof(char *); int k; for (k = 0; k < len; ++k) { if (!strcmp(flag_name[k], argv[param])) { flags |= flag_value[k]; break; } } if (k == len) break; param ++; } } else { param ++; /* done with the numeric flags then */ } if (argc < param + 4) { fprintf(stderr, "Wrong number of arguments\n"); exit(1); } mrids = rid_file(argv[param++]); srids = rid_file(argv[param++]); prids = rid_file(argv[param++]); orids = rid_file(argv[param++]); int limit, offset; if (argc == param ) { /* defaults */ limit = -1; offset = -1; } else if (argc > param + 2) { fprintf(stderr, "Wrong number of arguments\n"); exit(1); } else if (argc < param + 2) { fprintf(stderr, "Wrong number of arguments\n"); exit(1); } else { offset = atoi(argv[param]); limit = atoi(argv[param + 1]); } fsp_link *link = fsp_open_link(kbname, password, FS_OPEN_HINT_RO); if (!link) { fs_error (LOG_ERR, "couldn't connect to “%s”", argv[1]); exit(2); } segments = fsp_link_segments(link); if (seg < 0 || seg > segments) { fs_error (LOG_ERR, "Segment %d out of range (0-%u)", seg, segments); exit(1); } double then = fs_time(); int ans = 0; if (all) { ans = fsp_bind_limit_all(link, flags, mrids, srids, prids, orids, &result, offset, limit); } else if (many) { ans = fsp_bind_limit_many(link, flags, mrids, srids, prids, orids, &result, offset, limit); } else { ans = fsp_bind_limit(link, seg, flags, mrids, srids, prids, orids, &result, offset, limit); } double time_binding = fs_time() - then; if (ans != 0) exit(1); /* print results */ int cols = 0; for (int k = 0; k < 4; ++k) { if (flags & (1 << k)) cols++; } if (!result) { printf("NO MATCH found.\n"); } else if (cols == 0) { printf("MATCH found.\n"); } else if (result[0]) { int length = result[0]->length; if (flags & FS_BIND_MODEL) printf("-----Model------ "); if (flags & FS_BIND_SUBJECT) printf("----Subject----- "); if (flags & FS_BIND_PREDICATE) printf("----Predicate--- "); if (flags & FS_BIND_OBJECT) printf("-----Object-----"); putchar('\n'); for (int k = 0; k < length; ++k) { for (int c = 0; c < cols; ++c) { printf("%016llX ", result[c]->data[k]); } putchar('\n'); } } fprintf(stderr, "bind took %f seconds on client\n", time_binding); fs_query_timing times; if (all || many) { fprintf(stderr, "binding on all or many segments, times in seconds...\n"); for (int s = 0; s < segments; ++s) { fsp_get_query_times(link, s, ×); if (times.bind > 0.0f) { fprintf(stderr, "%d: %f\n", s, times.bind); } } fputc('\n', stderr); } else { fsp_get_query_times(link, seg, ×); fprintf(stderr, "binding segment %d took %f seconds\n", seg, times.bind); } fsp_close_link(link); }
int fs_bind_cache_wrapper_intl(fs_query_state *qs, fs_query *q, int all, int flags, fs_rid_vector *rids[4], fs_rid_vector ***result, int offset, int limit) { g_static_mutex_lock(&qs->cache_mutex); if (!qs->bind_cache) { qs->bind_cache = calloc(CACHE_SIZE, sizeof(struct _fs_bind_cache)); } if (fsp_acl_needs_reload(qs->link)) fs_acl_load_system_info(qs->link); g_static_mutex_unlock(&qs->cache_mutex); int slots = 0; if (flags & FS_BIND_MODEL) slots++; if (flags & FS_BIND_SUBJECT) slots++; if (flags & FS_BIND_PREDICATE) slots++; if (flags & FS_BIND_OBJECT) slots++; /* check for no possible bindings */ for (int s=0; s<4; s++) { if (rids[s]->length == 1 && rids[s]->data[0] == FS_RID_NULL) { *result = calloc(slots, sizeof(fs_rid_vector)); for (int s=0; s<slots; s++) { (*result)[s] = fs_rid_vector_new(0); } return 0; } } int cachable = 0; fs_rid cache_hash = 0; fs_rid cache_key[4]; /* only consult the cache for optimasation levels 0-2 */ if (q && q->opt_level < 3) goto skip_cache; if (q && q->qs && q->qs->cache_stats) q->qs->bind_hits++; cachable = 1; cache_hash += all + flags * 2 + offset * 256 + limit * 32768; for (int s=0; s<4; s++) { if (rids[s]->length == 1) { cache_hash ^= (rids[s]->data[0] + s); cache_key[s] = rids[s]->data[0]; } else if (rids[s]->length == 0) { cache_key[s] = 0; } else { /* bind cache does not cache binds with any slot containing multiple values */ cachable = 0; break; } } cache_hash %= (CACHE_SIZE - 1); g_static_mutex_lock(&qs->cache_mutex); if (cachable && qs->bind_cache[cache_hash].filled) { int match = 1; if (qs->bind_cache[cache_hash].all != all) match = 0; if (qs->bind_cache[cache_hash].flags != flags) match = 0; if (qs->bind_cache[cache_hash].offset != offset) match = 0; if (qs->bind_cache[cache_hash].limit != limit) match = 0; for (int s=0; s<4 && match; s++) { if (cache_key[s] != qs->bind_cache[cache_hash].key[s]) { match = 0; } } if (match) { *result = calloc(slots, sizeof(fs_rid_vector)); for (int s=0; s<slots; s++) { (*result)[s] = fs_rid_vector_copy(qs->bind_cache[cache_hash].res[s]); } fsp_hit_limits_add(qs->link, qs->bind_cache[cache_hash].limited); qs->bind_cache[cache_hash].hits++; if (q && q->qs && q->qs->cache_stats) q->qs->bind_cache_success++; g_static_mutex_unlock(&qs->cache_mutex); return 0; } } g_static_mutex_unlock(&qs->cache_mutex); int ret; skip_cache:; int limited_before = fsp_hit_limits(qs->link); if (all) { ret = fsp_bind_limit_all(qs->link, flags, rids[0], rids[1], rids[2], rids[3], result, offset, limit); } else { ret = fsp_bind_limit_many(qs->link, flags, rids[0], rids[1], rids[2], rids[3], result, offset, limit); } int limited = fsp_hit_limits(qs->link) - limited_before; if (ret) { fs_error(LOG_ERR, "bind failed in '%s', %d segments gave errors", fsp_kb_name(qs->link), ret); exit(1); } int small = 1; for (int s=0; s<slots; s++) { if (fs_rid_vector_length((*result)[s]) > 10000) { small = 0; break; } } if (cachable && small && slots > 0) { g_static_mutex_lock(&qs->cache_mutex); if (qs->bind_cache[cache_hash].filled == 1) { for (int s=0; s<4; s++) { fs_rid_vector_free(qs->bind_cache[cache_hash].res[s]); qs->bind_cache[cache_hash].res[s] = NULL; } } qs->bind_cache[cache_hash].filled = 1; qs->bind_cache[cache_hash].all = all; qs->bind_cache[cache_hash].flags = flags; qs->bind_cache[cache_hash].offset = offset; qs->bind_cache[cache_hash].limit = limit; qs->bind_cache[cache_hash].limited = limited; for (int s=0; s<4; s++) { qs->bind_cache[cache_hash].key[s] = cache_key[s]; if (s < slots) { qs->bind_cache[cache_hash].res[s] = fs_rid_vector_copy((*result)[s]); } else { qs->bind_cache[cache_hash].res[s] = NULL; } } g_static_mutex_unlock(&qs->cache_mutex); } return ret; }