static void _root_split(struct tree *t, struct node *new_root, struct node *old_root) { struct node *a; struct node *b; struct msg *split_key = NULL; __DEBUG("root split begin, old NID %"PRIu64" , height %d" , old_root->nid , old_root->height); if (old_root->height > 0 || old_root->n_children > 2) _node_split(t, old_root, &a, &b, &split_key); else _leaf_and_lmb_split(t, old_root, &a, &b, &split_key); /* swap two roots */ _root_swap(new_root, old_root); msgcpy(&new_root->pivots[0], split_key); new_root->parts[0].child_nid = a->nid; new_root->parts[1].child_nid = b->nid; msgfree(split_key); cache_unpin(t->cf, b->cpair, make_cpair_attr(b)); node_set_dirty(old_root); node_set_dirty(new_root); t->hdr->height++; status_increment(&t->e->status->tree_root_new_nums); __DEBUG("root split end, old NID %"PRIu64, old_root->nid); }
void arrange_container(struct sway_container *container) { if (config->reloading) { return; } if (container->view) { view_autoconfigure(container->view); node_set_dirty(&container->node); return; } struct wlr_box box; container_get_box(container, &box); arrange_children(container->children, container->layout, &box); node_set_dirty(&container->node); }
/* * EFFECT: * - split leaf&lmb into two leaves:a & b * a&b are both the half of the lmb * * PROCESS: * - leaf: * +-----------------------------------+ * | 0 | 1 | 2 | 3 | 4 | 5 | * +-----------------------------------+ * * - split: * root * +--------+ * | 2 | * +--------+ * / \ * +-----------------+ +------------------+ * | 0 | 1 | 2 | | 3 | 4 | 5 | * +-----------------+ +------------------+ * nodea nodeb * * ENTER: * - leaf is already locked (L_WRITE) * EXITS: * - a is locked * - b is locked */ void leaf_split(void *tree, struct node *node, struct node **a, struct node **b, struct msg **split_key) { struct partition *pa; struct partition *pb; struct node *leafa; struct node *leafb; struct lmb *mb; struct lmb *mba; struct lmb *mbb; struct msg *sp_key = NULL; struct buftree *t = (struct buftree*)tree; leafa = node; pa = &leafa->parts[0]; /* split lmb of leaf to mba & mbb */ mb = pa->msgbuf; lmb_split(mb, &mba, &mbb, &sp_key); lmb_free(mb); /* reset leafa buffer */ pa->msgbuf = mba; /* new leafb */ NID nid = hdr_next_nid(t->hdr); leaf_new(t->hdr, nid, 0, 1, &leafb); leaf_msgbuf_init(leafb); cache_put_and_pin(t->cf, nid, leafb); pb = &leafb->parts[0]; lmb_free(pb->msgbuf); pb->msgbuf = mbb; /* set dirty */ node_set_dirty(leafa); node_set_dirty(leafb); *a = leafa; *b = leafb; *split_key = sp_key; }
/* * EFFECT: * - flush in background thread * ENTER: * - parent is already locked * EXIT: * - nodes are all unlocked */ void tree_flush_node_on_background(struct tree *t, struct node *parent) { LOG; int childnum; enum reactivity re; struct node *child; struct partition *part; nassert(parent->height > 0); childnum = node_find_heaviest_idx(parent); part = &parent->parts[childnum]; /* pin the child */ if (cache_get_and_pin(t->cf, part->child_nid, (void**)&child, L_WRITE) != NESS_OK) { __ERROR("cache get node error, nid [%" PRIu64 "]", part->child_nid); return; } re = get_reactivity(t, child); if (re == STABLE) { /* detach buffer from parent */ struct nmb *buf = part->ptr.u.nonleaf->buffer; node_set_dirty(parent); part->ptr.u.nonleaf->buffer = nmb_new(t->e); /* flush it in background thread */ _place_node_and_buffer_on_background(t, child, buf); cache_unpin(t->cf, parent->cpair, make_cpair_attr(parent)); } else { /* the child is reactive, we deal it in main thread */ _child_maybe_reactivity(t, parent, child); } }
/* * EFFECT: * - do flush in a background thread * PROCESS: * - if buf is NULL, we will do _flush_some_child * - if buf is NOT NULL, we will do _flush_buffer_to_child * ENTER: * - fe->node is already locked * EXIT: * - nodes are unlocked */ static void _flush_node_func(void *fe) { enum reactivity re; struct flusher_extra *extra = (struct flusher_extra*)fe; struct tree *t = extra->tree; struct node *n = extra->node; struct nmb *buf = extra->buffer; node_set_dirty(n); if (buf) { _flush_buffer_to_child(t, n, buf); nmb_free(buf); /* check the child node */ re = get_reactivity(t, n); if (re == FLUSHBLE) _flush_some_child(t, n); else cache_unpin(t->cf, n->cpair, make_cpair_attr(n)); } else { /* we want flush some buffer from n */ _flush_some_child(t, n); } xfree(extra); }
/* * apply a msg to leaf basement * neither the leaf type is LE_CLEAN or LE_MVCC * basement will always keep multi-snapshot * the difference between LE_CLEAN and LE_MVCC is gc affects. * */ int leaf_apply_msg(struct node *leaf, struct bt_cmd *cmd) { write_lock(&leaf->u.l.le->rwlock); switch (cmd->type & 0xff) { case MSG_INSERT: case MSG_DELETE: case MSG_UPDATE: { /* TODO: do msg update, node->node_op->update */ } case MSG_COMMIT: case MSG_ABORT: default: basement_put(leaf->u.l.le->bsm, cmd->msn, cmd->type, cmd->key, cmd->val, &cmd->xidpair); } leaf->msn = cmd->msn > leaf->msn ? cmd->msn : leaf->msn; node_set_dirty(leaf); write_unlock(&leaf->u.l.le->rwlock); return NESS_OK; }
/* * EFFECT: * - put cmd to leaf * ENTER: * - leaf is already locked(L_WRITE) * EXITS: * - leaf is locked */ void leaf_put_cmd(struct node *leaf, struct bt_cmd *cmd) { LOG; leaf_apply_msg(leaf, cmd); leaf->msn = cmd->msn > leaf->msn ? cmd->msn : leaf->msn; node_set_dirty(leaf); }
/* * * PROCESS: * - if the layout as follows(3 pivots, 4 partitions): * * +--------+--------+--------+ * | 15 | 17 | 19 | +∞ * +--------+--------+--------+\ * pidx0 pidx1 pidx2 pidx3 * * * - so if spk is 16, pidx = 1, after added(4 pivtos, 5 partitions): * * +--------+--------+--------+--------+ * | 15 | [16] | 17 | 19 | +∞ * +--------+--------+--------+--------+\ * pidx0 [pidx1] pidx2 pidx3 pidx4 * * * ENTER: * - parent is already locked(L_WRITE) * - node a is already locked(L_WRITE) * - node b is already locked(L_WRITE) */ static void _add_pivot_to_parent(struct tree *t, struct node *parent, int child_num, struct node *a, struct node *b, struct msg *spk) { int i; int pidx; struct child_pointer *cptr; pidx = child_num; parent->pivots = xrealloc(parent->pivots, parent->n_children * PIVOT_SIZE); parent->parts = xrealloc(parent->parts, (parent->n_children + 1) * PART_SIZE); /* slide pivots */ for (i = (parent->n_children - 1); i > pidx; i--) parent->pivots[i] = parent->pivots[i - 1]; /* slide parts */ for (i = parent->n_children; i > pidx; i--) parent->parts[i] = parent->parts[i - 1]; /* new part */ msgcpy(&parent->pivots[pidx], spk); parent->parts[pidx].child_nid = a->nid; cptr = &parent->parts[pidx].ptr; cptr->u.nonleaf = create_nonleaf(t->e); parent->parts[pidx + 1].child_nid = b->nid; parent->n_children += 1; node_set_dirty(parent); status_increment(&t->e->status->tree_add_pivots_nums); }
/* * apply a msg to leaf msgbuf * neither the leaf type is LE_CLEAN or LE_MVCC * msgbuf will always keep multi-snapshot * the difference between LE_CLEAN and LE_MVCC is gc affects. * */ int leaf_put(struct node *leaf, struct bt_cmd *cmd) { int ret = NESS_ERR; struct lmb *buffer = (struct lmb*)leaf->parts[0].msgbuf; switch (cmd->type & 0xff) { case MSG_INSERT: lmb_put(buffer, cmd->msn, cmd->type, cmd->key, cmd->val, &cmd->xidpair); return NESS_OK; break; case MSG_DELETE: break; case MSG_UPDATE: break; case MSG_COMMIT: break; case MSG_ABORT: break; default: break; } leaf->msn = cmd->msn > leaf->msn ? cmd->msn : leaf->msn; node_set_dirty(leaf); return ret; }
void leaf_new(struct hdr *hdr, NID nid, uint32_t height, uint32_t children, struct node **n) { struct node *node; nassert(height == 0); nassert(children == 1); node = xcalloc(1, sizeof(*node)); nassert(node); node->nid = nid; node->height = height; ness_mutex_init(&node->attr.mtx); ness_mutex_init(&node->mtx); ness_rwlock_init(&node->rwlock, &node->mtx); node->n_children = children; node->layout_version = hdr->layout_version; if (children > 0) { node->pivots = xcalloc(children - 1, PIVOT_SIZE); node->parts = xcalloc(children, PART_SIZE); } node->opts = hdr->opts; node->i = &leaf_operations; node_set_dirty(node); *n = node; }
void arrange_workspace(struct sway_workspace *workspace) { if (config->reloading) { return; } if (!workspace->output) { // Happens when there are no outputs connected return; } struct sway_output *output = workspace->output; struct wlr_box *area = &output->usable_area; sway_log(SWAY_DEBUG, "Usable area for ws: %dx%d@%d,%d", area->width, area->height, area->x, area->y); workspace_remove_gaps(workspace); bool first_arrange = workspace->width == 0 && workspace->height == 0; double prev_x = workspace->x; double prev_y = workspace->y; workspace->width = area->width; workspace->height = area->height; workspace->x = output->wlr_output->lx + area->x; workspace->y = output->wlr_output->ly + area->y; // Adjust any floating containers double diff_x = workspace->x - prev_x; double diff_y = workspace->y - prev_y; if (!first_arrange && (diff_x != 0 || diff_y != 0)) { for (int i = 0; i < workspace->floating->length; ++i) { struct sway_container *floater = workspace->floating->items[i]; container_floating_translate(floater, diff_x, diff_y); double center_x = floater->x + floater->width / 2; double center_y = floater->y + floater->height / 2; struct wlr_box workspace_box; workspace_get_box(workspace, &workspace_box); if (!wlr_box_contains_point(&workspace_box, center_x, center_y)) { container_floating_move_to_center(floater); } } } workspace_add_gaps(workspace); node_set_dirty(&workspace->node); sway_log(SWAY_DEBUG, "Arranging workspace '%s' at %f, %f", workspace->name, workspace->x, workspace->y); if (workspace->fullscreen) { struct sway_container *fs = workspace->fullscreen; fs->x = output->lx; fs->y = output->ly; fs->width = output->width; fs->height = output->height; arrange_container(fs); } else { struct wlr_box box; workspace_get_box(workspace, &box); arrange_children(workspace->tiling, workspace->layout, &box); arrange_floating(workspace->floating); } }
/* * EFFECT: * - alloc node header */ struct node *node_alloc_empty(NID nid, int height) { struct node *node; node = xcalloc(1, sizeof(*node)); node->nid = nid; node->height = height; node->node_op = &nop; mutex_init(&node->attr.mtx); node_set_dirty(node); return node; }
/* * EFFECT: * - put cmd to nonleaf * ENTER: * - node is already locked (L_READ) * EXITS: * - node is locked */ void nonleaf_put_cmd(struct node *node, struct bt_cmd *cmd) { uint32_t pidx; struct nmb *buffer; pidx = node_partition_idx(node, cmd->key); buffer = node->parts[pidx].ptr.u.nonleaf->buffer; nassert(buffer); nmb_put(buffer, cmd-> msn, cmd->type, cmd->key, cmd->val, &cmd->xidpair); node->msn = cmd->msn > node->msn ? cmd->msn : node->msn; node_set_dirty(node); }
/* * +-----------------------------------------------+ * | 5 | 7 | 9 | * +-----------------------------------------------+ * | * +---------------+ * | 60 | 61 | 62 | * +---------------+ * * +---------------------------------------------------------------+ * | 5 | 60 | 7 | 9 | * +---------------------------------------------------------------+ * | | * +--------+ +---------+ * | 60 | | 61 | 62 | * +--------+ +---------+ * * * ENTER: * - node is already locked(L_WRITE) * EXITS: * - a is locked(L_WRITE) * - b is locked(L_WRITE) */ static void _node_split(struct tree *t, struct node *node, struct node **a, struct node **b, struct msg **split_key) { int i; int pivots_old; int pivots_in_a; int pivots_in_b; struct node *nodea; struct node *nodeb; struct msg *spk; __DEBUG("nonleaf split begin, NID %"PRIu64"" ", nodesz %d" ", nodec %d" ", children %d" , node->nid , node_size(node) , node_count(node) , node->n_children); nodea = node; pivots_old = node->n_children - 1; nassert(pivots_old > 2); pivots_in_a = pivots_old / 2; pivots_in_b = pivots_old - pivots_in_a; /* node a */ nodea->n_children = pivots_in_a + 1; /* node b */ NID nid = hdr_next_nid(t->hdr); node_create_light(nid, node->height > 0 ? 1 : 0, pivots_in_b + 1, t->hdr->version, t->e, &nodeb); cache_put_and_pin(t->cf, nid, nodeb); for (i = 0; i < (pivots_in_b); i++) nodeb->pivots[i] = nodea->pivots[pivots_in_a + i]; for (i = 0; i < (pivots_in_b + 1); i++) nodeb->parts[i] = nodea->parts[pivots_in_a + i]; /* the rightest partition of nodea */ struct child_pointer *ptr = &nodea->parts[pivots_in_a].ptr; if (nodea->height > 0) ptr->u.nonleaf = create_nonleaf(t->e); else ptr->u.leaf = create_leaf(t->e); /* split key */ spk = msgdup(&node->pivots[pivots_in_a - 1]); node_set_dirty(nodea); node_set_dirty(nodeb); __DEBUG("nonleaf split end, nodea NID %"PRIu64"" ", nodesz %d" ", nodec %d" ", children %d" , nodea->nid , node_size(nodea) , node_count(nodea) , nodea->n_children); __DEBUG("nonleaf split end, nodeb NID %"PRIu64"" ", nodesz %d" ", nodec %d" ", children %d" , nodeb->nid , node_size(nodeb) , node_count(nodeb) , nodeb->n_children); *a = nodea; *b = nodeb; *split_key = spk; }
struct tree *tree_open(const char *dbname, struct env *e, struct tree_callback *tcb) { int fd; int flag; mode_t mode; int is_create = 0; struct tree *t; struct node *root; struct cache_file *cf; t = xcalloc(1, sizeof(*t)); t->e = e; mode = S_IRWXU | S_IRWXG | S_IRWXO; flag = O_RDWR | O_BINARY; if (e->use_directio) fd = ness_os_open_direct(dbname, flag, mode); else fd = ness_os_open(dbname, flag, mode); if (fd == -1) { if (e->use_directio) fd = ness_os_open(dbname, flag | O_CREAT, mode); else fd = ness_os_open_direct(dbname, flag | O_CREAT, mode); if (fd == -1) goto ERR; is_create = 1; } t->fd = fd; t->hdr = hdr_new(e); /* tree header */ if (!is_create) { tcb->fetch_hdr_cb(fd, t->hdr); } /* create cache file */ cf = cache_file_create(e->cache, t->fd, t->hdr, tcb); t->cf = cf; /* tree root node */ if (is_create) { NID nid = hdr_next_nid(t->hdr); node_create(nid, 0, 1, t->hdr->version, t->e, &root); cache_put_and_pin(cf, nid, root); root->isroot = 1; node_set_dirty(root); cache_unpin(cf, root->cpair, make_cpair_attr(root)); t->hdr->root_nid = root->nid; __DEBUG("create new root, NID %"PRIu64, root->nid); } else { /* get the root node */ if (cache_get_and_pin(cf, t->hdr->root_nid, (void**)&root, L_READ) != NESS_OK) __PANIC("get root from cache error [%" PRIu64 "]", t->hdr->root_nid); root->isroot = 1; cache_unpin(cf, root->cpair, make_cpair_attr(root)); __DEBUG("fetch root, NID %"PRIu64, root->nid); } return t; ERR: xfree(t); return NESS_ERR; }
void _flush_buffer_to_child(struct tree *t, struct node *child, struct nmb *buf) { struct mb_iter iter; mb_iter_init(&iter, buf->pma); while (mb_iter_next(&iter)) { /* TODO(BohuTANG): check msn */ struct nmb_values nvalues; nmb_get_values(&iter, &nvalues); struct bt_cmd cmd = { .msn = nvalues.msn, .type = nvalues.type, .key = &nvalues.key, .val = &nvalues.val, .xidpair = nvalues.xidpair }; node_put_cmd(t, child, &cmd); } } void _flush_some_child(struct tree *t, struct node *parent); /* * PROCESS: * - check child reactivity * - if FISSIBLE: split child * - if FLUSHBLE: flush buffer from child * ENTER: * - parent is already locked * - child is already locked * EXIT: * - parent is unlocked * - no nodes are locked */ void _child_maybe_reactivity(struct tree *t, struct node *parent, struct node *child) { enum reactivity re = get_reactivity(t, child); switch (re) { case STABLE: cache_unpin(t->cf, child->cpair, make_cpair_attr(child)); cache_unpin(t->cf, parent->cpair, make_cpair_attr(parent)); break; case FISSIBLE: node_split_child(t, parent, child); cache_unpin(t->cf, child->cpair, make_cpair_attr(child)); cache_unpin(t->cf, parent->cpair, make_cpair_attr(parent)); break; case FLUSHBLE: cache_unpin(t->cf, parent->cpair, make_cpair_attr(parent)); _flush_some_child(t, child); break; } } /* * PROCESS: * - pick a heaviest child of parent * - flush from parent to child * - maybe split/flush child recursively * ENTER: * - parent is already locked * EXIT: * - parent is unlocked * - no nodes are locked */ void _flush_some_child(struct tree *t, struct node *parent) { int childnum; enum reactivity re; struct node *child; struct partition *part; struct nmb *buffer; struct timespec t1, t2; childnum = node_find_heaviest_idx(parent); nassert(childnum < parent->n_children); part = &parent->parts[childnum]; buffer = part->ptr.u.nonleaf->buffer; if (cache_get_and_pin(t->cf, part->child_nid, (void**)&child, L_WRITE) != NESS_OK) { __ERROR("cache get node error, nid [%" PRIu64 "]", part->child_nid); return; } ngettime(&t1); re = get_reactivity(t, child); if (re == STABLE) { node_set_dirty(parent); part->ptr.u.nonleaf->buffer = nmb_new(t->e); _flush_buffer_to_child(t, child, buffer); nmb_free(buffer); } ngettime(&t2); status_add(&t->e->status->tree_flush_child_costs, time_diff_ms(t1, t2)); status_increment(&t->e->status->tree_flush_child_nums); _child_maybe_reactivity(t, parent, child); }
/* * EFFECT: * - split leaf&lmb into two leaves:a & b * a&b are both the half of the lmb * * PROCESS: * - leaf: * +-----------------------------------+ * | 0 | 1 | 2 | 3 | 4 | 5 | * +-----------------------------------+ * * - split: * root * +--------+ * | 2 | * +--------+ * / \ * +-----------------+ +------------------+ * | 0 | 1 | 2 | | 3 | 4 | 5 | * +-----------------+ +------------------+ * nodea nodeb * * ENTER: * - leaf is already locked (L_WRITE) * EXITS: * - a is locked * - b is locked */ static void _leaf_and_lmb_split(struct tree *t, struct node *leaf, struct node **a, struct node **b, struct msg **split_key) { struct child_pointer *cptra; struct child_pointer *cptrb; struct node *leafa; struct node *leafb; struct lmb *mb; struct lmb *mba; struct lmb *mbb; struct msg *sp_key = NULL; __DEBUG("leaf split begin, NID %"PRIu64"" ", nodesz %d" ", nodec %d" ", children %d" , leaf->nid , node_size(leaf) , node_count(leaf) , leaf->n_children); leafa = leaf; cptra = &leafa->parts[0].ptr; /* split lmb of leaf to mba & mbb */ mb = cptra->u.leaf->buffer; lmb_split(mb, &mba, &mbb, &sp_key); lmb_free(mb); /* reset leafa buffer */ cptra->u.leaf->buffer = mba; /* new leafb */ NID nid = hdr_next_nid(t->hdr); node_create(nid, 0, 1, t->hdr->version, t->e, &leafb); cache_put_and_pin(t->cf, nid, leafb); cptrb = &leafb->parts[0].ptr; lmb_free(cptrb->u.leaf->buffer); cptrb->u.leaf->buffer = mbb; /* set dirty */ node_set_dirty(leafa); node_set_dirty(leafb); __DEBUG("leaf split end, leafa NID %"PRIu64"" ", nodesz %d" ", nodec %d" ", children %d" , leafa->nid , node_size(leafa) , node_count(leafa) , leafa->n_children); __DEBUG("leaf split end, leafb NID %"PRIu64"" ", nodesz %d" ", nodec %d" ", children %d" , leafb->nid , node_size(leafb) , node_count(leafb) , leafb->n_children); *a = leafa; *b = leafb; *split_key = sp_key; status_increment(&t->e->status->tree_leaf_split_nums); }