Reduces memory usage, with new array growing by fixed size and not exponential.

This commit is contained in:
Andrea Mazzoleni 2013-09-28 09:40:08 +02:00
parent 7f02cd068f
commit d525b4a14a
18 changed files with 497 additions and 53 deletions

13
HISTORY
View file

@ -1,21 +1,22 @@
SnapRAID HISTORY
================
5.0 2013/9 (BETA)
=================
* Adds support for RAIDTP (Triple Parity) and RAIDQP (Quad Parity).
5.0 2013/10
===========
* Added support for RAIDTP (Triple Parity) and RAIDQP (Quad Parity).
For Quad Parity, and only for Quad Parity, there is a limitation of
using no more than 21 data disks. This is a conseguence of the
high performant parity generator matrix used. An extension supporting
up to 89 disks with Hexa (6) parity is possible, but not yet implemented.
Note that more general approaches without these limitations are also
possible, but they would affect badly the performance.
* Reduced memory usage avoiding to allocate unnecessary memory.
4.1 2013/9 (BETA)
=================
4.1 2013/9
==========
* If the underline filesystem doesn't support the FIEMAP command,
automatically fallback to use FIBMAP for sorting files.
* Fixes the import of content files from previous version of SnapRAID that
* Fixed the import of content files from previous version of SnapRAID that
are the result of an incomplete sync.
* Added a new -C, --gen-conf option to generate a dummy configuration
file from the info in the content file.

View file

@ -44,6 +44,8 @@ noinst_HEADERS = \
spooky2test.c \
tommyarray.h \
tommyarrayof.h \
tommyarrayblk.h \
tommyarrayblkof.h \
tommychain.h \
tommyhash.h \
tommyhashdyn.h \
@ -51,6 +53,8 @@ noinst_HEADERS = \
tommytypes.h \
tommyarray.c \
tommyarrayof.c \
tommyarrayblk.c \
tommyarrayblkof.c \
tommyhash.c \
tommyhashdyn.c \
tommylist.c \

12
elem.c
View file

