create cluster table while writing tag data to image
This commit is contained in:
313
src/b-tree.c
313
src/b-tree.c
@@ -1,10 +1,10 @@
|
||||
#include "b-tree.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <blue/core/queue.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "b-tree.h"
|
||||
|
||||
#define SWAP(type, x, y) \
|
||||
do { \
|
||||
type tmp = x; \
|
||||
@@ -18,15 +18,17 @@ struct cache_entry {
|
||||
/* ... node data here ... */
|
||||
};
|
||||
|
||||
#define GET_ENTRY(tree, entries, index) \
|
||||
(b_tree_node_entry *)((unsigned char *)(entries) + ((index) * (tree)->tree_entry_size));
|
||||
|
||||
#define GET_ENTRY(tree, entries, index) \
|
||||
(b_tree_node_entry *)((unsigned char *)(entries) \
|
||||
+ ((index) * (tree)->tree_entry_size));
|
||||
|
||||
static b_tree_node *cache_alloc_node(struct b_tree *tree)
|
||||
{
|
||||
b_queue_iterator it = { 0 };
|
||||
b_queue_foreach (&it, &tree->tree_cache) {
|
||||
struct cache_entry *e = b_unbox(struct cache_entry, it.entry, c_entry);
|
||||
b_queue_iterator it = {0};
|
||||
b_queue_foreach(&it, &tree->tree_cache)
|
||||
{
|
||||
struct cache_entry *e
|
||||
= b_unbox(struct cache_entry, it.entry, c_entry);
|
||||
if (!e->c_allocated) {
|
||||
e->c_allocated = 1;
|
||||
return (b_tree_node *)(e + 1);
|
||||
@@ -49,11 +51,27 @@ static b_tree_node *cache_alloc_node(struct b_tree *tree)
|
||||
|
||||
static void cache_free_node(struct b_tree *tree, b_tree_node *node)
|
||||
{
|
||||
struct cache_entry *e = (struct cache_entry *)((unsigned char *)node - sizeof *e);
|
||||
struct cache_entry *e
|
||||
= (struct cache_entry *)((unsigned char *)node - sizeof *e);
|
||||
e->c_allocated = 0;
|
||||
}
|
||||
|
||||
void b_tree_init(struct b_tree *tree, const struct b_tree_ops *ops, unsigned int node_size, unsigned int entry_size, unsigned int order)
|
||||
b_tree_node *b_tree_cache_alloc_node(struct b_tree *tree)
|
||||
{
|
||||
return cache_alloc_node(tree);
|
||||
}
|
||||
|
||||
void b_tree_cache_release_node(struct b_tree *tree, b_tree_node *node)
|
||||
{
|
||||
cache_free_node(tree, node);
|
||||
}
|
||||
|
||||
void b_tree_init(
|
||||
struct b_tree *tree,
|
||||
const struct b_tree_ops *ops,
|
||||
unsigned int node_size,
|
||||
unsigned int entry_size,
|
||||
unsigned int order)
|
||||
{
|
||||
memset(tree, 0x0, sizeof *tree);
|
||||
assert((order % 2) == 0);
|
||||
@@ -83,82 +101,95 @@ static unsigned long node_get_nr_entries(struct b_tree *tree, b_tree_node *node)
|
||||
return tree->tree_ops->node_get_nr_entries(node);
|
||||
}
|
||||
|
||||
static void node_set_nr_entries(struct b_tree *tree, b_tree_node *node, unsigned long val)
|
||||
static void node_set_nr_entries(
|
||||
struct b_tree *tree,
|
||||
b_tree_node *node,
|
||||
unsigned long val)
|
||||
{
|
||||
tree->tree_ops->node_set_nr_entries(node, val);
|
||||
}
|
||||
|
||||
static long node_get_child(struct b_tree *tree, b_tree_node *node, unsigned long index)
|
||||
static unsigned long node_get_child(
|
||||
struct b_tree *tree,
|
||||
b_tree_node *node,
|
||||
unsigned long index)
|
||||
{
|
||||
uint16_t *children = tree->tree_ops->node_get_children(node);
|
||||
if (children[index] == 0xFFFF) {
|
||||
return B_TREE_INVALID_PTR;
|
||||
}
|
||||
|
||||
return children[index];
|
||||
return tree->tree_ops->node_get_child(node, index);
|
||||
}
|
||||
|
||||
static void node_set_child(struct b_tree *tree, b_tree_node *node, unsigned long index, long ptr)
|
||||
static void node_set_child(
|
||||
struct b_tree *tree,
|
||||
b_tree_node *node,
|
||||
unsigned long index,
|
||||
unsigned long ptr)
|
||||
{
|
||||
uint16_t *children = tree->tree_ops->node_get_children(node);
|
||||
if (ptr == B_TREE_INVALID_PTR) {
|
||||
children[index] = 0xFFFF;
|
||||
} else {
|
||||
children[index] = ptr;
|
||||
}
|
||||
tree->tree_ops->node_set_child(node, index, ptr);
|
||||
}
|
||||
|
||||
static b_tree_node_entry *node_get_entry(struct b_tree *tree, b_tree_node *node, unsigned long index)
|
||||
static b_tree_node_entry *node_get_entry(
|
||||
struct b_tree *tree,
|
||||
b_tree_node *node,
|
||||
unsigned long index)
|
||||
{
|
||||
b_tree_node_entry *entries = tree->tree_ops->node_get_entries(node);
|
||||
return GET_ENTRY(tree, entries, index);
|
||||
return tree->tree_ops->node_get_entry(node, index);
|
||||
}
|
||||
|
||||
static void node_set_entry(struct b_tree *tree, b_tree_node *node, unsigned long index, const b_tree_node_entry *entry)
|
||||
static void node_set_entry(
|
||||
struct b_tree *tree,
|
||||
b_tree_node *node,
|
||||
unsigned long index,
|
||||
const b_tree_node_entry *entry)
|
||||
{
|
||||
b_tree_node_entry *entries = tree->tree_ops->node_get_entries(node);
|
||||
b_tree_node_entry *dest = GET_ENTRY(tree, entries, index);
|
||||
memcpy(dest, entry, tree->tree_entry_size);
|
||||
tree->tree_ops->node_set_entry(node, index, entry);
|
||||
}
|
||||
|
||||
static void node_kill_entry(struct b_tree *tree, b_tree_node *node, unsigned long index)
|
||||
static void node_kill_entry(
|
||||
struct b_tree *tree,
|
||||
b_tree_node *node,
|
||||
unsigned long index)
|
||||
{
|
||||
b_tree_node_entry *entries = tree->tree_ops->node_get_entries(node);
|
||||
b_tree_node_entry *dest = GET_ENTRY(tree, entries, index);
|
||||
memset(dest, 0x0, tree->tree_entry_size);
|
||||
tree->tree_ops->node_kill_entry(node, index);
|
||||
}
|
||||
|
||||
static void node_shift_entries(struct b_tree *tree, b_tree_node *node, unsigned long shift_from, long shift_by)
|
||||
static void node_shift_entries(
|
||||
struct b_tree *tree,
|
||||
b_tree_node *node,
|
||||
unsigned long shift_from,
|
||||
long shift_by)
|
||||
{
|
||||
unsigned long nr_entries = node_get_nr_entries(tree, node);
|
||||
b_tree_node_entry *entries = tree->tree_ops->node_get_entries(node);
|
||||
|
||||
if (shift_from >= nr_entries) {
|
||||
return;
|
||||
}
|
||||
|
||||
b_tree_node_entry *src = GET_ENTRY(tree, entries, shift_from);
|
||||
b_tree_node_entry *dest = GET_ENTRY(tree, entries, shift_from + shift_by);
|
||||
unsigned int count = nr_entries - shift_from;
|
||||
unsigned long src = shift_from;
|
||||
unsigned long dest = shift_from + shift_by;
|
||||
unsigned long count = nr_entries - shift_from;
|
||||
|
||||
memmove(dest, src, tree->tree_entry_size * count);
|
||||
if (shift_by < 0) {
|
||||
dest = GET_ENTRY(tree, entries, nr_entries + shift_by);
|
||||
count = abs(shift_by);
|
||||
for (unsigned long i = 0; i < count; i++) {
|
||||
b_tree_node_entry *entry = node_get_entry(tree, node, src + i);
|
||||
node_set_entry(tree, node, dest + i, entry);
|
||||
}
|
||||
else {
|
||||
|
||||
if (shift_by < 0) {
|
||||
dest = nr_entries + shift_by;
|
||||
count = labs(shift_by);
|
||||
} else {
|
||||
dest = src;
|
||||
count = shift_by;
|
||||
}
|
||||
|
||||
memset(dest, 0x0, count * tree->tree_entry_size);
|
||||
return;
|
||||
node_kill_entry(tree, node, dest);
|
||||
}
|
||||
|
||||
static void node_shift_children(struct b_tree *tree, b_tree_node *node, unsigned long shift_from, long shift_by)
|
||||
static void node_shift_children(
|
||||
struct b_tree *tree,
|
||||
b_tree_node *node,
|
||||
unsigned long shift_from,
|
||||
long shift_by)
|
||||
{
|
||||
unsigned long nr_entries = node_get_nr_entries(tree, node);
|
||||
uint16_t *children = tree->tree_ops->node_get_children(node);
|
||||
|
||||
if (shift_from >= nr_entries + 1) {
|
||||
return;
|
||||
@@ -168,42 +199,56 @@ static void node_shift_children(struct b_tree *tree, b_tree_node *node, unsigned
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t *src = &children[shift_from];
|
||||
uint16_t *dest = &children[shift_from + shift_by];
|
||||
unsigned int count = nr_entries + 1 - shift_from;
|
||||
unsigned long src = shift_from;
|
||||
unsigned long dest = shift_from + shift_by;
|
||||
unsigned long count = nr_entries + 1 - shift_from;
|
||||
if (shift_by > 0) {
|
||||
count -= shift_by;
|
||||
}
|
||||
|
||||
memmove(dest, src, sizeof(uint16_t) * count);
|
||||
if (shift_by < 0) {
|
||||
dest = &children[nr_entries + 1 + shift_from];
|
||||
count = abs(shift_by);
|
||||
for (unsigned long i = 0; i < count; i++) {
|
||||
unsigned long child = node_get_child(tree, node, src + i);
|
||||
node_set_child(tree, node, dest + i, child);
|
||||
}
|
||||
else {
|
||||
|
||||
if (shift_by < 0) {
|
||||
dest = nr_entries + 1 + shift_from;
|
||||
count = labs(shift_by);
|
||||
} else {
|
||||
dest = src;
|
||||
count = shift_by;
|
||||
}
|
||||
|
||||
memset(dest, 0xFF, count * sizeof(uint16_t));
|
||||
node_set_child(tree, node, dest, B_TREE_INVALID_PTR);
|
||||
}
|
||||
|
||||
static void node_move_entries(struct b_tree *tree, b_tree_node *from, b_tree_node *to, unsigned long src_index, unsigned long dest_index, unsigned long count)
|
||||
static void node_move_entries(
|
||||
struct b_tree *tree,
|
||||
b_tree_node *from,
|
||||
b_tree_node *to,
|
||||
unsigned long src_index,
|
||||
unsigned long dest_index,
|
||||
unsigned long count)
|
||||
{
|
||||
unsigned long from_nr_entries = node_get_nr_entries(tree, from);
|
||||
unsigned long to_nr_entries = node_get_nr_entries(tree, to);
|
||||
|
||||
b_tree_node_entry *from_entries = tree->tree_ops->node_get_entries(from);
|
||||
b_tree_node_entry *to_entries = tree->tree_ops->node_get_entries(to);
|
||||
for (unsigned long i = 0; i < count; i++) {
|
||||
b_tree_node_entry *entry
|
||||
= node_get_entry(tree, from, src_index + i);
|
||||
node_set_entry(tree, to, dest_index + i, entry);
|
||||
}
|
||||
|
||||
b_tree_node_entry *src = GET_ENTRY(tree, from_entries, src_index);
|
||||
b_tree_node_entry *dest = GET_ENTRY(tree, to_entries, dest_index);
|
||||
|
||||
memmove(dest, src, count * tree->tree_entry_size);
|
||||
if (src_index + count >= from_nr_entries) {
|
||||
memset(src, 0x0, count * tree->tree_entry_size);
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
node_kill_entry(tree, from, src_index + i);
|
||||
}
|
||||
} else {
|
||||
node_shift_entries(tree, from, src_index + count, (int)count * -1);
|
||||
node_shift_entries(
|
||||
tree,
|
||||
from,
|
||||
src_index + count,
|
||||
(int)count * -1);
|
||||
}
|
||||
|
||||
from_nr_entries -= count;
|
||||
@@ -213,26 +258,50 @@ static void node_move_entries(struct b_tree *tree, b_tree_node *from, b_tree_nod
|
||||
node_set_nr_entries(tree, to, to_nr_entries);
|
||||
}
|
||||
|
||||
static void node_move_children(struct b_tree *tree, b_tree_node *from, b_tree_node *to, unsigned long src_index, unsigned long dest_index, unsigned long count)
|
||||
static void node_move_children(
|
||||
struct b_tree *tree,
|
||||
b_tree_node *from,
|
||||
b_tree_node *to,
|
||||
unsigned long src_index,
|
||||
unsigned long dest_index,
|
||||
unsigned long count)
|
||||
{
|
||||
unsigned long from_nr_entries = node_get_nr_entries(tree, from);
|
||||
|
||||
uint16_t *from_children = tree->tree_ops->node_get_children(from);
|
||||
uint16_t *to_children = tree->tree_ops->node_get_children(to);
|
||||
|
||||
uint16_t *src = &from_children[src_index];
|
||||
uint16_t *dest = &to_children[dest_index];
|
||||
|
||||
memmove(dest, src, count * sizeof(uint16_t));
|
||||
if (src_index + count >= from_nr_entries + 1) {
|
||||
memset(src, 0xFF, count * sizeof(uint16_t));
|
||||
for (unsigned long i = 0; i < count; i++) {
|
||||
unsigned long child = node_get_child(tree, from, src_index + i);
|
||||
node_set_child(tree, to, dest_index + i, child);
|
||||
}
|
||||
else {
|
||||
node_shift_children(tree, from, src_index + count, (int)count * -1);
|
||||
|
||||
if (src_index + count >= from_nr_entries + 1) {
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
node_set_child(
|
||||
tree,
|
||||
from,
|
||||
src_index + i,
|
||||
B_TREE_INVALID_PTR);
|
||||
}
|
||||
} else {
|
||||
node_shift_children(
|
||||
tree,
|
||||
from,
|
||||
src_index + count,
|
||||
(int)count * -1);
|
||||
}
|
||||
}
|
||||
|
||||
static int node_put(struct b_tree *tree, b_tree_node *n, const b_tree_node_entry *e)
|
||||
static int entry_compare(
|
||||
struct b_tree *tree,
|
||||
const b_tree_node_entry *a,
|
||||
const b_tree_node_entry *b)
|
||||
{
|
||||
return tree->tree_ops->entry_compare(a, b);
|
||||
}
|
||||
|
||||
static int node_put(
|
||||
struct b_tree *tree,
|
||||
b_tree_node *n,
|
||||
const b_tree_node_entry *e)
|
||||
{
|
||||
unsigned long nr_entries = node_get_nr_entries(tree, n);
|
||||
if (nr_entries == 0) {
|
||||
@@ -253,8 +322,7 @@ static int node_put(struct b_tree *tree, b_tree_node *n, const b_tree_node_entry
|
||||
|
||||
if (insert_at != -1) {
|
||||
node_shift_entries(tree, n, insert_at, 1);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
insert_at = nr_entries;
|
||||
}
|
||||
|
||||
@@ -278,18 +346,13 @@ static void node_init(struct b_tree *tree, b_tree_node *out)
|
||||
}
|
||||
}
|
||||
|
||||
static int entry_compare(struct b_tree *tree, const b_tree_node_entry *a, const b_tree_node_entry *b)
|
||||
{
|
||||
return tree->tree_ops->entry_compare(a, b);
|
||||
}
|
||||
|
||||
int b_tree_put(struct b_tree *tree, const b_tree_node_entry *to_put)
|
||||
{
|
||||
int depth = 0;
|
||||
|
||||
long current_id = tree->tree_root;
|
||||
long next_id = -1;
|
||||
|
||||
|
||||
b_tree_node *current = cache_alloc_node(tree);
|
||||
b_tree_node *next = cache_alloc_node(tree);
|
||||
|
||||
@@ -305,7 +368,7 @@ int b_tree_put(struct b_tree *tree, const b_tree_node_entry *to_put)
|
||||
/* root node is full. split it pre-emptively. */
|
||||
b_tree_node *a = next;
|
||||
b_tree_node *b = cache_alloc_node(tree);
|
||||
|
||||
|
||||
node_init(tree, a);
|
||||
node_init(tree, b);
|
||||
|
||||
@@ -341,7 +404,8 @@ int b_tree_put(struct b_tree *tree, const b_tree_node_entry *to_put)
|
||||
next_id = node_get_child(tree, current, nr_entries);
|
||||
|
||||
for (i = 0; i < nr_entries; i++) {
|
||||
b_tree_node_entry *entry = node_get_entry(tree, current, i);
|
||||
b_tree_node_entry *entry
|
||||
= node_get_entry(tree, current, i);
|
||||
int cmp = entry_compare(tree, entry, to_put);
|
||||
|
||||
if (cmp == 1) {
|
||||
@@ -358,8 +422,6 @@ int b_tree_put(struct b_tree *tree, const b_tree_node_entry *to_put)
|
||||
nr_entries = node_get_nr_entries(tree, next);
|
||||
if (nr_entries < tree->tree_order - 1) {
|
||||
/* swap current and next pointers. */
|
||||
SWAP(b_tree_node *, current, next);
|
||||
current_id = next_id;
|
||||
|
||||
leaf = node_is_leaf(tree, current);
|
||||
|
||||
@@ -380,7 +442,8 @@ int b_tree_put(struct b_tree *tree, const b_tree_node_entry *to_put)
|
||||
bool n3_is_next = false;
|
||||
nr_entries = node_get_nr_entries(tree, next);
|
||||
int median = nr_entries / 2;
|
||||
b_tree_node_entry *median_node = node_get_entry(tree, next, median);
|
||||
b_tree_node_entry *median_node
|
||||
= node_get_entry(tree, next, median);
|
||||
int cmp = entry_compare(tree, median_node, to_put);
|
||||
if (cmp == -1) {
|
||||
// median++;
|
||||
@@ -401,7 +464,7 @@ int b_tree_put(struct b_tree *tree, const b_tree_node_entry *to_put)
|
||||
median + 1,
|
||||
0,
|
||||
nr_entries - median);
|
||||
|
||||
|
||||
int index = node_put(tree, current, median_node);
|
||||
node_kill_entry(tree, next, median);
|
||||
nr_entries = node_get_nr_entries(tree, next);
|
||||
@@ -420,8 +483,7 @@ int b_tree_put(struct b_tree *tree, const b_tree_node_entry *to_put)
|
||||
cache_free_node(tree, current);
|
||||
current = n3;
|
||||
current_id = n3_id;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
SWAP(b_tree_node *, current, next);
|
||||
current_id = next_id;
|
||||
}
|
||||
@@ -434,4 +496,57 @@ int b_tree_put(struct b_tree *tree, const b_tree_node_entry *to_put)
|
||||
node_write(tree, current_id, current);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int b_tree_get(struct b_tree *tree, b_tree_node_entry *to_get)
|
||||
{
|
||||
long current_id = tree->tree_root;
|
||||
long next_id = -1;
|
||||
|
||||
b_tree_node *current = cache_alloc_node(tree);
|
||||
b_tree_node *next = cache_alloc_node(tree);
|
||||
|
||||
int err = node_read(tree, current_id, current);
|
||||
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
unsigned long nr_entries = node_get_nr_entries(tree, current);
|
||||
|
||||
while (1) {
|
||||
unsigned int i;
|
||||
bool found_bigger_key = false;
|
||||
|
||||
nr_entries = node_get_nr_entries(tree, current);
|
||||
next_id = node_get_child(tree, current, nr_entries);
|
||||
|
||||
for (i = 0; i < nr_entries; i++) {
|
||||
b_tree_node_entry *entry
|
||||
= node_get_entry(tree, current, i);
|
||||
int cmp = entry_compare(tree, entry, to_get);
|
||||
|
||||
if (cmp == 0) {
|
||||
memcpy(to_get, entry, tree->tree_entry_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cmp == 1) {
|
||||
next_id = node_get_child(tree, current, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
err = node_read(tree, next_id, next);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* swap current and next pointers. */
|
||||
SWAP(b_tree_node *, current, next);
|
||||
current_id = next_id;
|
||||
nr_entries = node_get_nr_entries(tree, current);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
40
src/b-tree.h
40
src/b-tree.h
@@ -1,27 +1,42 @@
|
||||
#ifndef B_TREE_H_
|
||||
#define B_TREE_H_
|
||||
|
||||
#include <blue/core/queue.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <blue/core/queue.h>
|
||||
|
||||
#define B_TREE_INVALID_PTR -1
|
||||
|
||||
struct b_tree;
|
||||
typedef struct { char _x; } b_tree_node;
|
||||
typedef struct { char _x; }b_tree_node_entry;
|
||||
typedef struct {
|
||||
char _x;
|
||||
} b_tree_node;
|
||||
typedef struct {
|
||||
char _x;
|
||||
} b_tree_node_entry;
|
||||
|
||||
struct b_tree_ops {
|
||||
int (*tree_get_node)(struct b_tree *, unsigned long, b_tree_node *);
|
||||
int (*tree_put_node)(struct b_tree *, unsigned long, const b_tree_node *);
|
||||
int (*tree_put_node)(
|
||||
struct b_tree *,
|
||||
unsigned long,
|
||||
const b_tree_node *);
|
||||
long (*tree_alloc_node)(struct b_tree *);
|
||||
|
||||
unsigned long (*node_get_nr_entries)(b_tree_node *);
|
||||
void (*node_set_nr_entries)(b_tree_node *, unsigned long);
|
||||
b_tree_node_entry *(*node_get_entries)(b_tree_node *);
|
||||
uint16_t *(*node_get_children)(b_tree_node *);
|
||||
b_tree_node_entry *(*node_get_entry)(b_tree_node *, unsigned long);
|
||||
void (*node_set_entry)(
|
||||
b_tree_node *,
|
||||
unsigned long,
|
||||
const b_tree_node_entry *);
|
||||
void (*node_kill_entry)(b_tree_node *, unsigned long);
|
||||
unsigned long (*node_get_child)(b_tree_node *, unsigned long);
|
||||
void (*node_set_child)(b_tree_node *, unsigned long, unsigned long);
|
||||
|
||||
int (*entry_compare)(const b_tree_node_entry *, const b_tree_node_entry *);
|
||||
int (*entry_compare)(
|
||||
const b_tree_node_entry *,
|
||||
const b_tree_node_entry *);
|
||||
};
|
||||
|
||||
struct b_tree {
|
||||
@@ -33,7 +48,16 @@ struct b_tree {
|
||||
long tree_root;
|
||||
};
|
||||
|
||||
extern void b_tree_init(struct b_tree *tree, const struct b_tree_ops *ops, unsigned int node_size, unsigned int entry_size, unsigned int order);
|
||||
extern void b_tree_init(
|
||||
struct b_tree *tree,
|
||||
const struct b_tree_ops *ops,
|
||||
unsigned int node_size,
|
||||
unsigned int entry_size,
|
||||
unsigned int order);
|
||||
extern int b_tree_put(struct b_tree *tree, const b_tree_node_entry *entry);
|
||||
extern int b_tree_get(struct b_tree *tree, b_tree_node_entry *entry);
|
||||
|
||||
extern b_tree_node *b_tree_cache_alloc_node(struct b_tree *tree);
|
||||
extern void b_tree_cache_release_node(struct b_tree *tree, b_tree_node *node);
|
||||
|
||||
#endif
|
||||
|
||||
87
src/bin.h
87
src/bin.h
@@ -1,9 +1,10 @@
|
||||
#ifndef BIN_H_
|
||||
#define BIN_H_
|
||||
|
||||
#include <blue/core/endian.h>
|
||||
#include "misc.h"
|
||||
|
||||
#include <blue/core/endian.h>
|
||||
|
||||
#define EC3_SIGNATURE 0x45433358
|
||||
|
||||
#define EC3_VERSION_1_0 0x0100
|
||||
@@ -34,6 +35,8 @@
|
||||
#define EC3_TAG_COMPRESSED 0x00000002u
|
||||
#define EC3_TAG_ENCRYPTED 0x00000004u
|
||||
|
||||
#define EC3_INVALID_OFFSET 0xFFFFFFFFu
|
||||
|
||||
/* 32K per cluster group */
|
||||
#define EC3_CLUSTERS_PER_GROUP 1637
|
||||
/* 1K per extent group */
|
||||
@@ -68,52 +71,46 @@
|
||||
|
||||
typedef uint8_t ec3_chunk_id[EC3_CHUNK_ID_SIZE];
|
||||
|
||||
PACK(
|
||||
struct ec3_header {
|
||||
b_i32 h_magic;
|
||||
b_i16 h_version;
|
||||
b_i16 h_cluster_size;
|
||||
b_i64 h_tag_table_offset;
|
||||
b_i64 h_extent_table_offset;
|
||||
b_i64 h_cluster_table_offset;
|
||||
b_i32 h_tag_count;
|
||||
b_i32 h_extent_count;
|
||||
b_i32 h_cluster_group_count;
|
||||
b_i16 h_compression;
|
||||
b_i16 h_encryption;
|
||||
b_i64 h_app_magic;
|
||||
uint8_t h_reserved[8];
|
||||
}
|
||||
);
|
||||
PACK(struct ec3_header {
|
||||
b_i32 h_magic;
|
||||
b_i16 h_version;
|
||||
b_i16 h_cluster_size;
|
||||
b_i64 h_tag_table_offset;
|
||||
b_i64 h_extent_table_offset;
|
||||
b_i64 h_cluster_table_offset;
|
||||
b_i32 h_tag_count;
|
||||
b_i32 h_extent_count;
|
||||
b_i32 h_cluster_group_count;
|
||||
b_i16 h_compression;
|
||||
b_i16 h_encryption;
|
||||
b_i64 h_app_magic;
|
||||
uint8_t h_reserved[8];
|
||||
});
|
||||
|
||||
PACK(
|
||||
struct ec3_cluster {
|
||||
/* cluster identifier */
|
||||
b_i32 c_id;
|
||||
/* lower 32-bits of the cluster bounds */
|
||||
b_i32 c_bounds0;
|
||||
/* upper 32-bits of the cluster bounds */
|
||||
b_i32 c_bounds1;
|
||||
/* CRC-16 of the on-disk cluster data */
|
||||
b_i16 c_checksum;
|
||||
/* flags that apply to this cluster */
|
||||
b_i16 c_flags;
|
||||
}
|
||||
);
|
||||
PACK(struct ec3_cluster {
|
||||
/* cluster identifier */
|
||||
b_i32 c_id;
|
||||
/* lower 32-bits of the cluster bounds */
|
||||
b_i32 c_bounds0;
|
||||
/* upper 32-bits of the cluster bounds */
|
||||
b_i32 c_bounds1;
|
||||
/* CRC-16 of the on-disk cluster data */
|
||||
b_i16 c_checksum;
|
||||
/* flags that apply to this cluster */
|
||||
b_i16 c_flags;
|
||||
});
|
||||
|
||||
PACK(
|
||||
struct ec3_cluster_group {
|
||||
/* the number of clusters that this group contains */
|
||||
b_i16 g_nr_clusters;
|
||||
uint8_t g_reserved[2];
|
||||
/* array of clusters contained within the group. */
|
||||
struct ec3_cluster g_clusters[EC3_CLUSTERS_PER_GROUP];
|
||||
/* offsets to other cluster groups, relative to the start of the
|
||||
* cluster group table. the cluster groups form a B-tree. */
|
||||
b_i32 g_child_offsets[EC3_CLUSTERS_PER_GROUP + 1];
|
||||
uint8_t g_padding[20];
|
||||
}
|
||||
);
|
||||
PACK(struct ec3_cluster_group {
|
||||
/* the number of clusters that this group contains */
|
||||
b_i16 g_nr_clusters;
|
||||
uint8_t g_reserved[2];
|
||||
/* array of clusters contained within the group. */
|
||||
struct ec3_cluster g_clusters[EC3_CLUSTERS_PER_GROUP];
|
||||
/* offsets to other cluster groups, relative to the start of the
|
||||
* cluster group table. the cluster groups form a B-tree. */
|
||||
b_i32 g_child_offsets[EC3_CLUSTERS_PER_GROUP + 1];
|
||||
uint8_t g_padding[20];
|
||||
});
|
||||
|
||||
struct ec3_tag_table_entry {
|
||||
b_i32 tag_type;
|
||||
|
||||
218
src/cluster.c
218
src/cluster.c
@@ -1,19 +1,149 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "bin.h"
|
||||
#include "cluster.h"
|
||||
|
||||
#include "bin.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static int node_init(struct ec3_cluster_group *n)
|
||||
{
|
||||
memset(n, 0x0, sizeof *n);
|
||||
|
||||
for (int i = 0; i < EC3_CLUSTERS_PER_GROUP + 1; i++) {
|
||||
n->g_child_offsets[i] = b_i32_htob(EC3_INVALID_OFFSET);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tree_get_node(struct b_tree *p, unsigned long id, b_tree_node *n)
|
||||
{
|
||||
struct cluster_table *table = (struct cluster_table *)p;
|
||||
size_t offset = (id * sizeof(struct ec3_cluster_group));
|
||||
fseek(table->t_storage, offset, SEEK_SET);
|
||||
size_t r
|
||||
= fread(n,
|
||||
sizeof(struct ec3_cluster_group),
|
||||
1,
|
||||
table->t_storage);
|
||||
return r == 1 ? 0 : -1;
|
||||
}
|
||||
|
||||
static int tree_put_node(
|
||||
struct b_tree *p,
|
||||
unsigned long id,
|
||||
const b_tree_node *n)
|
||||
{
|
||||
struct cluster_table *table = (struct cluster_table *)p;
|
||||
size_t offset = (id * sizeof(struct ec3_cluster_group));
|
||||
fseek(table->t_storage, offset, SEEK_SET);
|
||||
size_t r = fwrite(
|
||||
n,
|
||||
sizeof(struct ec3_cluster_group),
|
||||
1,
|
||||
table->t_storage);
|
||||
return r == 1 ? 0 : -1;
|
||||
}
|
||||
|
||||
static long tree_alloc_node(struct b_tree *p)
|
||||
{
|
||||
struct cluster_table *table = (struct cluster_table *)p;
|
||||
size_t pos = ftell(table->t_storage);
|
||||
fseek(table->t_storage, 0, SEEK_END);
|
||||
size_t len = ftell(table->t_storage);
|
||||
|
||||
struct ec3_cluster_group *n
|
||||
= (struct ec3_cluster_group *)b_tree_cache_alloc_node(p);
|
||||
node_init(n);
|
||||
|
||||
fwrite(&n, sizeof *n, 1, table->t_storage);
|
||||
|
||||
fseek(table->t_storage, pos, SEEK_SET);
|
||||
|
||||
len /= sizeof *n;
|
||||
|
||||
return (long)len;
|
||||
}
|
||||
|
||||
static unsigned long node_get_nr_entries(b_tree_node *n)
|
||||
{
|
||||
struct ec3_cluster_group *node = (struct ec3_cluster_group *)n;
|
||||
return b_i16_btoh(node->g_nr_clusters);
|
||||
}
|
||||
|
||||
static void node_set_nr_entries(b_tree_node *n, unsigned long val)
|
||||
{
|
||||
struct ec3_cluster_group *node = (struct ec3_cluster_group *)n;
|
||||
node->g_nr_clusters = b_i16_htob(val);
|
||||
}
|
||||
|
||||
static b_tree_node_entry *node_get_entry(b_tree_node *n, unsigned long index)
|
||||
{
|
||||
struct ec3_cluster_group *node = (struct ec3_cluster_group *)n;
|
||||
return (b_tree_node_entry *)&node->g_clusters[index];
|
||||
}
|
||||
|
||||
static void node_set_entry(
|
||||
b_tree_node *n,
|
||||
unsigned long index,
|
||||
const b_tree_node_entry *entry)
|
||||
{
|
||||
struct ec3_cluster_group *node = (struct ec3_cluster_group *)n;
|
||||
memmove(&node->g_clusters[index], entry, sizeof(struct ec3_cluster));
|
||||
}
|
||||
|
||||
static unsigned long node_get_child(b_tree_node *n, unsigned long index)
|
||||
{
|
||||
struct ec3_cluster_group *node = (struct ec3_cluster_group *)n;
|
||||
b_i32 enc_child = node->g_child_offsets[index];
|
||||
unsigned long child = b_i32_btoh(enc_child);
|
||||
return child == EC3_INVALID_OFFSET ? B_TREE_INVALID_PTR : child;
|
||||
}
|
||||
|
||||
static void node_set_child(
|
||||
b_tree_node *n,
|
||||
unsigned long index,
|
||||
unsigned long ptr)
|
||||
{
|
||||
struct ec3_cluster_group *node = (struct ec3_cluster_group *)n;
|
||||
unsigned long child = ptr == B_TREE_INVALID_PTR ? EC3_INVALID_OFFSET
|
||||
: (uint16_t)ptr;
|
||||
node->g_child_offsets[index] = b_i32_htob(child);
|
||||
}
|
||||
|
||||
static int entry_compare(
|
||||
const b_tree_node_entry *e0,
|
||||
const b_tree_node_entry *e1)
|
||||
{
|
||||
struct ec3_cluster *a = (struct ec3_cluster *)e0,
|
||||
*b = (struct ec3_cluster *)e1;
|
||||
|
||||
unsigned long a_id = b_i32_btoh(a->c_id);
|
||||
unsigned long b_id = b_i32_btoh(b->c_id);
|
||||
|
||||
if (a_id < b_id) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (a_id > b_id) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct b_tree_ops cluster_table_ops = {
|
||||
.tree_get_node = NULL,
|
||||
.tree_put_node = NULL,
|
||||
.tree_alloc_node = NULL,
|
||||
.tree_get_node = tree_get_node,
|
||||
.tree_put_node = tree_put_node,
|
||||
.tree_alloc_node = tree_alloc_node,
|
||||
|
||||
.node_get_nr_entries = NULL,
|
||||
.node_set_nr_entries = NULL,
|
||||
.node_get_entries = NULL,
|
||||
.node_get_children = NULL,
|
||||
.node_get_nr_entries = node_get_nr_entries,
|
||||
.node_set_nr_entries = node_set_nr_entries,
|
||||
.node_get_entry = node_get_entry,
|
||||
.node_set_entry = node_set_entry,
|
||||
.node_get_child = node_get_child,
|
||||
.node_set_child = node_set_child,
|
||||
|
||||
.entry_compare = NULL,
|
||||
.entry_compare = entry_compare,
|
||||
};
|
||||
|
||||
void cluster_table_init(struct cluster_table *table, FILE *storage)
|
||||
@@ -22,20 +152,74 @@ void cluster_table_init(struct cluster_table *table, FILE *storage)
|
||||
|
||||
table->t_storage = storage;
|
||||
|
||||
b_tree_init(&table->t_base, &cluster_table_ops, sizeof(struct ec3_cluster_group), sizeof(struct ec3_cluster), EC3_CLUSTERS_PER_GROUP + 1);
|
||||
b_tree_init(
|
||||
&table->t_base,
|
||||
&cluster_table_ops,
|
||||
sizeof(struct ec3_cluster_group),
|
||||
sizeof(struct ec3_cluster),
|
||||
EC3_CLUSTERS_PER_GROUP + 1);
|
||||
|
||||
/* allocate root node */
|
||||
struct ec3_cluster_group *root
|
||||
= (struct ec3_cluster_group *)b_tree_cache_alloc_node(
|
||||
&table->t_base);
|
||||
node_init(root);
|
||||
tree_put_node(&table->t_base, 0, (b_tree_node *)root);
|
||||
b_tree_cache_release_node(&table->t_base, (b_tree_node *)root);
|
||||
}
|
||||
|
||||
void cluster_table_finish(struct cluster_table *table)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int cluster_table_get(struct cluster_table *table, unsigned long id, struct cluster *out)
|
||||
static void encode_cluster(const struct cluster *in, struct ec3_cluster *out)
|
||||
{
|
||||
return -1;
|
||||
out->c_id = b_i32_htob(in->c_id);
|
||||
out->c_flags = b_i16_htob(in->c_flags);
|
||||
out->c_checksum = b_i16_htob(in->c_checksum);
|
||||
uint32_t bounds_lo = in->c_base & 0xFFFFFFFF;
|
||||
uint32_t bounds_hi = (in->c_base >> 32) & 0xFFFF;
|
||||
bounds_hi |= ((uint32_t)(in->c_len & 0xFFFF)) << 16;
|
||||
|
||||
out->c_bounds0 = b_i32_htob(bounds_lo);
|
||||
out->c_bounds1 = b_i32_htob(bounds_hi);
|
||||
}
|
||||
|
||||
static void decode_cluster(const struct ec3_cluster *in, struct cluster *out)
|
||||
{
|
||||
out->c_id = b_i32_btoh(in->c_id);
|
||||
out->c_flags = b_i16_btoh(in->c_flags);
|
||||
out->c_checksum = b_i16_btoh(in->c_checksum);
|
||||
|
||||
uint32_t bounds_lo = b_i32_btoh(in->c_bounds0);
|
||||
uint32_t bounds_hi = b_i32_btoh(in->c_bounds1);
|
||||
|
||||
out->c_base = (size_t)bounds_lo | ((size_t)bounds_hi & 0xFFFF) << 32;
|
||||
out->c_len = ((size_t)bounds_hi >> 16) & 0xFFFF;
|
||||
}
|
||||
|
||||
int cluster_table_get(
|
||||
struct cluster_table *table,
|
||||
unsigned long id,
|
||||
struct cluster *out)
|
||||
{
|
||||
struct ec3_cluster entry = {0};
|
||||
entry.c_id = b_i32_htob(id);
|
||||
|
||||
int err = b_tree_get(&table->t_base, (b_tree_node_entry *)&entry);
|
||||
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
decode_cluster(&entry, out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cluster_table_put(struct cluster_table *table, const struct cluster *in)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
struct ec3_cluster entry = {0};
|
||||
encode_cluster(in, &entry);
|
||||
|
||||
return b_tree_put(&table->t_base, (b_tree_node_entry *)&entry);
|
||||
}
|
||||
|
||||
89
src/create.c
89
src/create.c
@@ -1,17 +1,17 @@
|
||||
#include "b-tree.h"
|
||||
#include "bin.h"
|
||||
#include "commands.h"
|
||||
#include "b-tree.h"
|
||||
|
||||
#include <blue/cmd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <zstd.h>
|
||||
|
||||
#define INVALID_NODE_PTR 0xFFFF
|
||||
#define INVALID_NODE_PTR 0xFFFF
|
||||
|
||||
#define ORDER 6
|
||||
#define MAX (ORDER - 1)
|
||||
#define MIN (MAX / 2)
|
||||
#define ORDER 6
|
||||
#define MAX (ORDER - 1)
|
||||
#define MIN (MAX / 2)
|
||||
|
||||
enum {
|
||||
ARG_INPATH,
|
||||
@@ -19,8 +19,7 @@ enum {
|
||||
OPT_OUTPATH_PATH,
|
||||
};
|
||||
|
||||
struct entry
|
||||
{
|
||||
struct entry {
|
||||
uint32_t key;
|
||||
uint32_t value;
|
||||
};
|
||||
@@ -38,7 +37,7 @@ struct data_tree {
|
||||
|
||||
static int node_init(struct node *n)
|
||||
{
|
||||
memset(n, 0x0, sizeof * n);
|
||||
memset(n, 0x0, sizeof *n);
|
||||
|
||||
for (int i = 0; i < ORDER; i++) {
|
||||
n->children[i] = INVALID_NODE_PTR;
|
||||
@@ -56,7 +55,10 @@ static int tree_get_node(struct b_tree *p, unsigned long id, b_tree_node *n)
|
||||
return r == 1 ? 0 : -1;
|
||||
}
|
||||
|
||||
static int tree_put_node(struct b_tree *p, unsigned long id, const b_tree_node *n)
|
||||
static int tree_put_node(
|
||||
struct b_tree *p,
|
||||
unsigned long id,
|
||||
const b_tree_node *n)
|
||||
{
|
||||
struct data_tree *tree = (struct data_tree *)p;
|
||||
size_t offset = (id * sizeof(struct node));
|
||||
@@ -96,19 +98,42 @@ static void node_set_nr_entries(b_tree_node *n, unsigned long val)
|
||||
node->nr_entries = val;
|
||||
}
|
||||
|
||||
static b_tree_node_entry *node_get_entries(b_tree_node *n)
|
||||
static b_tree_node_entry *node_get_entry(b_tree_node *n, unsigned long index)
|
||||
{
|
||||
struct node *node = (struct node *)n;
|
||||
return (b_tree_node_entry *)node->entries;
|
||||
return (b_tree_node_entry *)&node->entries[index];
|
||||
}
|
||||
|
||||
static uint16_t *node_get_children(b_tree_node *n)
|
||||
static void node_set_entry(
|
||||
b_tree_node *n,
|
||||
unsigned long index,
|
||||
const b_tree_node_entry *entry)
|
||||
{
|
||||
struct node *node = (struct node *)n;
|
||||
return node->children;
|
||||
memmove(&node->entries[index], entry, sizeof(struct entry));
|
||||
}
|
||||
|
||||
static int entry_compare(const b_tree_node_entry *e0, const b_tree_node_entry *e1)
|
||||
static unsigned long node_get_child(b_tree_node *n, unsigned long index)
|
||||
{
|
||||
struct node *node = (struct node *)n;
|
||||
uint16_t child = node->children[index];
|
||||
return child == INVALID_NODE_PTR ? B_TREE_INVALID_PTR : child;
|
||||
}
|
||||
|
||||
static void node_set_child(
|
||||
b_tree_node *n,
|
||||
unsigned long index,
|
||||
unsigned long ptr)
|
||||
{
|
||||
struct node *node = (struct node *)n;
|
||||
uint16_t child
|
||||
= ptr == B_TREE_INVALID_PTR ? INVALID_NODE_PTR : (uint16_t)ptr;
|
||||
node->children[index] = child;
|
||||
}
|
||||
|
||||
static int entry_compare(
|
||||
const b_tree_node_entry *e0,
|
||||
const b_tree_node_entry *e1)
|
||||
{
|
||||
struct entry *a = (struct entry *)e0, *b = (struct entry *)e1;
|
||||
|
||||
@@ -130,8 +155,10 @@ static const struct b_tree_ops ops = {
|
||||
|
||||
.node_get_nr_entries = node_get_nr_entries,
|
||||
.node_set_nr_entries = node_set_nr_entries,
|
||||
.node_get_entries = node_get_entries,
|
||||
.node_get_children = node_get_children,
|
||||
.node_get_entry = node_get_entry,
|
||||
.node_set_entry = node_set_entry,
|
||||
.node_get_child = node_get_child,
|
||||
.node_set_child = node_set_child,
|
||||
|
||||
.entry_compare = entry_compare,
|
||||
};
|
||||
@@ -161,10 +188,13 @@ int node_print(struct b_tree *tree, struct node *n, int depth)
|
||||
continue;
|
||||
}
|
||||
|
||||
err = tree_get_node(tree, n->children[index], (b_tree_node *)&child);
|
||||
err = tree_get_node(
|
||||
tree,
|
||||
n->children[index],
|
||||
(b_tree_node *)&child);
|
||||
if (err != 0) {
|
||||
printf("ERR: failed to read node %u\n",
|
||||
n->children[index]);
|
||||
n->children[index]);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -193,10 +223,13 @@ int node_print(struct b_tree *tree, struct node *n, int depth)
|
||||
continue;
|
||||
}
|
||||
|
||||
err = tree_get_node(tree, n->children[index], (b_tree_node *)&child);
|
||||
err = tree_get_node(
|
||||
tree,
|
||||
n->children[index],
|
||||
(b_tree_node *)&child);
|
||||
if (err != 0) {
|
||||
printf("ERR: failed to read node %u\n",
|
||||
n->children[index]);
|
||||
n->children[index]);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -240,20 +273,24 @@ static int create(
|
||||
fwrite(&root, sizeof root, 1, fp);
|
||||
|
||||
struct data_tree tree;
|
||||
b_tree_init(&tree.base, &ops, sizeof(struct node), sizeof(struct entry), ORDER);
|
||||
b_tree_init(
|
||||
&tree.base,
|
||||
&ops,
|
||||
sizeof(struct node),
|
||||
sizeof(struct entry),
|
||||
ORDER);
|
||||
tree.fp = fp;
|
||||
|
||||
|
||||
for (int i = 1; i <= 32; i++) {
|
||||
int key = rand() % 65535;
|
||||
//int key = i;
|
||||
// printf("%d: adding [%d]\n", i, key);
|
||||
struct entry e = { .key = key, .value = key * 2 };
|
||||
// int key = i;
|
||||
// printf("%d: adding [%d]\n", i, key);
|
||||
struct entry e = {.key = key, .value = key * 2};
|
||||
b_tree_put(&tree.base, (b_tree_node_entry *)&e);
|
||||
}
|
||||
|
||||
tree_print(&tree.base);
|
||||
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
|
||||
20
src/write.c
20
src/write.c
@@ -1,6 +1,7 @@
|
||||
#include "write.h"
|
||||
|
||||
#include "bin.h"
|
||||
#include "cluster.h"
|
||||
#include "pipeline.h"
|
||||
|
||||
#include <blue/core/queue.h>
|
||||
@@ -19,9 +20,10 @@ struct ec3_writer {
|
||||
size_t w_extent_nr_clusters;
|
||||
|
||||
size_t w_data_offset;
|
||||
size_t w_next_cluster_id;
|
||||
|
||||
FILE *w_data;
|
||||
FILE *w_cluster_table;
|
||||
struct cluster_table w_cluster_table;
|
||||
FILE *w_extent_table;
|
||||
FILE *w_tag_table;
|
||||
|
||||
@@ -83,8 +85,10 @@ enum ec3_status ec3_writer_create(
|
||||
|
||||
size_t cluster_size = cluster_sizes[param->p_cluster_size];
|
||||
|
||||
FILE *cluster_table = tmpfile();
|
||||
|
||||
writer->w_data = param->p_outp;
|
||||
writer->w_cluster_table = tmpfile();
|
||||
cluster_table_init(&writer->w_cluster_table, cluster_table);
|
||||
writer->w_extent_table = tmpfile();
|
||||
writer->w_tag_table = tmpfile();
|
||||
|
||||
@@ -190,7 +194,7 @@ void ec3_writer_finish(struct ec3_writer *w)
|
||||
}
|
||||
|
||||
size_t cluster_table_offset = ftell(w->w_data);
|
||||
status = copy_file(w->w_cluster_table, w->w_data);
|
||||
status = copy_file(w->w_cluster_table.t_storage, w->w_data);
|
||||
|
||||
size_t extent_table_offset = ftell(w->w_data);
|
||||
status = copy_file(w->w_extent_table, w->w_data);
|
||||
@@ -291,6 +295,16 @@ static enum ec3_status flush_tag_buffer(struct ec3_tag_writer *w)
|
||||
return status;
|
||||
}
|
||||
|
||||
struct cluster cluster = {
|
||||
.c_id = container->w_next_cluster_id++,
|
||||
.c_base = container->w_data_offset,
|
||||
.c_len = nr_written,
|
||||
.c_flags = w->w_flags,
|
||||
.c_checksum = 0,
|
||||
};
|
||||
|
||||
cluster_table_put(&container->w_cluster_table, &cluster);
|
||||
|
||||
container->w_data_offset += nr_written;
|
||||
w->w_ptr = 0;
|
||||
w->w_nr_clusters++;
|
||||
|
||||
Reference in New Issue
Block a user