mirror of
https://github.com/facebook/sapling.git
synced 2024-10-12 09:48:05 +03:00
c12e300bb8
Summary: Move top-level Python packages `mercurial`, `hgext` and `hgdemandimport` to a new top-level package `edenscm`. This allows the Python packages provided by the upstream Mercurial to be installed side-by-side. To maintain compatibility, `edenscm/` gets added to `sys.path` in `mercurial/__init__.py`. Reviewed By: phillco, ikostia Differential Revision: D13853115 fbshipit-source-id: b296b0673dc54c61ef6a591ebc687057ff53b22e
136 lines
4.5 KiB
C
136 lines
4.5 KiB
C
// Copyright 2016-present Facebook. All Rights Reserved.
|
|
//
|
|
// tree_arena.c: methods to create a tree with a fixed memory arena and to
|
|
// allocate nodes from the fixed memory arena.
|
|
//
|
|
// no-check-code
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "edenscm/hgext/extlib/cfastmanifest/tree.h"
|
|
#include "node.h"
|
|
#include "tree_arena.h"
|
|
|
|
#define ARENA_INCREMENT_PERCENTAGE 20
|
|
#define ARENA_MIN_STORAGE_INCREMENT (1024 * 1024)
|
|
#define ARENA_MAX_STORAGE_INCREMENT (16 * 1024 * 1024)
|
|
|
|
static inline size_t calculate_arena_free(const tree_t* tree) {
|
|
intptr_t arena_start = (intptr_t)tree->arena;
|
|
intptr_t arena_free_start = (intptr_t)tree->arena_free_start;
|
|
intptr_t arena_end = arena_start + tree->arena_sz;
|
|
size_t arena_free = arena_end - arena_free_start;
|
|
|
|
return arena_free;
|
|
}
|
|
|
|
arena_alloc_node_result_t arena_alloc_node_helper(
|
|
arena_policy_t policy,
|
|
tree_t* tree,
|
|
const char* name,
|
|
size_t name_sz,
|
|
size_t max_children) {
|
|
// since name_sz and max_chlidren are going to be downcasted, we should verify
|
|
// that they're not too large for the types in node.h
|
|
if (!VERIFY_NAME_SZ(name_sz) || !VERIFY_CHILD_NUM(max_children)) {
|
|
return COMPOUND_LITERAL(arena_alloc_node_result_t){
|
|
ARENA_ALLOC_EXCEEDED_LIMITS, NULL};
|
|
}
|
|
|
|
do {
|
|
size_t arena_free = calculate_arena_free(tree);
|
|
|
|
node_t* candidate = (node_t*)tree->arena_free_start;
|
|
void* next = setup_node(
|
|
tree->arena_free_start,
|
|
arena_free,
|
|
name,
|
|
(name_sz_t)name_sz,
|
|
(child_num_t)max_children);
|
|
|
|
if (next == NULL) {
|
|
if (policy == ARENA_POLICY_FAIL) {
|
|
return COMPOUND_LITERAL(arena_alloc_node_result_t){ARENA_ALLOC_OOM,
|
|
NULL};
|
|
} else {
|
|
size_t new_arena_sz =
|
|
(tree->arena_sz * (100 + ARENA_INCREMENT_PERCENTAGE)) / 100;
|
|
// TODO: optimization opportunity!
|
|
// we can calculate how much free space we need and set that as another
|
|
// minimum. in the unlikely scenario we need a huge node, just setting
|
|
// the lower bound on ARENA_MIN_STORAGE_INCREMENT may require multiple
|
|
// rounds of realloc.
|
|
if (new_arena_sz - tree->arena_sz < ARENA_MIN_STORAGE_INCREMENT) {
|
|
new_arena_sz = tree->arena_sz + ARENA_MIN_STORAGE_INCREMENT;
|
|
}
|
|
if (new_arena_sz - tree->arena_sz > ARENA_MAX_STORAGE_INCREMENT) {
|
|
new_arena_sz = tree->arena_sz + ARENA_MAX_STORAGE_INCREMENT;
|
|
}
|
|
|
|
// resize the arena so it's bigger.
|
|
void* new_arena = realloc(tree->arena, new_arena_sz);
|
|
|
|
if (new_arena == NULL) {
|
|
return COMPOUND_LITERAL(arena_alloc_node_result_t){ARENA_ALLOC_OOM,
|
|
NULL};
|
|
}
|
|
|
|
// success! update the pointers.
|
|
if (new_arena != tree->arena) {
|
|
intptr_t arena_start = (intptr_t)tree->arena;
|
|
intptr_t arena_free_start = (intptr_t)tree->arena_free_start;
|
|
intptr_t new_arena_start = (intptr_t)new_arena;
|
|
|
|
// if the shadow root is inside the arena, we need to relocate it.
|
|
if (in_arena(tree, tree->shadow_root)) {
|
|
intptr_t shadow_root = (intptr_t)tree->shadow_root;
|
|
ptrdiff_t shadow_root_offset = shadow_root - arena_start;
|
|
|
|
tree->shadow_root = (node_t*)(new_arena_start + shadow_root_offset);
|
|
}
|
|
|
|
intptr_t new_arena_free_start = new_arena_start;
|
|
new_arena_free_start += (arena_free_start - arena_start);
|
|
tree->arena_free_start = (void*)new_arena_free_start;
|
|
tree->arena = new_arena;
|
|
}
|
|
tree->arena_sz = new_arena_sz;
|
|
}
|
|
} else {
|
|
tree->arena_free_start = next;
|
|
tree->consumed_memory += candidate->block_sz;
|
|
return COMPOUND_LITERAL(arena_alloc_node_result_t){ARENA_ALLOC_OK,
|
|
candidate};
|
|
}
|
|
} while (true);
|
|
}
|
|
|
|
tree_t* alloc_tree_with_arena(size_t arena_sz) {
|
|
void* arena = malloc(arena_sz);
|
|
tree_t* tree = (tree_t*)calloc(1, sizeof(tree_t));
|
|
node_t* shadow_root = alloc_node("/", 1, 1);
|
|
|
|
if (arena == NULL || tree == NULL || shadow_root == NULL) {
|
|
free(arena);
|
|
free(tree);
|
|
free(shadow_root);
|
|
return NULL;
|
|
}
|
|
|
|
#if 0 // FIXME: (ttung) probably remove this
|
|
tree->mode = STANDARD_MODE;
|
|
#endif /* #if 0 */
|
|
tree->arena = tree->arena_free_start = arena;
|
|
tree->arena_sz = arena_sz;
|
|
tree->compacted = true;
|
|
tree->shadow_root = NULL;
|
|
|
|
tree->consumed_memory = 0;
|
|
tree->num_leaf_nodes = 0;
|
|
|
|
shadow_root->type = TYPE_ROOT;
|
|
tree->shadow_root = shadow_root;
|
|
|
|
return tree;
|
|
}
|