mirror of
https://github.com/facebook/sapling.git
synced 2024-10-11 17:27:53 +03:00
fc8c0d61a1
Summary: This allows us to use fastmanifest as a directory to drop in the python module. Test Plan: compiles, passes existing tests. Reviewers: lcharignon Reviewed By: lcharignon Subscribers: mitrandir, mjpieters Differential Revision: https://phabricator.intern.facebook.com/D3351021 Signature: t1:3351021:1464284417:6cbcde514ab1fd7b5caa6c83cb5577f3502dbc58
135 lines
4.4 KiB
C
135 lines
4.4 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 "node.h"
|
|
#include "tree.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 (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 (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 (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 (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;
|
|
}
|