@ -252,7 +252,7 @@ int filter_existence(int filter_missing, const char* dir, const char* sub)
return 1;
}
int filter_correctness(int filter_error, tommy_arrayof* infoarr, struct snapraid_file* file)
int filter_correctness(int filter_error, tommy_arrayblkof* infoarr, struct snapraid_file* file)
{
unsigned i;
@ -534,7 +534,7 @@ struct snapraid_disk* disk_alloc(const char* name, const char* dir, uint64_t dev
tommy_hashdyn_init(&disk->linkset);
tommy_list_init(&disk->dirlist);
tommy_hashdyn_init(&disk->dirset);
tommy_array_init(&disk->blockarr);
tommy_arrayblk_init(&disk->blockarr);
return disk;
}
@ -549,7 +549,7 @@ void disk_free(struct snapraid_disk* disk)
tommy_hashdyn_done(&disk->linkset);
tommy_list_foreach(&disk->dirlist, (tommy_foreach_func*)dir_free);
tommy_hashdyn_done(&disk->dirset);
tommy_array_done(&disk->blockarr);
tommy_arrayblk_done(&disk->blockarr);
free(disk);
}
@ -567,13 +567,13 @@ int disk_is_empty(struct snapraid_disk* disk, block_off_t blockmax)
return 0;
/* limit the search to the size of the disk */
if (blockmax > tommy_array_size(&disk->blockarr))
blockmax = tommy_array_size(&disk->blockarr);
if (blockmax > tommy_arrayblk_size(&disk->blockarr))
blockmax = tommy_arrayblk_size(&disk->blockarr);
/* checks all the blocks to search for deleted ones */
/* this search is slow, but it's done only if no file is present */
for(i=0;i<blockmax;++i) {
struct snapraid_block* block = tommy_array_get(&disk->blockarr, i);
struct snapraid_block* block = tommy_arrayblk_get(&disk->blockarr, i);
unsigned block_state = block_state_get(block);
switch (block_state) {

22
elem.h
View file

@ -24,6 +24,8 @@
#include "tommyhashdyn.h"
#include "tommyarray.h"
#include "tommyarrayof.h"
#include "tommyarrayblk.h"
#include "tommyarrayblkof.h"
/****************************************************************************/
/* snapraid */
@ -282,7 +284,7 @@ struct snapraid_disk {
*
* Each element points to a snapraid_block structure, or it's BLOCK_EMPTY.
*/
tommy_array blockarr;
tommy_arrayblk blockarr;
/**
* List of all the snapraid_file for the disk.
@ -386,7 +388,7 @@ int filter_existence(int filter_missing, const char* dir, const char* sub);
* Filter a file if bad.
* Return !=0 if the file is correct and it should be excluded.
*/
int filter_correctness(int filter_error, tommy_arrayof* infoarr, struct snapraid_file* file);
int filter_correctness(int filter_error, tommy_arrayblkof* infoarr, struct snapraid_file* file);
/**
* Filters a dir using a list of filters.
@ -724,8 +726,8 @@ void disk_free(struct snapraid_disk* disk);
*/
static inline struct snapraid_block* disk_block_get(struct snapraid_disk* disk, block_off_t pos)
{
if (pos < tommy_array_size(&disk->blockarr))
return tommy_array_get(&disk->blockarr, pos);
if (pos < tommy_arrayblk_size(&disk->blockarr))
return tommy_arrayblk_get(&disk->blockarr, pos);
else
return BLOCK_EMPTY;
}
@ -811,25 +813,25 @@ static inline snapraid_info info_set_rehash(snapraid_info info)
* Sets the info at the specified position.
* The position is allocated if not yet done.
*/
static inline void info_set(tommy_arrayof* array, unsigned pos, snapraid_info info)
static inline void info_set(tommy_arrayblkof* array, unsigned pos, snapraid_info info)
{
tommy_arrayof_grow(array, pos + 1);
tommy_arrayblkof_grow(array, pos + 1);
memcpy(tommy_arrayof_ref(array, pos), &info, sizeof(snapraid_info));
memcpy(tommy_arrayblkof_ref(array, pos), &info, sizeof(snapraid_info));
}
/**
* Gets the info at the specified position.
* For not allocated position, 0 is returned.
*/
static inline snapraid_info info_get(tommy_arrayof* array, unsigned pos)
static inline snapraid_info info_get(tommy_arrayblkof* array, unsigned pos)
{
snapraid_info info;
if (pos >= tommy_arrayof_size(array))
if (pos >= tommy_arrayblkof_size(array))
return 0;
memcpy(&info, tommy_arrayof_ref(array, pos), sizeof(snapraid_info));
memcpy(&info, tommy_arrayblkof_ref(array, pos), sizeof(snapraid_info));
return info;
}

View file

@ -35,12 +35,12 @@ block_off_t parity_size(struct snapraid_state* state)
struct snapraid_disk* disk = i->data;
/* start from the declared size */
block_off_t block = tommy_array_size(&disk->blockarr);
block_off_t block = tommy_arrayblk_size(&disk->blockarr);
/* decrease the block until an used one */
/* we don't stop at deleted blocks, because we want to have them cleared */
/* if they are at the end of the parity */
while (block > parity_block && !block_has_file(tommy_array_get(&disk->blockarr, block - 1)))
while (block > parity_block && !block_has_file(tommy_arrayblk_get(&disk->blockarr, block - 1)))
--block;
/* get the highest value */

14
scan.c
View file

@ -201,7 +201,7 @@ static void scan_file_remove(struct snapraid_state* state, struct snapraid_disk*
tommy_list_insert_tail(&disk->deletedlist, &deleted->node, deleted);
/* set the deleted block in the block array */
tommy_array_set(&disk->blockarr, block_pos, &deleted->block);
tommy_arrayblk_set(&disk->blockarr, block_pos, &deleted->block);
}
/* remove the file from the file containers */
@ -229,25 +229,25 @@ static void scan_file_insert(struct snapraid_state* state, struct snapraid_disk*
/* allocate the blocks of the file */
block_pos = disk->first_free_block;
block_max = tommy_array_size(&disk->blockarr);
block_max = tommy_arrayblk_size(&disk->blockarr);
for(i=0;i<file->blockmax;++i) {
struct snapraid_block* block;
/* find a free block */
while (block_pos < block_max && block_has_file(tommy_array_get(&disk->blockarr, block_pos)))
while (block_pos < block_max && block_has_file(tommy_arrayblk_get(&disk->blockarr, block_pos)))
++block_pos;
/* if not found, allocate a new one */
if (block_pos == block_max) {
++block_max;
tommy_array_grow(&disk->blockarr, block_max);
tommy_arrayblk_grow(&disk->blockarr, block_max);
}
/* set the position */
file->blockvec[i].parity_pos = block_pos;
/* block to overwrite */
block = tommy_array_get(&disk->blockarr, block_pos);
block = tommy_arrayblk_get(&disk->blockarr, block_pos);
/* if the block is an empty one */
if (block == BLOCK_EMPTY) {
@ -260,7 +260,7 @@ static void scan_file_insert(struct snapraid_state* state, struct snapraid_disk*
}
/* store in the disk map, after invalidating all the other blocks */
tommy_array_set(&disk->blockarr, block_pos, &file->blockvec[i]);
tommy_arrayblk_set(&disk->blockarr, block_pos, &file->blockvec[i]);
}
if (file->blockmax) {
/* set the new free position, but only if allocated something */
@ -1122,7 +1122,5 @@ void state_scan(struct snapraid_state* state, int output)
}
tommy_list_foreach(&scanlist, (tommy_foreach_func*)free);
printf("Using %u MiB of memory.\n", (unsigned)(malloc_counter() / 1024 / 1024));
}

View file

@ -79,6 +79,15 @@ void usage(void)
printf(" " SWITCH_GETOPT_LONG("-V, --version ", "-V") " Version\n");
}
void memory(struct snapraid_state* state)
{
if (state->opt.gui) {
fprintf(stdlog, "memory:used:%"PRIu64"\n", (uint64_t)malloc_counter());
} else {
printf("Using %u MiB of memory.\n", (unsigned)(malloc_counter() / 1024 / 1024));
}
}
#define OPT_TEST_SKIP_SELF 256
#define OPT_TEST_KILL_AFTER_SYNC 257
#define OPT_TEST_EXPECT_UNRECOVERABLE 258
@ -564,11 +573,15 @@ int main(int argc, char* argv[])
state_read(&state);
state_scan(&state, 1);
memory(&state);
} else if (operation == OPERATION_SYNC) {
state_read(&state);
state_scan(&state, 0);
memory(&state);
/* intercept Ctrl+C */
signal(SIGINT, &signal_handler);
@ -614,6 +627,8 @@ int main(int argc, char* argv[])
/* apply the command line filter */
state_filter(&state, &filterlist_file, &filterlist_disk, filter_missing, filter_error);
memory(&state);
/* intercept Ctrl+C */
signal(SIGINT, &signal_handler);
@ -632,6 +647,8 @@ int main(int argc, char* argv[])
} else if (operation == OPERATION_SCRUB) {
state_read(&state);
memory(&state);
/* intercept Ctrl+C */
signal(SIGINT, &signal_handler);
@ -648,9 +665,13 @@ int main(int argc, char* argv[])
state_read(&state);
state_write(&state);
memory(&state);
} else if (operation == OPERATION_STATUS) {
state_read(&state);
memory(&state);
state_status(&state);
} else if (operation == OPERATION_DUP) {
state_read(&state);
@ -669,6 +690,8 @@ int main(int argc, char* argv[])
/* apply the command line filter */
state_filter(&state, &filterlist_file, &filterlist_disk, filter_missing, filter_error);
memory(&state);
/* intercept Ctrl+C */
signal(SIGINT, &signal_handler);

20
state.c
View file

@ -75,7 +75,7 @@ void state_init(struct snapraid_state* state)
tommy_list_init(&state->importlist);
tommy_hashdyn_init(&state->importset);
tommy_hashdyn_init(&state->previmportset);
tommy_arrayof_init(&state->infoarr, sizeof(snapraid_info));
tommy_arrayblkof_init(&state->infoarr, sizeof(snapraid_info));
}
void state_done(struct snapraid_state* state)
@ -87,7 +87,7 @@ void state_done(struct snapraid_state* state)
tommy_list_foreach(&state->importlist, (tommy_foreach_func*)import_file_free);
tommy_hashdyn_done(&state->importset);
tommy_hashdyn_done(&state->previmportset);
tommy_arrayof_done(&state->infoarr);
tommy_arrayblkof_done(&state->infoarr);
}
/**
@ -1003,8 +1003,8 @@ static void state_read_text(struct snapraid_state* state, const char* path, STRE
}
/* insert the block in the block array */
tommy_array_grow(&disk->blockarr, v_pos + 1);
tommy_array_set(&disk->blockarr, v_pos, block);
tommy_arrayblk_grow(&disk->blockarr, v_pos + 1);
tommy_arrayblk_set(&disk->blockarr, v_pos, block);
/* check for termination of the block list */
++blockidx;
@ -1136,8 +1136,8 @@ static void state_read_text(struct snapraid_state* state, const char* path, STRE
}
/* insert the block in the block array */
tommy_array_grow(&disk->blockarr, v_pos + 1);
tommy_array_set(&disk->blockarr, v_pos, &deleted->block);
tommy_arrayblk_grow(&disk->blockarr, v_pos + 1);
tommy_arrayblk_set(&disk->blockarr, v_pos, &deleted->block);
/* if the block has an hash */
if (block_has_any_hash(&deleted->block)) {
@ -2186,7 +2186,7 @@ static void state_read_binary(struct snapraid_state* state, const char* path, ST
}
/* grow the array */
tommy_array_grow(&disk->blockarr, v_pos + v_count);
tommy_arrayblk_grow(&disk->blockarr, v_pos + v_count);
/* fill the blocks in the run */
while (v_count) {
@ -2234,7 +2234,7 @@ static void state_read_binary(struct snapraid_state* state, const char* path, ST
}
/* insert the block in the block array */
tommy_array_set(&disk->blockarr, v_pos, block);
tommy_arrayblk_set(&disk->blockarr, v_pos, block);
/* stat */
++count_block;
@ -2369,7 +2369,7 @@ static void state_read_binary(struct snapraid_state* state, const char* path, ST
switch (c) {
case 'o' :
/* grow the array */
tommy_array_grow(&disk->blockarr, v_pos + v_count);
tommy_arrayblk_grow(&disk->blockarr, v_pos + v_count);
/* if it's a run of deleted blocks */
while (v_count) {
@ -2399,7 +2399,7 @@ static void state_read_binary(struct snapraid_state* state, const char* path, ST
}
/* insert the block in the block array */
tommy_array_set(&disk->blockarr, v_pos, &deleted->block);
tommy_arrayblk_set(&disk->blockarr, v_pos, &deleted->block);
/* go to next block */
++v_pos;

View file

@ -103,7 +103,7 @@ struct snapraid_state {
tommy_list importlist; /**< List of import file. */
tommy_hashdyn importset; /**< Hashtable by hash of all the import blocks. */
tommy_hashdyn previmportset; /**< Hashtable by prevhash of all the import blocks. Valid only if we are in a rehash state. */
tommy_arrayof infoarr; /**< Block information array. */
tommy_arrayblkof infoarr; /**< Block information array. */
block_off_t loaded_blockmax; /**< Previous size of the parity file, computed from the loaded state. */
time_t progress_start; /**< Start of processing for progress visualization. */
time_t progress_last; /**< Last update of progress visualization. */

4
sync.c
View file

@ -150,7 +150,7 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
/* if the block is deleted */
if (block_state_get(block) == BLOCK_STATE_DELETED) {
/* set it to empty */
tommy_array_set(&handle[j].disk->blockarr, i, BLOCK_EMPTY);
tommy_arrayblk_set(&handle[j].disk->blockarr, i, BLOCK_EMPTY);
/* mark the state as needing write */
state->need_write = 1;
@ -328,7 +328,7 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
/* if it's a deleted block */
if (block_state_get(block) == BLOCK_STATE_DELETED) {
/* the parity is now updated without this block, so it's now empty */
tommy_array_set(&handle[j].disk->blockarr, i, BLOCK_EMPTY);
tommy_arrayblk_set(&handle[j].disk->blockarr, i, BLOCK_EMPTY);
continue;
}

View file

@ -29,4 +29,6 @@
#include "tommyhashdyn.c"
#include "tommyarray.c"
#include "tommyarrayof.c"
#include "tommyarrayblk.c"
#include "tommyarrayblkof.c"

View file

@ -26,13 +26,15 @@
*/
/** \file
* Dynamic array.
* Dynamic array based on segments of exponential growing size.
*
* This array is able to grow dynamically upon request.
*
* The resize involve an allocation of a new array segment, without reallocating
* the already allocated memory, and then not increasing the heap fragmentation.
*
* Allocated segments grow in size exponentially.
*
* This means that the address of the allocated segments never change.
*/

83
tommyarrayblk.c Normal file
View file

@ -0,0 +1,83 @@
/*
* Copyright 2013 Andrea Mazzoleni. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY ANDREA MAZZOLENI AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL ANDREA MAZZOLENI OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "tommyarrayblk.h"
#include <string.h> /* for memset */
/******************************************************************************/
/* array */
void tommy_arrayblk_init(tommy_arrayblk* array)
{
tommy_array_init(&array->block);
array->size = 0;
}
void tommy_arrayblk_done(tommy_arrayblk* array)
{
unsigned i;
for(i=0;i<tommy_array_size(&array->block);++i)
tommy_free(tommy_array_get(&array->block, i));
tommy_array_done(&array->block);
}
void tommy_arrayblk_grow(tommy_arrayblk* array, unsigned size)
{
unsigned block_max = (size + TOMMY_ARRAYBLK_SIZE - 1) / TOMMY_ARRAYBLK_SIZE;
unsigned block_mac = tommy_array_size(&array->block);
if (block_mac < block_max) {
/* grow the block array */
tommy_array_grow(&array->block, block_max);
/* allocate new blocks */
while (block_mac < block_max) {
void* ptr = tommy_malloc(TOMMY_ARRAYBLK_SIZE * sizeof(void*));
/* initializes it with zeros */
memset(ptr, 0, TOMMY_ARRAYBLK_SIZE * sizeof(void*));
/* set the new block */
tommy_array_set(&array->block, block_mac, ptr);
++block_mac;
}
}
if (array->size < size)
array->size = size;
}
tommy_size_t tommy_arrayblk_memory_usage(tommy_arrayblk* array)
{
return tommy_array_memory_usage(&array->block) + tommy_array_size(&array->block) * TOMMY_ARRAYBLK_SIZE * sizeof(void*);
}

143
tommyarrayblk.h Normal file
View file

@ -0,0 +1,143 @@
/*
* Copyright 2013 Andrea Mazzoleni. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY ANDREA MAZZOLENI AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL ANDREA MAZZOLENI OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/** \file
* Dynamic array based on blocks of fixed sizes.
*
* This array is able to grow dynamically upon request.
*
* The resize involve an allocation of a new array block, without reallocating
* the already allocated memory, and then not increasing the heap fragmentation.
*
* Allocated blocks are always of the same size.
*
* This means that the address of the allocated blocks never change.
*/
#ifndef __TOMMYARRAYBLK_H
#define __TOMMYARRAYBLK_H
#include "tommytypes.h"
#include "tommyarray.h"
#include <assert.h> /* for assert */
/******************************************************************************/
/* array */
/**
* Elements for each block.
*/
#define TOMMY_ARRAYBLK_SIZE (64 * 1024)
/**
* Array.
*/
typedef struct tommy_arrayblk_struct {
tommy_array block; /**< Array of blocks. */
unsigned size; /**< Currently allocated and initialized size. */
} tommy_arrayblk;
/**
* Initializes the array.
*/
void tommy_arrayblk_init(tommy_arrayblk* array);
/**
* Deinitializes the array.
*/
void tommy_arrayblk_done(tommy_arrayblk* array);
/**
* Grow the size up to the specified value.
* All the new elements in the array are initialized with the 0 value.
*/
void tommy_arrayblk_grow(tommy_arrayblk* array, unsigned size);
/**
* Gets a reference of the element at the specified position.
* You must be sure that space for this position is already
* allocated calling tommy_arrayblk_grow().
*/
tommy_inline void** tommy_arrayblk_ref(tommy_arrayblk* array, unsigned pos)
{
void** ptr;
assert(pos < array->size);
ptr = tommy_array_get(&array->block, pos / TOMMY_ARRAYBLK_SIZE);
return &ptr[pos % TOMMY_ARRAYBLK_SIZE];
}
/**
* Sets the element at the specified position.
* You must be sure that space for this position is already
* allocated calling tommy_arrayblk_grow().
*/
tommy_inline void tommy_arrayblk_set(tommy_arrayblk* array, unsigned pos, void* element)
{
*tommy_arrayblk_ref(array, pos) = element;
}
/**
* Gets the element at the specified position.
* You must be sure that space for this position is already
* allocated calling tommy_arrayblk_grow().
*/
tommy_inline void* tommy_arrayblk_get(tommy_arrayblk* array, unsigned pos)
{
return *tommy_arrayblk_ref(array, pos);
}
/**
* Grows and inserts a new element at the end of the array.
*/
tommy_inline void tommy_arrayblk_insert(tommy_arrayblk* array, void* element)
{
unsigned pos = array->size;
tommy_arrayblk_grow(array, pos + 1);
tommy_arrayblk_set(array, pos, element);
}
/**
* Gets the initialized size of the array.
*/
tommy_inline unsigned tommy_arrayblk_size(tommy_arrayblk* array)
{
return array->size;
}
/**
* Gets the size of allocated memory.
*/
tommy_size_t tommy_arrayblk_memory_usage(tommy_arrayblk* array);
#endif

83
tommyarrayblkof.c Normal file
View file

@ -0,0 +1,83 @@
/*
* Copyright 2013 Andrea Mazzoleni. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY ANDREA MAZZOLENI AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL ANDREA MAZZOLENI OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "tommyarrayblkof.h"
#include <string.h> /* for memset */
/******************************************************************************/
/* array */
void tommy_arrayblkof_init(tommy_arrayblkof* array, unsigned element_size)
{
tommy_array_init(&array->block);
array->element_size = element_size;
array->size = 0;
}
void tommy_arrayblkof_done(tommy_arrayblkof* array)
{
unsigned i;
for(i=0;i<tommy_array_size(&array->block);++i)
tommy_free(tommy_array_get(&array->block, i));
tommy_array_done(&array->block);
}
void tommy_arrayblkof_grow(tommy_arrayblkof* array, unsigned size)
{
unsigned block_max = (size + TOMMY_ARRAYBLK_SIZE - 1) / TOMMY_ARRAYBLK_SIZE;
unsigned block_mac = tommy_array_size(&array->block);
if (block_mac < block_max) {
/* grow the block array */
tommy_array_grow(&array->block, block_max);
/* allocate new blocks */
while (block_mac < block_max) {
void* ptr = tommy_malloc(TOMMY_ARRAYBLK_SIZE * array->element_size);
/* initializes it with zeros */
memset(ptr, 0, TOMMY_ARRAYBLK_SIZE * array->element_size);
/* set the new block */
tommy_array_set(&array->block, block_mac, ptr);
++block_mac;
}
}
if (array->size < size)
array->size = size;
}
tommy_size_t tommy_arrayblkof_memory_usage(tommy_arrayblkof* array)
{
return tommy_array_memory_usage(&array->block) + tommy_array_size(&array->block) * TOMMY_ARRAYBLKOF_SIZE * array->element_size;
}

108
tommyarrayblkof.h Normal file
View file

@ -0,0 +1,108 @@
/*
* Copyright 2013 Andrea Mazzoleni. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY ANDREA MAZZOLENI AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL ANDREA MAZZOLENI OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/** \file
* Dynamic array based on blocks of fixed sizes.
*
* This array is able to grow dynamically upon request.
*
* This is very similar at ::tommy_arrayblk, but it allows to store elements of any
* size and not just pointers.
*/
#ifndef __TOMMYARRAYBLKOF_H
#define __TOMMYARRAYBLKOF_H
#include "tommytypes.h"
#include "tommyarray.h"
#include <assert.h> /* for assert */
/******************************************************************************/
/* array */
/**
* Elements for each block.
*/
#define TOMMY_ARRAYBLKOF_SIZE (64 * 1024)
/**
* Array.
*/
typedef struct tommy_arrayblkof_struct {
tommy_array block; /**< Array of blocks. */
unsigned element_size; /**< Size of the stored element in bytes. */
unsigned size; /**< Currently allocated and initialized size. */
} tommy_arrayblkof;
/**
* Initializes the array.
*/
void tommy_arrayblkof_init(tommy_arrayblkof* array, unsigned element_size);
/**
* Deinitializes the array.
*/
void tommy_arrayblkof_done(tommy_arrayblkof* array);
/**
* Grow the size up to the specified value.
* All the new elements in the array are initialized with the 0 value.
*/
void tommy_arrayblkof_grow(tommy_arrayblkof* array, unsigned size);
/**
* Gets a reference of the element at the specified position.
* You must be sure that space for this position is already
* allocated calling tommy_arrayblkof_grow().
*/
tommy_inline void* tommy_arrayblkof_ref(tommy_arrayblkof* array, unsigned pos)
{
unsigned char* base;
assert(pos < array->size);
base = tommy_array_get(&array->block, pos / TOMMY_ARRAYBLKOF_SIZE);
return base + (pos % TOMMY_ARRAYBLKOF_SIZE) * array->element_size;
}
/**
* Gets the initialized size of the array.
*/
tommy_inline unsigned tommy_arrayblkof_size(tommy_arrayblkof* array)
{
return array->size;
}
/**
* Gets the size of allocated memory.
*/
tommy_size_t tommy_arrayblkof_memory_usage(tommy_arrayblkof* array);
#endif

View file

@ -1,5 +1,5 @@
/*
* Copyright 2011 Andrea Mazzoleni. All rights reserved.
* Copyright 2013 Andrea Mazzoleni. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions

View file

@ -26,17 +26,12 @@
*/
/** \file
* Dynamic array.
* Dynamic array based on segments of exponential growing size.
*
* This array is able to grow dynamically upon request.
*
* This is very similar at ::tommy_array, but it allows to store elements of any
* size and not just pointers.
*
* The resize involve an allocation of a new array segment, without reallocating
* the already allocated memory, and then not increasing the heap fragmentation.
*
* This means that the address of the allocated segments never change.
*/
#ifndef __TOMMYARRAYOF_H