static struct VirtualContainer *recursive_parse(FILE *const in, uint64_t start_bit, struct DB *const db) { char buf[128]; fgets(buf, 120, in); assert(buf[0] == '['); if (buf[1] == ']') { return NULL; } struct VirtualContainer *vc = vc_create(start_bit); fgets(buf, 28, in); assert(buf[0] == '<'); // '<!' : bloomcontainer // '<' : bloomtable const bool load_bf = (buf[1] != '!'); for (uint64_t j = 0; j < DB_CONTAINER_NR; j++) { fgets(buf, 28, in); if (buf[0] == '>') break; const uint64_t mtid = strtoull(buf, NULL, 16); assert(db->cms[start_bit / 3]); const int raw_fd = db->cms[start_bit / 3]->raw_fd; struct MetaTable *const mt = db_load_metatable(db, mtid, raw_fd, load_bf); assert(mt); vc->cc.count++; vc->cc.metatables[j] = mt; } if (buf[0] != '>') { // read 8 in loop, eat '>' fgets(buf, 28, in); assert(buf[0] == '>'); } if (!load_bf) { // no bf, load bc assert(buf[1] == '!'); // load bloomcontainer assert(buf[2] != '\0'); const uint64_t mtid_bc = strtoull(buf + 2, NULL, 16); struct BloomContainer *const bc = db_load_bloomcontainer_meta(db, mtid_bc); vc->cc.bc = bc; } for (uint64_t i = 0; i < 8; i++) { vc->sub_vc[i] = recursive_parse(in, start_bit + 3, db); } fgets(buf, 28, in); assert(buf[0] == ']'); return vc; }
static void compaction_initial(struct Compaction *const comp, struct DB *const db, struct VirtualContainer *const vc, uint64_t nr_feed) { bzero(comp, sizeof(*comp)); comp->start_bit = vc->start_bit; comp->sub_bit = vc->start_bit + 3; comp->gen_bc = (comp->sub_bit >= BC_START_BIT); assert(nr_feed <= vc->cc.count); assert(vc->cc.count <= DB_CONTAINER_NR); comp->nr_feed = nr_feed; comp->db = db; comp->vc = vc; comp->cm_to = db->cms[comp->sub_bit / 3]; // alloc arenas uint8_t *const arena = huge_alloc(TABLE_ALIGN); assert(arena); comp->arena = arena; // old mts & mtids for (uint64_t i = 0; i < nr_feed; i++) { struct MetaTable *const mt = vc->cc.metatables[i]; assert(mt); comp->mts_old[i] = mt; comp->mtids_old[i] = mt->mtid; } // new tables for (uint64_t i = 0; i < 8u; i++) { struct Table *const table = table_alloc_default(1.8); assert(table); comp->tables[i] = table; } // mbcs_old (if exists else NULL) for (uint64_t i = 0; i < 8u; i++) { if (!vc->sub_vc[i]) { vc->sub_vc[i] = vc_create(comp->sub_bit); } comp->mbcs_old[i] = vc->sub_vc[i]->cc.bc; } }
// create empty db static struct DB *db_create(const char *const meta_dir, struct ContainerMapConf *const cm_conf) { const double sec0 = debug_time_sec(); if (!db_touch_dir(meta_dir, "")) return NULL; if (!db_touch_dir(meta_dir, DB_META_BACKUP_DIR)) return NULL; // pre make 256 sub-dirs char sub_dir[16]; for (uint64_t i = 0; i < 256; i++) { sprintf(sub_dir, "%02" PRIx64, i); if (!db_touch_dir(meta_dir, sub_dir)) return NULL; } struct DB *const db = (typeof(db))malloc(sizeof(*db)); bzero(db, sizeof(*db)); for (int i = 0; (i < 6) && cm_conf->raw_fn[i]; i++) { struct ContainerMap *const cm = containermap_create(cm_conf->raw_fn[i], cm_conf->hints[i]); assert(cm); db->cms_dump[i] = cm; } db_initial(db, meta_dir, cm_conf); // empty vc db->vcroot = vc_create(0); assert(db->vcroot); // mtid start from 1 db->next_mtid = 1; // initial anything db_log_diff(db, sec0, "Initialized Metadata"); return db; }
int main(int argc, char** argv) { // NOTE: devmgr has getenv_bool. when more options are added, consider // sharing that. bool keep_log = false; const char* value = getenv("virtcon.keep-log-visible"); if (value == NULL || ((strcmp(value, "0") == 0) || (strcmp(value, "false") == 0) || (strcmp(value, "off") == 0))) { keep_log = false; } else { keep_log = true; } const char* cmd = NULL; int shells = 0; while (argc > 1) { if (!strcmp(argv[1], "--run")) { if (argc > 2) { argc--; argv++; cmd = argv[1]; if (shells < 1) shells = 1; printf("CMD: %s\n", cmd); } } else if (!strcmp(argv[1], "--shells")) { if (argc > 2) { argc--; argv++; shells = atoi(argv[1]); } } argc--; argv++; } if (port_init(&port) < 0) { return -1; } // create initial console for debug log if (vc_create(&log_vc, false) != ZX_OK) { return -1; } snprintf(log_vc->title, sizeof(log_vc->title), "debuglog"); // Get our process koid so the log reader can // filter out our own debug messages from the log zx_info_handle_basic_t info; if (zx_object_get_info(zx_process_self(), ZX_INFO_HANDLE_BASIC, &info, sizeof(info), NULL, NULL) == ZX_OK) { proc_koid = info.koid; } log_ph.handle = zx_take_startup_handle(PA_HND(PA_USER0, 1)); if (log_ph.handle == ZX_HANDLE_INVALID) { printf("vc log listener: did not receive log startup handle\n"); return -1; } log_ph.func = log_reader_cb; log_ph.waitfor = ZX_LOG_READABLE; if ((new_vc_ph.handle = zx_take_startup_handle(PA_HND(PA_USER0, 0))) != ZX_HANDLE_INVALID) { new_vc_ph.func = new_vc_cb; new_vc_ph.waitfor = ZX_CHANNEL_READABLE; port_wait(&port, &new_vc_ph); } setup_dir_watcher("/dev/class/input", input_cb, &input_ph, &input_dir_fd); if (!vc_display_init()) { return -1; } setenv("TERM", "xterm", 1); for (int i = 0; i < shells; ++i) { if (i == 0) start_shell(!keep_log, cmd); else start_shell(false, NULL); } zx_status_t r = port_dispatch(&port, ZX_TIME_INFINITE, false); printf("vc: port failure: %d\n", r); return -1; }
static zx_status_t session_create(vc_t** out, int* out_fd, bool make_active, bool special) { int fd; // The ptmx device can start later than these threads int retry = 30; while ((fd = open("/dev/misc/ptmx", O_RDWR | O_NONBLOCK)) < 0) { if (--retry == 0) { return ZX_ERR_IO; } usleep(100000); } int client_fd = openat(fd, "0", O_RDWR); if (client_fd < 0) { close(fd); return ZX_ERR_IO; } vc_t* vc; if (vc_create(&vc, special)) { close(fd); close(client_fd); return ZX_ERR_INTERNAL; } zx_status_t r; if ((r = port_fd_handler_init(&vc->fh, fd, POLLIN | POLLRDHUP | POLLHUP)) < 0) { vc_destroy(vc); close(fd); close(client_fd); return r; } vc->fd = fd; if (make_active) { vc_set_active(-1, vc); } pty_window_size_t wsz = { .width = vc->columns, .height = vc->rows, }; ioctl_pty_set_window_size(fd, &wsz); vc->fh.func = session_io_cb; *out = vc; *out_fd = client_fd; return ZX_OK; } static void start_shell(bool make_active, const char* cmd) { vc_t* vc; int fd; if (session_create(&vc, &fd, make_active, cmd != NULL) < 0) { return; } vc->is_shell = true; if (launch_shell(vc, fd, cmd) < 0) { session_destroy(vc); } else { port_wait(&port, &vc->fh.ph); } }