1 Commits

Author SHA1 Message Date
Maxim Tikhonov
2e8fba7836 Imported Debian patch 11.2-0tikhonov1~xenial 2019-01-07 14:06:17 +01:00
42 changed files with 1094 additions and 408 deletions

View File

@@ -1 +1 @@
11.3
11.2

10
HISTORY
View File

@@ -1,16 +1,6 @@
SnapRAID HISTORY
================
11.3 2018/11
============
* Fixed handing of Linux devices that have multiple slaves. This affects
the smart/list/devices/down commands [Valentin Hilbig].
* The 'list' command in verbose mode prints the full nanosecond
timestamp precision.
* After writing content files also sync their directory.
* Fix a invalid time computation that could result in future scrub dates.
Such dates are fixed automatically at the next scrub or sync.
11.2 2017/12
============
* Fixed recognition of NTFS hardlinks. They behave differently than

16
TODO
View File

@@ -17,18 +17,6 @@ Not checked disks should be allowed to be missing.
* Add an option to ignore subsecond timestamp.
Like when you copy data to a filesystem with less timestamp precision.
* Use threads to scan all the disks at the same time.
- After 7.0 Windows changes it seems fast enough even
with a mono thread implementation with 100.0000 files.
+ But if you have millions of files, it could take minutes.
* Support more parity levels
It can be done with a generic computation function, using
intrinsic for SSSE3 and AVX instructions.
It would be intersting to compare performance with the hand-written
assembler functions. Eventially we can convert them to use intrinsic also.
https://sourceforge.net/p/snapraid/discussion/1677233/thread/9dbd7581/
* Extend haspdeep to support the SnapRAID hash :
https://github.com/jessek/hashdeep/
https://sourceforge.net/p/snapraid/discussion/1677233/thread/90b0e9b2/?limit=25
@@ -234,6 +222,10 @@ and if we manage to keep it in the cache, we should save time.
- We now hash first the faster disks, and this could
reduce performance as we'll have to wait for all disks.
* Use threads to scan all the disks at the same time.
- After 7.0 Windows changes it seems fast enough even
with a mono thread implementation.
* Enable storing of creation time NTFS, crtime/birth time EXT4.
But see: http://unix.stackexchange.com/questions/50177/birth-is-empty-on-ext4
coreutils stat has an example, but it doesn't work in Linux (see lib/stat-time.h)

View File

@@ -889,7 +889,7 @@ void io_init(struct snapraid_io* io, struct snapraid_state* state,
allocated += state->block_size * buffer_max;
}
msg_progress("Using %u MiB of memory for %u cached blocks.\n", (unsigned)(allocated / MEBI), io->io_max);
msg_progress("Using %u MiB of memory for %u blocks of IO cache.\n", (unsigned)(allocated / MEBI), io->io_max);
if (parity_writer) {
io->reader_max = handle_max;

View File

@@ -74,7 +74,7 @@ void state_list(struct snapraid_state* state)
if (tm) {
printf("%04u/%02u/%02u %02u:%02u", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min);
if (msg_level >= MSG_VERBOSE)
printf(":%02u.%09u", tm->tm_sec, file->mtime_nsec);
printf(":%02u.%03u", tm->tm_sec, file->mtime_nsec / 1000000);
printf(" ");
}
printf("%s\n", fmt_term(disk, file->sub, esc_buffer));
@@ -105,7 +105,7 @@ void state_list(struct snapraid_state* state)
printf("%12s ", type);
printf(" ");
if (msg_level >= MSG_VERBOSE)
printf(" ");
printf(" ");
printf("%s -> %s\n", fmt_term(disk, slink->sub, esc_buffer), fmt_term(disk, slink->linkto, esc_buffer_alt));
}
}

View File

@@ -694,7 +694,6 @@ static void windows_errno(DWORD error)
errno = EPERM;
break;
case ERROR_IO_DEVICE : /* in ReadFile() and WriteFile() */
case ERROR_CRC : /* in ReadFile() */
errno = EIO;
break;
default :

View File

@@ -41,7 +41,6 @@ void test(void)
s = sopen_multi_write(STREAM_MAX);
for (i = 0; i < STREAM_MAX; ++i) {
snprintf(file, sizeof(file), "stream%u.bin", i);
remove(file);
if (sopen_multi_file(s, i, file) != 0) {
/* LCOV_EXCL_START */
exit(EXIT_FAILURE);

View File

@@ -136,29 +136,25 @@ void MurmurHash3_x86_128(const void* data, size_t size, const uint8_t* seed, voi
uint32_t k4 = 0;
switch (size_remainder) {
case 15 : k4 ^= (uint32_t)tail[14] << 16; /* fallthrough */
case 14 : k4 ^= (uint32_t)tail[13] << 8; /* fallthrough */
case 13 : k4 ^= (uint32_t)tail[12] << 0; /* fallthrough */
case 15 : k4 ^= (uint32_t)tail[14] << 16;
case 14 : k4 ^= (uint32_t)tail[13] << 8;
case 13 : k4 ^= (uint32_t)tail[12] << 0;
k4 *= c4; k4 = util_rotl32(k4, 18); k4 *= c1; h4 ^= k4;
/* fallthrough */
case 12 : k3 ^= (uint32_t)tail[11] << 24; /* fallthrough */
case 11 : k3 ^= (uint32_t)tail[10] << 16; /* fallthrough */
case 10 : k3 ^= (uint32_t)tail[ 9] << 8; /* fallthrough */
case 9 : k3 ^= (uint32_t)tail[ 8] << 0; /* fallthrough */
case 12 : k3 ^= (uint32_t)tail[11] << 24;
case 11 : k3 ^= (uint32_t)tail[10] << 16;
case 10 : k3 ^= (uint32_t)tail[ 9] << 8;
case 9 : k3 ^= (uint32_t)tail[ 8] << 0;
k3 *= c3; k3 = util_rotl32(k3, 17); k3 *= c4; h3 ^= k3;
/* fallthrough */
case 8 : k2 ^= (uint32_t)tail[ 7] << 24; /* fallthrough */
case 7 : k2 ^= (uint32_t)tail[ 6] << 16; /* fallthrough */
case 6 : k2 ^= (uint32_t)tail[ 5] << 8; /* fallthrough */
case 5 : k2 ^= (uint32_t)tail[ 4] << 0; /* fallthrough */
case 8 : k2 ^= (uint32_t)tail[ 7] << 24;
case 7 : k2 ^= (uint32_t)tail[ 6] << 16;
case 6 : k2 ^= (uint32_t)tail[ 5] << 8;
case 5 : k2 ^= (uint32_t)tail[ 4] << 0;
k2 *= c2; k2 = util_rotl32(k2, 16); k2 *= c3; h2 ^= k2;
/* fallthrough */
case 4 : k1 ^= (uint32_t)tail[ 3] << 24; /* fallthrough */
case 3 : k1 ^= (uint32_t)tail[ 2] << 16; /* fallthrough */
case 2 : k1 ^= (uint32_t)tail[ 1] << 8; /* fallthrough */
case 1 : k1 ^= (uint32_t)tail[ 0] << 0; /* fallthrough */
case 4 : k1 ^= (uint32_t)tail[ 3] << 24;
case 3 : k1 ^= (uint32_t)tail[ 2] << 16;
case 2 : k1 ^= (uint32_t)tail[ 1] << 8;
case 1 : k1 ^= (uint32_t)tail[ 0] << 0;
k1 *= c1; k1 = util_rotl32(k1, 15); k1 *= c2; h1 ^= k1;
/* fallthrough */
}
}

View File

@@ -87,7 +87,7 @@ void memory(void)
log_tag("memory:link:%" PRIu64 "\n", (uint64_t)(sizeof(struct snapraid_link)));
log_tag("memory:dir:%" PRIu64 "\n", (uint64_t)(sizeof(struct snapraid_dir)));
msg_progress("Using %u MiB of memory for the file-system.\n", (unsigned)(malloc_counter_get() / MEBI));
msg_progress("Using %u MiB of memory for the FileSystem.\n", (unsigned)(malloc_counter_get() / MEBI));
}
void test(int argc, char* argv[])
@@ -1091,7 +1091,7 @@ int main(int argc, char* argv[])
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
/* fallthrough */
/* follow */
case OPERATION_SPINUP :
case OPERATION_SPINDOWN :
if (!tommy_list_empty(&filterlist_file)) {

View File

@@ -2872,7 +2872,6 @@ struct state_write_thread_context {
/* input */
block_off_t blockmax;
time_t info_oldest;
time_t info_now;
int info_has_rehash;
STREAM* f;
/* output */
@@ -2889,7 +2888,6 @@ static void* state_write_thread(void* arg)
struct snapraid_state* state = context->state;
block_off_t blockmax = context->blockmax;
time_t info_oldest = context->info_oldest;
time_t info_now = context->info_now;
int info_has_rehash = context->info_has_rehash;
STREAM* f = context->f;
uint32_t crc;
@@ -3280,18 +3278,7 @@ static void* state_write_thread(void* arg)
flag |= 8;
sputb32(flag, f);
t = info_get_time(info);
/* truncate any time that is in the future */
if (t > info_now)
t = info_now;
/* the oldest info is computed only on required blocks, so it may not be the absolute oldest */
if (t < info_oldest)
t = 0;
else
t -= info_oldest;
t = info_get_time(info) - info_oldest;
sputb32(t, f);
} else {
/* write a special 0 flag to mark missing info */
@@ -3366,7 +3353,6 @@ static void state_write_content(struct snapraid_state* state, uint32_t* out_crc)
tommy_node* i;
block_off_t blockmax;
time_t info_oldest;
time_t info_now;
int info_has_rehash;
int mapping_idx;
block_off_t idx;
@@ -3385,7 +3371,6 @@ static void state_write_content(struct snapraid_state* state, uint32_t* out_crc)
/* clear the info for unused blocks */
/* and get some other info */
info_oldest = 0; /* oldest time in info */
info_now = time(0); /* get the present time */
info_has_rehash = 0; /* if there is a rehash info */
for (idx = 0; idx < blockmax; ++idx) {
/* if the position is used */
@@ -3449,21 +3434,10 @@ static void state_write_content(struct snapraid_state* state, uint32_t* out_crc)
msg_progress("Saving state to %s...\n", content->content);
pathprint(tmp, sizeof(tmp), "%s.tmp", content->content);
/* ensure to delete a previous stale file */
if (remove(tmp) != 0) {
if (errno != ENOENT) {
/* LCOV_EXCL_START */
log_fatal("Error removing the stale content file '%s'. %s.\n", tmp, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
f = sopen_write(tmp);
if (f == 0) {
/* LCOV_EXCL_START */
log_fatal("Error opening the temporary content file '%s'. %s.\n", tmp, strerror(errno));
log_fatal("Error opening the content file '%s'. %s.\n", tmp, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
@@ -3476,7 +3450,6 @@ static void state_write_content(struct snapraid_state* state, uint32_t* out_crc)
context->state = state;
context->blockmax = blockmax;
context->info_oldest = info_oldest;
context->info_now = info_now;
context->info_has_rehash = info_has_rehash;
context->f = f;
@@ -3589,24 +3562,12 @@ static void state_write_content(struct snapraid_state* state, uint32_t* out_crc)
struct snapraid_content* content = i->data;
char tmp[PATH_MAX];
pathprint(tmp, sizeof(tmp), "%s.tmp", content->content);
/* ensure to delete a previous stale file */
if (remove(tmp) != 0) {
if (errno != ENOENT) {
/* LCOV_EXCL_START */
log_fatal("Error removing the stale content file '%s'. %s.\n", tmp, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
if (sopen_multi_file(f, k, tmp) != 0) {
/* LCOV_EXCL_START */
log_fatal("Error opening the temporary content file '%s'. %s.\n", tmp, strerror(errno));
log_fatal("Error opening the content file '%s'. %s.\n", tmp, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
++k;
i = i->next;
}
@@ -3618,7 +3579,6 @@ static void state_write_content(struct snapraid_state* state, uint32_t* out_crc)
context->state = state;
context->blockmax = blockmax;
context->info_oldest = info_oldest;
context->info_now = info_now;
context->info_has_rehash = info_has_rehash;
context->f = f;
@@ -3891,10 +3851,11 @@ static void state_verify_content(struct snapraid_state* state, uint32_t crc)
msg_progress("Verifying %s...\n", content->content);
pathprint(tmp, sizeof(tmp), "%s.tmp", content->content);
f = sopen_read(tmp);
if (f == 0) {
/* LCOV_EXCL_START */
log_fatal("Error reopening the temporary content file '%s'. %s.\n", tmp, strerror(errno));
log_fatal("Error reopening the content file '%s'. %s.\n", tmp, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
@@ -3963,59 +3924,6 @@ static void state_rename_content(struct snapraid_state* state)
{
tommy_node* i;
#if defined(_linux) /* this sequence is linux specific */
i = tommy_list_head(&state->contentlist);
while (i) {
struct snapraid_content* content = i->data;
char tmp[PATH_MAX];
char dir[PATH_MAX];
char* slash;
int handle;
pathcpy(dir, sizeof(dir), content->content);
slash = strrchr(tmp, '/');
if (slash)
*slash = 0;
else
pathcpy(dir, sizeof(dir), ".");
/* open the directory to get the handle */
handle = open(dir, O_RDONLY | O_DIRECTORY);
if (handle < 0) {
/* LCOV_EXCL_START */
log_fatal("Error opening the directory '%s'. %s.\n", dir, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
/* now rename the just written copy with the correct name */
pathprint(tmp, sizeof(tmp), "%s.tmp", content->content);
if (rename(tmp, content->content) != 0) {
/* LCOV_EXCL_START */
log_fatal("Error renaming the content file '%s' to '%s'. %s.\n", tmp, content->content, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
/* sync the directory */
if (fsync(handle) != 0) {
/* LCOV_EXCL_START */
log_fatal("Error syncing the directory '%s'. %s.\n", dir, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (close(handle) != 0) {
/* LCOV_EXCL_START */
log_fatal("Error closing the directory '%s'. %s.\n", dir, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
i = i->next;
}
#else
i = tommy_list_head(&state->contentlist);
while (i) {
struct snapraid_content* content = i->data;
@@ -4032,7 +3940,6 @@ static void state_rename_content(struct snapraid_state* state)
i = i->next;
}
#endif
}
void state_write(struct snapraid_state* state)

View File

@@ -29,10 +29,6 @@
unsigned day_ago(time_t ref, time_t now)
{
/* in case some dates is in the future */
if (now < ref)
return 0;
return (now - ref) / (24 * 3600);
}
@@ -462,10 +458,6 @@ int state_status(struct snapraid_state* state)
printf("\n");
if (newest > now) {
printf("WARNING! You have scrub dates in the future! The next sync/scrub will truncate them!\n");
}
if (unsynced_blocks) {
printf("WARNING! The array is NOT fully synced.\n");
printf("You have a sync in progress at %u%%.\n", (blockmax - unsynced_blocks) * 100 / blockmax);

View File

@@ -112,8 +112,7 @@ int sopen_multi_file(STREAM* s, unsigned i, const char* file)
pathcpy(s->handle[i].path, sizeof(s->handle[i].path), file);
/* O_EXCL to be resilent ensure to always create a new file and not use a stale link to the original file */
f = open(file, O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_SEQUENTIAL, 0600);
f = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_SEQUENTIAL, 0600);
if (f == -1) {
/* LCOV_EXCL_START */
return -1;

View File

@@ -299,8 +299,6 @@ void pathslash(char* dst, size_t size);
/**
* Cut everything after the latest slash.
*
* If the string doesn't contain any slash, it returns the empty string.
*/
void pathcut(char* dst);

View File

@@ -1536,7 +1536,7 @@ int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t
data_off_t out_size;
parity_size(&parity_handle[l], &out_size);
parity_overflow(state, out_size);
log_fatal("WARNING! Without an usable %s file, it isn't possible to sync.\n", lev_name(l));
log_fatal("WARNING! Without an unsable %s file, it isn't possible to sync.\n", lev_name(l));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}

View File

@@ -917,20 +917,18 @@ static int devtree(const char* name, const char* custom, dev_t device, devinfo_t
while ((dd = readdir(d)) != 0) {
if (dd->d_name[0] != '.') {
dev_t subdev;
/* for each slave, expand the full potential tree */
pathprint(path, sizeof(path), "/sys/dev/block/%u:%u/slaves/%s/dev", major(device), minor(device), dd->d_name);
subdev = devread(path);
if (!subdev) {
device = devread(path);
if (!device) {
/* LCOV_EXCL_START */
closedir(d);
return -1;
/* LCOV_EXCL_STOP */
}
if (devtree(name, custom, subdev, parent, list) != 0) {
if (devtree(name, custom, device, parent, list) != 0) {
/* LCOV_EXCL_START */
closedir(d);
return -1;
@@ -1074,8 +1072,8 @@ static int devscan(tommy_list* list)
#if HAVE_LINUX_DEVICE
static int devsmart(dev_t device, const char* name, const char* custom, uint64_t* smart, char* serial, char* vendor, char* model)
{
char cmd[PATH_MAX + 64];
char file[PATH_MAX];
char cmd[128];
char file[128];
FILE* f;
int ret;
@@ -1088,7 +1086,7 @@ static int devsmart(dev_t device, const char* name, const char* custom, uint64_t
/* if there is a custom command */
if (custom[0]) {
char option[PATH_MAX];
char option[128];
snprintf(option, sizeof(option), custom, file);
snprintf(cmd, sizeof(cmd), "smartctl -a %s", option);
} else {
@@ -1142,8 +1140,8 @@ static int devsmart(dev_t device, const char* name, const char* custom, uint64_t
#if HAVE_LINUX_DEVICE
static int devdown(dev_t device, const char* name, const char* custom)
{
char cmd[PATH_MAX + 64];
char file[PATH_MAX];
char cmd[128];
char file[128];
FILE* f;
int ret;
@@ -1156,7 +1154,7 @@ static int devdown(dev_t device, const char* name, const char* custom)
/* if there is a custom command */
if (custom[0]) {
char option[PATH_MAX];
char option[128];
snprintf(option, sizeof(option), custom, file);
snprintf(cmd, sizeof(cmd), "smartctl -s standby,now %s", option);
} else {

20
configure vendored
View File

@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for snapraid 11.3.
# Generated by GNU Autoconf 2.69 for snapraid 11.2.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -577,8 +577,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='snapraid'
PACKAGE_TARNAME='snapraid'
PACKAGE_VERSION='11.3'
PACKAGE_STRING='snapraid 11.3'
PACKAGE_VERSION='11.2'
PACKAGE_STRING='snapraid 11.2'
PACKAGE_BUGREPORT=''
PACKAGE_URL='http://www.snapraid.it'
@@ -1304,7 +1304,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures snapraid 11.3 to adapt to many kinds of systems.
\`configure' configures snapraid 11.2 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1374,7 +1374,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of snapraid 11.3:";;
short | recursive ) echo "Configuration of snapraid 11.2:";;
esac
cat <<\_ACEOF
@@ -1496,7 +1496,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
snapraid configure 11.3
snapraid configure 11.2
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2102,7 +2102,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by snapraid $as_me 11.3, which was
It was created by snapraid $as_me 11.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -2965,7 +2965,7 @@ fi
# Define the identity of the package.
PACKAGE='snapraid'
VERSION='11.3'
VERSION='11.2'
cat >>confdefs.h <<_ACEOF
@@ -7373,7 +7373,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by snapraid $as_me 11.3, which was
This file was extended by snapraid $as_me 11.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -7436,7 +7436,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
snapraid config.status 11.3
snapraid config.status 11.2
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"

686
debian/changelog vendored Normal file
View File

@@ -0,0 +1,686 @@
snapraid (11.2-0tikhonov1~xenial) xenial; urgency=medium
[11.2 2017/12]
* Fixed recognition of NTFS hardlinks. They behave differently than
standard Unix hardlinks and this could result in SnapRAID reporting
internal inconsistency errors for detecting links to the same file
with different metadata attributes.
* More efficient 'pool' command that updates only the links
that need to be updated. This ensures that no change is
done, avoiding to trigger a directory rescan of other programs.
* In Linux use by default the advise "discard" mode instead of "flush".
This avoids to swap-out the other process memory, leaving the system
more responsive.
* Changed the fallocate() use to work better with Btrfs with parity disks.
* Changed the --test-io-stats screen to print the file name in process
for each disk.
-- Maxim Tikhonov <flaterichd@gmail.com> Wed, 18 Jul 2018 19:44:46 +0400
snapraid (11.1-0tikhonov1~trusty) trusty; urgency=medium
[11.1 2017/05]
* Fixed the check command to correctly ignore errors on unused parity.
This was broken in version 9.0.
* Allow increasing the number of parity splits of existing parity.
* Fixed quoting when printing in Linux. This fixes the UTF-8 screen
output. Windows version was not affected.
* Fixed recognition of 'hashsize' in the configuration file.
The previous incorrect 'hash_size' is still supported for backward
compatibility.
* Fixed building in platforms that don't provide major/minor definitions
in sys/types.h.
* When creating 'pool' symbolic links, set their time as the linked files.
* Added support for the Windows 10 symbolic link unprivileged creation,
using SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE.
* Windows binaries built with gcc 4.9.4 using the MXE cross compiler at
commit ae56efa2b23a793b0146508bfef33027cdb09fd2 with targets
i686-w64-mingw32 and x86_64-w64-mingw32 and optimization -O2.
-- Maxim Tikhonov <flaterichd@gmail.com> Mon, 28 Aug 2017 12:41:29 +0400
snapraid (11.0-0tikhonov1~trusty) trusty; urgency=medium
[11.0 2016/11]
* Added support for splitting the parity in multiple partitions. You
can now specify multiple files for a single parity. As soon a file
cannot grow anymore, the next one starts growing.
In the configuration file, just put more files in the same 'parity'
line, separated by , (comma).
Note that if this feature is used, the saved content file won't be
read by older SnapRAID versions.
In Windows, 256 MB are left free in each disk to avoid the warning
about full disks.
* Added a new 'hashsize' configuration option. It could be useful in
systems with low memory, to reduce the memory usage.
Note that if this feature is used, the saved content file won't be
read by older SnapRAID versions.
* In Linux added the missing support for Btrfs file-systems. Note that
to have full support you need also the 'libblkid' library, otherwise
you won't get the UUIDs.
* In screen messages don't print the disk directory in file path. You
can control the format with the test option:
--test-fmt file|disk|path.
* In Windows allows to use the escape char '^' to handle file patterns
containing real characters matching the globbing '*?[]' ones. In Unix
it was already possible to do the same escaping with '\'.
* Added a new -R, --force-realloc option to reallocate all the
parity information keeping the precomputed hash.
This is the previous -F, --force-full that instead now maintains the
same parity organization and just recomputes it.
* Added test options for selecting the file advise mode to use:
--test-io-advise-none for standard mode
--test-io-advise-sequential advise sequential access (Linux/Windows)
--test-io-advise-flush flush cache after every operation (Linux)
--test-io-advise-flush-window flush cache every 8 MB (Linux)
--test-io-advise-discard discard cache after every operation (Linux)
--test-io-advise-discard-window discard cache every 8 MB (Linux)
--test-io-advise-direct use direct/unbuffered mode (Linux/Windows)
The new default mode is 'flush' in Linux (before it was 'sequential'),
and 'sequential' in Windows (like before).
* For Seagate SMR (Shingled Magnetic Recording) ignore the SMART
attribute Command_Timeout 188 as not reliable.
* Fixed running in Windows platforms that miss the RtlGenRandom()
function.
* Added the --test-io-cache=1 option to disable the multi-thread IO
mode.
-- Maxim Tikhonov <flaterichd@gmail.com> Thu, 01 Dec 2016 16:25:21 +0400
snapraid (10.0-0tikhonov1~trusty) trusty; urgency=medium
[ 10.0 2016/02 ]
* Boosts the speed of the 'sync' and 'scrub' commands with a new
multi-thread implementation. It uses one thread for each disk,
dedicated exclusively to read-ahead data and parity and to
write-behind parity. This maximizes the data throughput keeping
disks always busy.
You can control the number of blocks to cache with the option
--test-io-cache=NUMBER, where the number is between 3 and 128.
The default is 8 MiB of blocks.
You can show run-time stats during the process with the
--test-io-stats option. You will see a graph with the number of
cached blocks, and a graph with the wait time percentage for all the
disks and computations.
* The -h, --pre-hash command, saves the content file only after having
verified all the hashes. This allows recovering of moved files in
case a silent error is found during the hash verification check.
* Allows to use the -d, --filter-disk option in the 'up' and 'down'
commands.
* Allows to run the 'smart' command without a configuration file.
In such case it operates on all the disks of the machine.
* In the configuration file 'data' is now a synonymous of 'disk'.
* Adds the 'touch' command intended to arbitrarily set all the zero
sub-second timestamps. This improves the SnapRAID capabilities to
identify files. The 'status' command recommends to run 'touch' if
required.
* Restores the functionality of the -D, --force-device option when used
to workaround the use of the same disk for two logical data drives
when running the 'fix' command.
* Uses a correct shell quoting in the example commands that involve
files.
* The minimum Windows version supported is now Windows Vista. This is
required to use the native Windows thread support for the new
multi-thread implementation. If you need to run on Windows XP, you
have to stick on SnapRAID 9.x.
-- Maxim Tikhonov <flaterichd@gmail.com> Sat, 05 Mar 2016 17:44:53 +0400
snapraid (9.3-0tikhonov1~trusty) trusty; urgency=medium
[ 9.3 2016/01 ]
* Fixes an invalid assumption in the copy detection mechanism that
could result in an internal inconsistency, and with the impossibility
to run the 'sync' and 'diff' commands.
This was triggered by a very specific pattern of identical files.
At least three of them, with one already in the parity, and at a
higher disk number than the others that should be instead new ones.
This had no bad effect, if not preventing the 'sync' command to run.
A workaround was to just run 'sync' one time with the -N,
--force-nocopy option to disable the copy detection.
* Restored the -O2 optimization option for Windows binaries, as -Og has
a too big performance penality.
[ 9.2 2016/01 ]
* Fixes support for symlinks pointing to an empty target. Before they
were only partially supported, and their presence could result in a
content file not readable.
This also disables multi-thread content write, as this was the issue
we tried to detect with this feature, and it doesn't provide a
performance advantage. Content verification is instead still multi
thread.
* Autorename disks using the matching UUID. To rename a disk you can
now change directly the name in the configuration file, and run a
'sync' command.
* Improves the physical offset ordering for the Btrfs file-system,
correctly detecting files that have not a physical offset, for
whatever reason.
* Adds UUID support to Btrfs file-systems. It's present only if the
'libblkid' development library is available on the system.
Usually this requires to install the libblkid-dev or libblkid-devel
package.
* Added a new --no-warnings option to disable some repetitive warnings
that could be annoying to power users.
* Improves the error reporting, printing a complete stack trace, that
can be used to track down bugs more easily.
For this reason the Windows binaries are now built with optimization
option -Og, instead than -O2.
-- Maxim Tikhonov <flaterichd@gmail.com> Tue, 02 Feb 2016 12:59:13 +0400
snapraid (9.1-0tikhonov1~trusty) trusty; urgency=medium
[ 9.1 2015/11 ]
* Fixes a bug when reading a content file with a deleted entry bigger
than 4 GB. This was a regression introduced in version 9.0 that
could result in the impossibility to read a valid content file,
after a deletion of a file bigger than 4 GB in the array.
If this happened to you, just upgrading to 9.1 fixes the issue, and
it allows you to continue to work.
Note that this bug only prevented to run 9.0, but your data was still
protected and could have been recovered using the versions 8.1 or 9.1.
* In Windows disables the file zero check requiring the --force-zero
option. This check is intended for possible case using ext3/4 in Linux,
and there is no evidence that in Windows it's possible at all.
* Windows binaries built with gcc 4.9.3 using the MXE cross compiler at
commit 62bcdbee56e87c81f1faa105b8777a5879d4e2e with targets
i686-w64-mingw32 and x86_64-w64-mingw32 and optimization -O2.
[ 9.0 2015/11 ]
* Fixes an invalid assumption that could happen when using the
-e, --filter-error option with "fix" or "check".
This was triggered by a very specific pattern of fragmented files
and bad blocks combination, not so easy to reproduce.
This had no bad effect, if not preventing the command to run.
* Drastically reduces the memory usage. For each block, it now
uses 17 bytes of memory, instead of the previous 28 bytes
(for 32 bit) or 36 bytes (for 64 bit).
This could result is a memory saving of up the 50%.
* The -p, --plan option (old --percentage) can be used to
define a scrub plan: "new", "bad" and "full".
The "new" plan scrubs all the new synced blocks not yet scrubbed.
This allows to verify as early as possible that the written
parity during sync is really correct. You can use the "status"
command to show the amount blocks not yet scrubbed.
The "bad" plan scrubs only bad blocks.
The "full" plan scrubs all blocks.
* The graph in the "status" command now show scrubbed blocks
with '*', and synced, but not yet scrubbed, blocks with 'o'.
Note that when upgrading from a previous version, all blocks
are assumed scrubbed the first time.
* Content files are now written asyncronously from different
threads to avoid the unfortunate condition that a memory
error affects all of them in the same way.
After writing, they are read again to verify their CRC.
This is done to ensure thay they are really OK, even in the
case of the worst possible silent errors.
* Extends the -D, --force-device option to ignore more
erroneous conditions in the 'fix' command, like unaccessible
disks, or disks sharing the same physical device.
* Extends the -d, --filter-disk option to allow to filter also
by parity disk.
* Extends the -h, --pre-hash option to also verify moved and
copied files into the array before running a 'sync'.
* Updates 'best' RAID functions for recent Atom CPUs.
* Validates filters specifications rejecting relative paths.
-- Maxim Tikhonov <flaterichd@gmail.com> Tue, 01 Dec 2015 23:50:52 +0400
snapraid (8.1-0tikhonov1~trusty) trusty; urgency=medium
[ 8.1 2015/05 ]
* Fix build issues in generic Unix platforms, including Mac OS X.
* The "diff" command returns with error code 2 if a "sync" is
required, to differentiate with the generic error code 1.
* Reduced the effect of SMART attribute 193 on the failure
probability to avoid some false positive reports.
-- Maxim Tikhonov <flaterichd@gmail.com> Sun, 17 May 2015 23:29:11 +0400
snapraid (8.0-0tikhonov1~trusty) trusty; urgency=medium
[ 8.0 2015/04 ]
* Allows "sync" and "scrub" to continue after the first bunch of disk
errors. Blocks with errors are marked as bad, and you can fix them
with the "fix -e" command.
The fix is expected to force the disk firmware to reallocate the
bad sector, likely fixing the problem.
You can control the number of allowed errors with the new
-L, --error-limit option. The default is 100.
* The -e, --filter-error option doesn't write anymore fixes to
unsynced files. This helps in case you are running it on a not
synced array, removing the risk to revert some files to an old state.
* The -e, --filter-error option is now optimal and reads only the
minimal amount of data necessary to fix the errors.
* The "diff" command returns with an error code if a "sync" is
required.
* Adds new "smart" command to print a SMART report of the array.
* Adds new "up" and "down" commands to spin up and down the disks of
the array.
* Adds new "devices" command to print the devices associations in
the array.
* Changes the log handling. If no log file is specified, all the
warnings and not fatal errors messages goes to stderr. If a log file
is specified, only fatal error messages are printed on the screen.
You can control the amount of informative messages on stdout with
the -q, --quiet and -v, --verbose options, that can be specified
multiple times to be more quiet or verbose.
* In the "status" command the "Wasted" column now shows a negative
number for the amount of space that you can still waste without
filling up the parity.
* In the "status" and others commands we now use GB instead of GiB,
when referring to disk space.
* Renames the -s and -t options to -S and -B as they are intended to
be manual only operations.
* Windows binary built with gcc 4.8.1 using the MXE cross compiler 2.23,
with targets i686-w64-mingw32 and x86_64-w64-mingw32. Before the x86
target was i686-pc-mingw32.
-- Maxim Tikhonov <flaterichd@gmail.com> Thu, 30 Apr 2015 23:01:55 +0400
snapraid (7.1-0tikhonov1~precise) precise; urgency=medium
[ 7.1 2015/01 ]
* In 'scrub' and 'sync' detects and reports Input/Output errors
separately from generic file system errors.
* In 'diff' doesn't print the "add" entry if a "copy" one is already
printed.
* Fixes build with old compilers in the x64 platforms [Leigh Phillips].
* Fixes out-of-dir builds [Christoph Junghans].
-- Maxim Tikhonov <flaterichd@gmail.com> Wed, 11 Mar 2015 20:36:58 +0400
snapraid (7.0-0tikhonov2~precise) precise; urgency=medium
[ 7.0 2014/11 ]
* In 'check' and 'fix' the array is scanned to find any moved files
that could be used to recover missing data. Files are identified by
timestamp, and then they are recognized also if moved to a different
disk. Note that even if there are false positive they are identified
checking the hash, so they have not effect, besides making the
process a little slower. To disable this new behaviour you can use
the -N, --force-nocopy option.
* The -i, --import command now identifies files by timestamp making it
very fast in importing directories.
* More detailed 'status' report with single disk stats and free space
available.
* A lot faster directory listing for Windows.
* Adds AVX2 support to improve parity generation speed.
* Prints the time spent waiting for each disk also in 'scrub'.
* The CPU usage, speed and ETA estimations are now based on the last 100
seconds rather than from the start.
* Keeps track of the UUID of the parity disks to check them before
operating.
* Windows binary built with gcc 4.8.1 using the MXE cross compiler 2.23.
-- Maxim Tikhonov <flaterichd@gmail.com> Thu, 27 Nov 2014 00:36:59 +0400
snapraid (6.2-0tikhonov1~precise) precise; urgency=low
[ 6.2 2014/5 ]
* Fixed the regression test when run as root.
* Added a new heuristic to detect file copies. Now a file is assumed
to be a copy if name, size and nanosecond timestamp are matching,
but if the nanosecond part of the timestamp is 0, it requires
the full path matching and not only the name.
* Added the -N, --force-nocopy option to disable completely
the copy detection. SnapRAID also suggests to use this option
in the error message of a data mismatch if likely caused by the
copy detection.
-- Maxim Tikhonov <flaterichd@gmail.com> Wed, 16 Jul 2014 01:01:09 +0400
snapraid (6.1-0tikhonov1~precise) precise; urgency=high
[ 6.1 2014/4 ]
* Fix build and regression test in Mac OS X.
-- Maxim Tikhonov <flaterichd@gmail.com> Tue, 22 Apr 2014 00:22:07 +0400
snapraid (6.0-0tikhonov1~precise) precise; urgency=low
[ 6.0 2014/3 ]
* In "sync", even if a silent error is found, continue to update
the parity if it's possible to correct the error.
Note that the block will be marked bad, and the data
will be fixed only at the next "fix -e" call.
But any new data added will be protected if you are using
enough parity to fix both the silent error and at least
another potential error.
* Detect copied files from one disk to another and reuse the already
computed hash information to validate them in "sync".
Files are assumed copied if they matches the name, size and timestamp.
* For "sync", added a new -h, --pre-hash option to run a preliminary
hashing step for all the new files to ensure to detect silent errors
caused by the heavy machine usage of the parity computation.
* In "fix", if a previous fixing attempt was made resulting in a
.unrecoverable file, uses this file as starting point for the
new attempt.
* In the log file name allows the use of the '>>', %D, %T modifiers
to select append mode, and to insert the date and time in the name.
* The options -p, --percentage and -o, --older-than now keep their
default value even if the other one is specified.
* Moved the .lock file in the same dir of the first specified content
file. This avoid to spin-up the parity disks in all commands.
* The "diff", "list", "dup", "status" and "pool" commands don't access
anymore the parity disks that can now stay powered down.
* The default configuration file in Windows is now searched in the same
directory where the snapraid.exe file resides.
* New source code organization. The RAID engine is now
an external component usable also in other projects.
-- Maxim Tikhonov <flaterichd@gmail.com> Fri, 11 Apr 2014 02:43:52 +0400
snapraid (5.3-0tikhonov1~precise) precise; urgency=low
[ 5.3 2014/3 ]
* Don't warn about UUID changed if it's for an empty disk.
* Fixed the number of blocks that scrub has to process when
selecting a high percentage of the array.
* Removed duplicate recovery attempts in synced state.
[ 5.2 2013/12 ]
* If a disk changes UUID, automatically disable the inode
recognition, because this is likely a new filesystem with
all the inodes reassigned, and we don't want to risk a false
positive when searching for inode/timestamp/size.
* Allow to run a fix command with disks that doesn't need to be
fixed mounted as read-only.
* After a failed sync, always reallocates new files with a not
yet computed parity to ensure to minimize the parity usage,
if some other file is deleted in the meantime.
* Doesn't count empty dirs as files in the diff counters.
* Added a new "share" configuration option to allow to share
in the network the pool directory also in Windows.
* Fixed build problems in OpenBSD due the old assembler.
* Fixed build problems in platforms different than x86.
[ 5.1 2013/12 ]
* Fixed a potential crash if a file is deleted during a "sync/scrub".
This is a problem introduced in version 5.0 due new logging.
If happened to you to have a crash in sync, you don't need to
take any special action, just run "sync" again.
* Restored the functionality of -C, --gen-conf command.
* Prints the files with duplicate physical offset if the
-v, --verbose option is specified.
-- Maxim Tikhonov <flaterichd@gmail.com> Tue, 11 Mar 2014 18:56:46 +0400
snapraid (5.0-0tikhonov1~precise) precise; urgency=low
* New upstream release.
[ Upstream changelog 4.4 ]
* Added support for up to six levels of parity.
* Added a specific and faster triple parity format for CPUs that
don't support SSSE3 instructions like ARM and AMD Phenom, Athlon
and Opteron.
* Faster RAID5 and RAID6 implementation for ARM 64 bit CPUs.
* If a silent error is found during a "sync" command, directly marks
the block as bad like in "scrub", without stopping the the "sync"
process.
* Sort files by inode when listing the directory. This improves
the scanning performance.
* For files with changes only in some blocks, updates the parity
only for blocks that really are changed.
This improves the performance in sync for modified files.
* Added a new "list" command to see the stored list of files.
* Removed the detailed list of errors from the screen output.
To get it you must explicitely use the -l, --log option.
It's now too detailed for the screen, because it contains a lot
of info.
* Changed the output format of some commands to make it similar
at the new "list" one.
* Reduced memory usage removing some unnecessary allocations.
* Added a memory test on the memory buffers used in sync/scrub/check/fix
before using them.
-- Maxim Tikhonov <flaterichd@gmail.com> Mon, 25 Nov 2013 15:58:37 +0400
snapraid (4.4-0tikhonov1~precise) precise; urgency=low
* New upstream release.
[ Upstream changelog 4.4 ]
* Relaxed the check about small parity files, to allow to recover after a
failed sync before resizing the parity files.
[ Upstream changelog 4.3 ]
* Fixed the scrub command with the -p0 option. Now it really scrubs only the
blocks marked as bad and not the full array.
[ Upstream changelog 4.2 ]
* Fixed the wrong warning about physical offsets not supported caused by files
not having a real offset because too small. For example, in NTFS it's possible
to store such files in the MFT. It's just a cosmetic change, and not a
functional one.
* Remove unexpected 'Restore' entries in the diff output when dealing with
filesystem without persistent inodes like NTFS in Linux.
* Added support for filenames containing newlines. This happens in Mac OS X.
[ Upstream changelog 4.1 ]
* If the underline filesystem doesn't support the FIEMAP command, automatically
fallback to use FIBMAP for sorting files.
* 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. Just in case that you lose everything, except
the content file.
* At the end of sync/scrub/check/fix prints "Everything OK" if no error was found.
This should make clear that everything is really OK.
[ Upstream changelog 4.0 ]
* New 'scrub' command to periodically check the oldest blocks for silent
errors without the need to scan the whole array.
* New 'status' command to check the fragmentation, the last check time
distribution, and the silent error status of the array.
* Added the new Spooky hash. It's faster in 64 bit architectures. To
convert you can use the new 'rehash' command.
* Changed to a binary content file to improve speed and reduce size.
* Removed the --find-by-name, -N option. Now it always searches
by name if a file is not found searching by inode, automatically
reassigning inodes in restored files without needing to sync
again the file. This happens only if the file has the same path, size
and timestamp at nanosecond precision.
* Added a hash seed to make harder intentional collision attacks.
* When inserting files for the first time, sort them by their physical
address to improve read performance.
* Optimized the cache use for the all the RAID computations.
This improves a lot the RAID performance.
* Better selection of the RAID6 implementation for different CPUs.
* Added RAID5/RAID6 mmx and sse2 implementations with unrolling by 4.
They are a little faster than the previous unroll by 2.
* Added a lock file to avoid multiple running instances on the same array.
The file is named as parity file adding the .lock extension.
There is also the undocumented --test-skip-lock to avoid to check it.
* Automatically ignores, with warning, mount points inside the array
directory tree.
* Changes the 'dup' output format to include the size of each duplicate file.
-- Maxim Tikhonov <flaterichd@gmail.com> Fri, 01 Nov 2013 00:04:46 +0400
snapraid (3.2-0tikhonov1~precise) precise; urgency=low
* New upstream release.
[ Upstream changelog 3.2 ]
* Fix a directory creation problem in Windows when the "disk" option points to
the root directory of a drive. Now SnapRAID won't complain about the
inability to create such directory.
If you encouter this problem when trying to recover your data, just upgrade
to this version, and you'll be able to complete the recovering process.
No need to upgrade for platforms different than Windows.
[ Upstream changelog 3.1 ]
* Direct use of Windows API for disk access to improve error reporting.
* If the 'fix' process is aborted, it removes all the new files partially
recovered, to allow to reuse again the '-m, --filter-missing' flag.
* In Windows don't exclude anymore system files. Only system directories are
excluded.
* In Windows applies filters in case insensitive way.
* The Windows binaries are now built with gcc 4.7.2.
* Reduced memory occupation for hardlinks and directories.
* In 'dup' don't list file with 0 size.
-- Maxim Tikhonov <flaterichd@gmail.com> Fri, 09 Aug 2013 17:43:06 +0400
snapraid (3.0-0tikhonov1~precise) precise; urgency=low
* New upstream release.
[ Upstream changelog ]
* Added pooling support with the new 'pool' command. It creates a virtual
view of the array using symbolic links pointing to the original files.
* Added a new -m, --filter-missing option that allow to undelete files,
without checking/fixing the others.
* Added a new -i, --import option to automatically import deleted files
when fixing.
* Added a new -l, --log option to save to disk the detailed log.
* Added support also for hardlinks and empty directories.
* Added support to save symlinks to files in Windows. Note that only the
symlink is saved and not the linked file.
Symlinks to dirs and junctions are still not supported in Windows.
* Files without read permission generate an error instead of a warning.
You now must explicitely exclude them in the configuration file with
exclusion rules.
* In 'check' and 'fix', if verbose is enabled, prints the result for each
processed file.
* Added an UUID check to detect when a disk is replaced, and to prevent
unwanted disk swaps.
-- Maxim Tikhonov <flaterichd@gmail.com> Wed, 03 Apr 2013 13:01:53 +0400
snapraid (2.1-0tikhonov1~precise) precise; urgency=low
* New upstream release.
[ Upstream changelog ]
* Checks for wrong empty fields in the configuration file.
* Filter rules for files are not anymore applied to directories.
-- Maxim Tikhonov <flaterichd@gmail.com> Mon, 28 Jan 2013 02:10:28 +0400
snapraid (2.0-0tikhonov1~precise) precise; urgency=low
* New upstream release.
[ Upstream changelog ]
* Added a new -a option to make the 'check' command to only check file hashes
without checking the parity data.
* Added a new -d option to filter by disk name.
* The file modification time is now saved using nanosecond precision.
This allows to restore the exact modification time in 'fix'.
The new 'content' files written with this version are not backward
compatible, but it's still possible to read the old 'content' format.
* Fixed hard-links automatic exclusion. All the hardlinks after the first one
are now correctly ignored.
* If it isn't possible to grow a parity file, prints the list of files
outside the maximum size allocated.
* Autosave isn't triggered if we are near the end of the 'sync' process.
* Before starting a 'sync', we wait for two seconds, to workaround the FAT
limitation of having two seconds modification time precision.
This a safe measure to be 100% sure to always detect file changes.
* Always fill the memory after allocating it to avoid the OOM (Out Of Memory)
killer in Linux.
* Fixed compilation in Solaris/OpenIndiana for lacking both futimes()
and futimens().
* Now 'sync' ensures that the parity files are not too small to contain the
just loaded data.
* Removed the '-H,--filter-nohidden' option. It doesn't make sense to
have it as command line option.
You must use the 'nohidden' option in the configuration file.
* When opening files in read-only mode, also specify the noatime flag,
to avoid to update the file access time.
* Exclude rules for files are now also applied to directories.
This allows to excludes some file/directory without the need to call
the stat() function on them.
* The -N, --find-by-name option also ignores the nanosecond part of
timestamps to work with copy programs not supporting nanoseconds.
* Fixed deduplicated files handling in Windows Server 2012.
* Removed MD5 support.
-- Maxim Tikhonov <flaterichd@gmail.com> Thu, 06 Dec 2012 00:38:20 +0400
snapraid (1.13-0tikhonov1~precise) precise; urgency=low
* New upstream release.
[ Upstream changelog ]
* Fixed a Segmentation Fault when checking/fixing if there are three or
more errors in a specific block.
-- Maxim Tikhonov <flaterichd@gmail.com> Mon, 05 Nov 2012 16:31:22 +0400
snapraid (1.12-0tikhonov1~precise) precise; urgency=low
* New upstream release 1.12.
[ Upstream changelog ]
* Fixed file renaming in Windows during a 'fix' command. This is only a
Windows issue, no reason to upgrade for other platforms.
-- Maxim Tikhonov <flaterichd@gmail.com> Thu, 20 Sep 2012 13:13:40 +0400
snapraid (1.11-0tikhonov1~precise) precise; urgency=high
* New upstream release 1.11.
[ Upstream changelog ]
* Fixed again directories inclusion. Exclusion rules for directories were ignored.
-- Maxim Tikhonov <flaterichd@gmail.com> Mon, 09 Jul 2012 19:06:01 +0400
snapraid (1.10-0tikhonov1~precise) precise; urgency=low
* New upstream release 1.10.
[ Upstream changelog ]
* Fixed directory inclusion, in case the last rule is an "include" one.
* Fixed very long paths in Windows. We now always use the special '\\?' prefix to remove the 260 chars limitation.
* If a file is excluded, it prints explicitely which attribute caused the exclusion.
* Automatically excludes also the temporary copy of content file, the one with the ".tmp" extension.
* Avoid the Windows system to go in automatic sleep mode when running.
-- Maxim Tikhonov <flaterichd@gmail.com> Sun, 01 Jul 2012 21:43:16 +0400
snapraid (1.9-0tikhonov1~precise) precise; urgency=low
* New upstream release 1.9.
[ Upstream changelog ]
* Implemented a more sophisticated recovering in case a harddisk failure happens during a 'sync'
command. When using RAID6 it improves the chances of recovering data after an aborted 'sync'.
* Fixed the count of new files.
* Added a new 'autosave' configuration option to save the intermediate 'sync' state.
* Supported filesystems with read requests returning less data than requested.
* In Windows ensures that the disk serial number is not zero.
-- Maxim Tikhonov <flaterichd@gmail.com> Tue, 10 Apr 2012 17:31:51 +0400
snapraid (1.8-0tikhonov1~oneiric) oneiric; urgency=low
* New upstream release 1.8.
Upstream changelog:
* Added a new "dup" command to find all the duplicate files.
* Added a new option "--filter-nohidden" to exclude hidden files.
* Faster and parallel writing of content files.
* The example configuration files now put the content files in the data
disks instead than in the parity disks.
* Added a checksum at the content file to ensure its integrity.
* Using fallocate() instead posix_fallocate() to avoid the very slow
posix_fallocate() fallback of writing the whole file.
-- Maxim Tikhonov <flaterichd@gmail.com> Sat, 17 Mar 2012 19:15:07 +0400
snapraid (1.7-0tikhonov2~oneiric) oneiric; urgency=low
* Fixed example snapraid.conf.
-- Maxim Tikhonov <flaterichd@gmail.com> Sat, 24 Dec 2011 01:28:39 +0400
snapraid (1.7-0tikhonov1~oneiric) oneiric; urgency=low
* Initial release.
-- Maxim Tikhonov <flaterichd@gmail.com> Thu, 22 Dec 2011 19:46:17 +0400

1
debian/compat vendored Normal file
View File

@@ -0,0 +1 @@
7

28
debian/control vendored Normal file
View File

@@ -0,0 +1,28 @@
Source: snapraid
Section: utils
Priority: extra
Maintainer: Maxim Tikhonov <flaterichd@gmail.com>
Build-Depends: debhelper (>= 7.0.0), autotools-dev
Standards-Version: 3.9.2
Homepage: http://snapraid.sourceforge.net/
Package: snapraid
Architecture: any
Depends:
${shlibs:Depends},
${misc:Depends}
Description: SnapRAID is a backup program for disk arrays.
SnapRAID is a backup program for disk arrays.
.
SnapRAID stores redundancy information in the disk array, and it allows recovering from up to two disk failures.
.
SnapRAID is mainly targeted for a home media center, where you have a lot of big files that rarely change.
.
Beside the ability to recover from disk failures, the other features of SnapRAID are:
- You can start using SnapRAID with already filled disks.
- The disks of the array can have different sizes.
- You can add more disks at any time.
- If you accidentally delete some files in a disk, you can recover them.
- If more than two disks fail, you lose the data only on the failed disks. All the data in the other disks is safe.
- It doesn't lock-in your data. You can stop using SnapRAID at any time without the need to reformat or move data.
- All your data is hashed to ensure data integrity and avoid silent corruption.

40
debian/copyright vendored Normal file
View File

@@ -0,0 +1,40 @@
Format: http://dep.debian.net/deps/dep5
Name: snapraid
Upstream-Name: snapraid
Maintainer: Maxim Tikhonov <flaterichd@gmail.com>
Source: http://sourceforge.net/projects/snapraid/files/
Files: *
Copyright: 2011 Andrea Mazzoleni <amadvance@users.sourceforge.net>
License: GPL-3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
On Debian systems, the complete text of the GNU General
Public License can be found in `/usr/share/common-licenses/GPL-3'.
Files: debian/*
Copyright: 2011 Maxim Tikhonov <flaterichd@gmail.com>
License: GPL-2+
This package is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
.
This package is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
.
On Debian systems, the complete text of the GNU General
Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".

9
debian/docs vendored Normal file
View File

@@ -0,0 +1,9 @@
AUTHORS
CHECK
COPYING
HISTORY
INSTALL
README
TODO
snapraid.conf.example
snapraid.txt

2
debian/install vendored Normal file
View File

@@ -0,0 +1,2 @@
debian/snapraid.conf etc
snapraid usr/bin

1
debian/manpage.1 vendored Symbolic link
View File

@@ -0,0 +1 @@
../snapraid.1

21
debian/rules vendored Executable file
View File

@@ -0,0 +1,21 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
#
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
#
# Modified to make a template file for a multi-binary package with separated
# build-arch and build-indep targets by Bill Allombert 2001
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
# This has to be exported to make some magic below work.
export DH_OPTIONS
%:
dh $@

86
debian/snapraid.conf vendored Normal file
View File

@@ -0,0 +1,86 @@
# Example configuration for snapraid
# Defines the file to use as parity storage
# It must NOT be in a data disk
# Format: "parity FILE_PATH"
parity /mnt/diskp/snapraid.parity
# Defines the files to use as additional parity storage.
# If specified, they enable the multiple failures protection
# from two to six level of parity.
# To enable, uncomment one parity file for each level of extra
# protection required. Start from 2-parity, and follow in order.
# It must NOT be in a data disk
# Format: "X-parity FILE_PATH"
#2-parity /mnt/diskq/snapraid.2-parity
#3-parity /mnt/diskr/snapraid.3-parity
#4-parity /mnt/disks/snapraid.4-parity
#5-parity /mnt/diskt/snapraid.5-parity
#6-parity /mnt/disku/snapraid.6-parity
# Defines the files to use as content list
# You can use multiple specification to store more copies
# You must have least one copy for each parity file plus one. Some more don't hurt
# They can be in the disks used for data, parity or boot,
# but each file must be in a different disk
# Format: "content FILE_PATH"
content /var/snapraid.content
content /mnt/disk1/snapraid.content
content /mnt/disk2/snapraid.content
# Defines the data disks to use
# The name and mount point association is relevant for parity, do not change it
# WARNING: Adding here your /home, /var or /tmp disks is NOT a good idea!
# SnapRAID is better suited for files that rarely changes!
# Format: "disk DISK_NAME DISK_MOUNT_POINT"
data d1 /mnt/disk1/
data d2 /mnt/disk2/
data d3 /mnt/disk3/
# Excludes hidden files and directories (uncomment to enable).
#nohidden
# Defines files and directories to exclude
# Remember that all the paths are relative at the mount points
# Format: "exclude FILE"
# Format: "exclude DIR/"
# Format: "exclude /PATH/FILE"
# Format: "exclude /PATH/DIR/"
exclude *.unrecoverable
exclude /tmp/
exclude /lost+found/
# Defines the block size in kibi bytes (1024 bytes) (uncomment to enable).
# Default value is 256 -> 256 kibi bytes -> 262144 bytes
# Format: "blocksize SIZE_IN_KiB"
#blocksize 256
# Automatically save the state when syncing after the specified amount
# of GB processed (uncomment to enable).
# This option is useful to avoid to restart from scratch long 'sync'
# commands interrupted by a machine crash.
# It also improves the recovering if a disk break during a 'sync'.
# Default value is 0, meaning disabled.
# Format: "autosave SIZE_IN_GB"
#autosave 500
# Defines the pooling directory where the virtual view of the disk
# array is created using the "pool" command (uncomment to enable).
# The files are not really copied here, but just linked using
# symbolic links.
# This directory must be outside the array.
# Format: "pool DIR"
#pool /pool
# Defines a custom smartctl command to obtain the SMART attributes
# for each disk. This may be required for RAID controllers and for
# some USB disk that cannot be autodetected.
# In the specified options, the "%s" string is replaced by the device name.
# Refers at the smartmontools documentation about the possible options:
# RAID -> https://www.smartmontools.org/wiki/Supported_RAID-Controllers
# USB -> https://www.smartmontools.org/wiki/Supported_USB-Devices
#smartctl d1 -d sat %s
#smartctl d2 -d usbjmicron %s
#smartctl parity -d areca,1/1 /dev/sg0
#smartctl 2-parity -d areca,2/1 /dev/sg0

1
debian/source/format vendored Normal file
View File

@@ -0,0 +1 @@
3.0 (quilt)

2
debian/watch vendored Normal file
View File

@@ -0,0 +1,2 @@
version=3
https://github.com/amadvance/snapraid/releases .*snapraid-([0-9.]*\.[0-9.]*).tar.gz

View File

@@ -647,7 +647,7 @@ and ignore all the parity data.
This command will take a long time, but if you are not paranoid,
you can skip it.
.SS STEP 4 \-> Sync
Run the \[dq]sync\[dq] command to re\-synchronize the array with the new disk.
Run the \[dq]sync\[dq] command to resynchronize the array with the new disk.
.PP
.RS 4
snapraid sync
@@ -745,7 +745,7 @@ Spins up all the disks of the array.
.PP
You can spin\-up only some specific disks using the \-d, \-\-filter\-disk option.
.PP
Take care that spinning\-up all the disks at the same time needs a lot of power.
Take care that spinniup\-up all the disks at the same time needs a lot of power.
Ensure that your power\-supply can sustain that.
.PP
Nothing is modified.
@@ -912,7 +912,7 @@ Verify all the files and the parity data.
It works like \[dq]fix\[dq], but it only simulates a recovery and no change
is written in the array.
.PP
This command is mostly intended for manual verification,
This command is mostly intended for manual verifications,
like after a recovery process or in other special conditions.
For periodic and scheduled checks uses \[dq]scrub\[dq].
.PP
@@ -931,7 +931,7 @@ Nothing is modified.
.SS dup
Lists all the duplicate files. Two files are assumed equal if their
hashes are matching. The file data is not read, but only the
pre\-computed hashes are used.
precomputed hashes are used.
.PP
Nothing is modified.
.SS pool
@@ -942,7 +942,7 @@ The files are not really copied here, but just linked using
symbolic links.
.PP
When updating, all the present symbolic links and empty
sub\-directories are deleted and replaced with the new
subdirectories are deleted and replaced with the new
view of the array. Any other regular file is left in place.
.PP
Nothing is modified outside the pool directory.
@@ -962,20 +962,20 @@ low level devices used by a single disk in the array.
.PP
Nothing is modified.
.SS touch
Sets arbitrarily the sub\-second time\-stamp of all the files
Sets arbitrarely the sub\-second timestamp of all the files
that have it at zero.
.PP
This improves the SnapRAID capability to recognize moved
and copied files as it makes the time\-stamp almost unique,
and copied files as it makes the timestamp almost unique,
removing possible duplicates.
.PP
More specifically, if the sub\-second time\-stamp is not zero,
More specifically, if the sub\-second timestamp is not zero,
a moved or copied file is identified as such if it matches
the name, size and time\-stamp. If instead the sub\-second time\-stamp
the name, size and timestamp. If instead the sub\-second timestamp
is zero, it\'s considered a copy only if it matches the full path,
size and time\-stamp.
size and timestamp.
.PP
Note that the second precision time\-stamp is not modified,
Note that the second precision timestamp is not modified,
and all the dates and times of your files will be maintained.
.SS rehash
Schedules a rehash of the whole array.
@@ -1090,7 +1090,7 @@ Imports from the specified directory any file that you deleted
from the array after the last \[dq]sync\[dq].
If you still have such files, they could be used by \[dq]check\[dq]
and \[dq]fix\[dq] to improve the recover process.
The files are read also in sub\-directories and they are
The files are read also in subdirectories and they are
identified regardless of their name.
This option can be used only with \[dq]check\[dq] and \[dq]fix\[dq].
.TP
@@ -1146,7 +1146,7 @@ This allows to identify copied or moved files from one disk
to another, and to reuse the already computed hash information
to detect silent errors or to recover missing files.
This behavior, in some rare cases, may result in false positives,
or in a slow process due the many hash verification, and this
or in a slow process due the many hash verifications, and this
option allows to resolve them.
This option can be used only with \[dq]sync\[dq], \[dq]check\[dq] and \[dq]fix\[dq].
.TP
@@ -1280,7 +1280,7 @@ is enabled:
6\-parity enables hexa (six) parity
.PD
.PP
Each parity level requires the presence of all the previous parity
Each parity level requires the precence of all the previous parity
levels.
.PP
The same considerations of the \'parity\' option apply.

View File

@@ -391,7 +391,7 @@ This command will take a long time, but if you are not paranoid,
you can skip it.
---- 4.4.4 STEP 4 -> Sync ----
Run the "sync" command to re-synchronize the array with the new disk.
Run the "sync" command to resynchronize the array with the new disk.
snapraid sync
@@ -476,7 +476,7 @@ Spins up all the disks of the array.
You can spin-up only some specific disks using the -d, --filter-disk option.
Take care that spinning-up all the disks at the same time needs a lot of power.
Take care that spinniup-up all the disks at the same time needs a lot of power.
Ensure that your power-supply can sustain that.
Nothing is modified.
@@ -643,7 +643,7 @@ Verify all the files and the parity data.
It works like "fix", but it only simulates a recovery and no change
is written in the array.
This command is mostly intended for manual verification,
This command is mostly intended for manual verifications,
like after a recovery process or in other special conditions.
For periodic and scheduled checks uses "scrub".
@@ -668,7 +668,7 @@ Nothing is modified.
Lists all the duplicate files. Two files are assumed equal if their
hashes are matching. The file data is not read, but only the
pre-computed hashes are used.
precomputed hashes are used.
Nothing is modified.
@@ -682,7 +682,7 @@ The files are not really copied here, but just linked using
symbolic links.
When updating, all the present symbolic links and empty
sub-directories are deleted and replaced with the new
subdirectories are deleted and replaced with the new
view of the array. Any other regular file is left in place.
Nothing is modified outside the pool directory.
@@ -708,20 +708,20 @@ Nothing is modified.
5.14 touch
----------
Sets arbitrarily the sub-second time-stamp of all the files
Sets arbitrarely the sub-second timestamp of all the files
that have it at zero.
This improves the SnapRAID capability to recognize moved
and copied files as it makes the time-stamp almost unique,
and copied files as it makes the timestamp almost unique,
removing possible duplicates.
More specifically, if the sub-second time-stamp is not zero,
More specifically, if the sub-second timestamp is not zero,
a moved or copied file is identified as such if it matches
the name, size and time-stamp. If instead the sub-second time-stamp
the name, size and timestamp. If instead the sub-second timestamp
is zero, it's considered a copy only if it matches the full path,
size and time-stamp.
size and timestamp.
Note that the second precision time-stamp is not modified,
Note that the second precision timestamp is not modified,
and all the dates and times of your files will be maintained.
5.15 rehash
@@ -843,7 +843,7 @@ SnapRAID provides the following options:
from the array after the last "sync".
If you still have such files, they could be used by "check"
and "fix" to improve the recover process.
The files are read also in sub-directories and they are
The files are read also in subdirectories and they are
identified regardless of their name.
This option can be used only with "check" and "fix".
@@ -899,7 +899,7 @@ SnapRAID provides the following options:
to another, and to reuse the already computed hash information
to detect silent errors or to recover missing files.
This behavior, in some rare cases, may result in false positives,
or in a slow process due the many hash verification, and this
or in a slow process due the many hash verifications, and this
option allows to resolve them.
This option can be used only with "sync", "check" and "fix".
@@ -1037,7 +1037,7 @@ is enabled:
* 5-parity enables penta (five) parity
* 6-parity enables hexa (six) parity
Each parity level requires the presence of all the previous parity
Each parity level requires the precence of all the previous parity
levels.
The same considerations of the 'parity' option apply.

View File

@@ -36,7 +36,7 @@ void tommy_array_init(tommy_array* array)
/* fixed initial size */
array->bucket_bit = TOMMY_ARRAY_BIT;
array->bucket_max = (tommy_size_t)1 << array->bucket_bit;
array->bucket_max = 1 << array->bucket_bit;
array->bucket[0] = tommy_cast(void**, tommy_calloc(array->bucket_max, sizeof(void*)));
for (i = 1; i < TOMMY_ARRAY_BIT; ++i)
array->bucket[i] = array->bucket[0];
@@ -51,11 +51,11 @@ void tommy_array_done(tommy_array* array)
tommy_free(array->bucket[0]);
for (i = TOMMY_ARRAY_BIT; i < array->bucket_bit; ++i) {
void** segment = array->bucket[i];
tommy_free(&segment[(tommy_ptrdiff_t)1 << i]);
tommy_free(&segment[((tommy_ptrdiff_t)1) << i]);
}
}
void tommy_array_grow(tommy_array* array, tommy_size_t count)
void tommy_array_grow(tommy_array* array, tommy_count_t count)
{
if (array->count >= count)
return;
@@ -72,7 +72,7 @@ void tommy_array_grow(tommy_array* array, tommy_size_t count)
array->bucket[array->bucket_bit] = &segment[-(tommy_ptrdiff_t)array->bucket_max];
++array->bucket_bit;
array->bucket_max = (tommy_size_t)1 << array->bucket_bit;
array->bucket_max = 1 << array->bucket_bit;
}
}

View File

@@ -53,15 +53,20 @@
*/
#define TOMMY_ARRAY_BIT 6
/** \internal
* Max number of elements as a power of 2.
*/
#define TOMMY_ARRAY_BIT_MAX 32
/**
* Array container type.
* \note Don't use internal fields directly, but access the container only using functions.
*/
typedef struct tommy_array_struct {
void** bucket[TOMMY_SIZE_BIT]; /**< Dynamic array of buckets. */
tommy_size_t bucket_max; /**< Number of buckets. */
tommy_size_t count; /**< Number of initialized elements in the array. */
void** bucket[TOMMY_ARRAY_BIT_MAX]; /**< Dynamic array of buckets. */
tommy_uint_t bucket_bit; /**< Bits used in the bit mask. */
tommy_count_t bucket_max; /**< Number of buckets. */
tommy_count_t count; /**< Number of initialized elements in the array. */
} tommy_array;
/**
@@ -78,21 +83,21 @@ void tommy_array_done(tommy_array* array);
* Grows the size up to the specified value.
* All the new elements in the array are initialized with the 0 value.
*/
void tommy_array_grow(tommy_array* array, tommy_size_t size);
void tommy_array_grow(tommy_array* array, tommy_count_t 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_array_grow().
*/
tommy_inline void** tommy_array_ref(tommy_array* array, tommy_size_t pos)
tommy_inline void** tommy_array_ref(tommy_array* array, tommy_count_t pos)
{
tommy_uint_t bsr;
assert(pos < array->count);
/* get the highest bit set, in case of all 0, return 0 */
bsr = tommy_ilog2(pos | 1);
bsr = tommy_ilog2_u32(pos | 1);
return &array->bucket[bsr][pos];
}
@@ -102,7 +107,7 @@ tommy_inline void** tommy_array_ref(tommy_array* array, tommy_size_t pos)
* You must be sure that space for this position is already
* allocated calling tommy_array_grow().
*/
tommy_inline void tommy_array_set(tommy_array* array, tommy_size_t pos, void* element)
tommy_inline void tommy_array_set(tommy_array* array, tommy_count_t pos, void* element)
{
*tommy_array_ref(array, pos) = element;
}
@@ -112,7 +117,7 @@ tommy_inline void tommy_array_set(tommy_array* array, tommy_size_t pos, void* el
* You must be sure that space for this position is already
* allocated calling tommy_array_grow().
*/
tommy_inline void* tommy_array_get(tommy_array* array, tommy_size_t pos)
tommy_inline void* tommy_array_get(tommy_array* array, tommy_count_t pos)
{
return *tommy_array_ref(array, pos);
}
@@ -122,7 +127,7 @@ tommy_inline void* tommy_array_get(tommy_array* array, tommy_size_t pos)
*/
tommy_inline void tommy_array_insert(tommy_array* array, void* element)
{
tommy_size_t pos = array->count;
tommy_count_t pos = array->count;
tommy_array_grow(array, pos + 1);
@@ -132,7 +137,7 @@ tommy_inline void tommy_array_insert(tommy_array* array, void* element)
/**
* Gets the initialized size of the array.
*/
tommy_inline tommy_size_t tommy_array_size(tommy_array* array)
tommy_inline tommy_count_t tommy_array_size(tommy_array* array)
{
return array->count;
}

View File

@@ -40,7 +40,7 @@ void tommy_arrayblkof_init(tommy_arrayblkof* array, tommy_size_t element_size)
void tommy_arrayblkof_done(tommy_arrayblkof* array)
{
tommy_size_t i;
tommy_count_t i;
for (i = 0; i < tommy_array_size(&array->block); ++i)
tommy_free(tommy_array_get(&array->block, i));
@@ -48,10 +48,10 @@ void tommy_arrayblkof_done(tommy_arrayblkof* array)
tommy_array_done(&array->block);
}
void tommy_arrayblkof_grow(tommy_arrayblkof* array, tommy_size_t count)
void tommy_arrayblkof_grow(tommy_arrayblkof* array, tommy_count_t count)
{
tommy_size_t block_max;
tommy_size_t block_mac;
tommy_count_t block_max;
tommy_count_t block_mac;
if (array->count >= count)
return;

View File

@@ -61,7 +61,7 @@
typedef struct tommy_arrayblkof_struct {
tommy_array block; /**< Array of blocks. */
tommy_size_t element_size; /**< Size of the stored element in bytes. */
tommy_size_t count; /**< Number of initialized elements in the array. */
tommy_count_t count; /**< Number of initialized elements in the array. */
} tommy_arrayblkof;
/**
@@ -79,14 +79,14 @@ void tommy_arrayblkof_done(tommy_arrayblkof* array);
* Grows 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, tommy_size_t size);
void tommy_arrayblkof_grow(tommy_arrayblkof* array, tommy_count_t 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, tommy_size_t pos)
tommy_inline void* tommy_arrayblkof_ref(tommy_arrayblkof* array, tommy_count_t pos)
{
unsigned char* base;
@@ -100,7 +100,7 @@ tommy_inline void* tommy_arrayblkof_ref(tommy_arrayblkof* array, tommy_size_t po
/**
* Gets the initialized size of the array.
*/
tommy_inline tommy_size_t tommy_arrayblkof_size(tommy_arrayblkof* array)
tommy_inline tommy_count_t tommy_arrayblkof_size(tommy_arrayblkof* array)
{
return array->count;
}

View File

@@ -136,6 +136,11 @@ tommy_inline void tommy_chain_merge_degenerated(tommy_chain* first, tommy_chain*
tommy_chain_merge(first, second, cmp);
}
/**
* Max number of elements as a power of 2.
*/
#define TOMMY_CHAIN_BIT_MAX 32
/**
* Sorts a chain.
* It's a stable merge sort using power of 2 buckets, with O(N*log(N)) complexity,
@@ -153,20 +158,20 @@ tommy_inline void tommy_chain_mergesort(tommy_chain* chain, tommy_compare_func*
/*
* Bit buckets of chains.
* Each bucket contains 2^i nodes or it's empty.
* The chain at address TOMMY_BIT_MAX is an independet variable operating as "carry".
* The chain at address TOMMY_CHAIN_BIT_MAX is an independet variable operating as "carry".
* We keep it in the same "bit" vector to avoid reports from the valgrind tool sgcheck.
*/
tommy_chain bit[TOMMY_SIZE_BIT + 1];
tommy_chain bit[TOMMY_CHAIN_BIT_MAX + 1];
/**
* Value stored inside the bit bucket.
* It's used to know which bucket is empty of full.
*/
tommy_size_t counter;
tommy_count_t counter;
tommy_node* node = chain->head;
tommy_node* tail = chain->tail;
tommy_size_t mask;
tommy_size_t i;
tommy_count_t mask;
tommy_count_t i;
counter = 0;
while (1) {
@@ -174,9 +179,9 @@ tommy_inline void tommy_chain_mergesort(tommy_chain* chain, tommy_compare_func*
tommy_chain* last;
/* carry bit to add */
last = &bit[TOMMY_SIZE_BIT];
bit[TOMMY_SIZE_BIT].head = node;
bit[TOMMY_SIZE_BIT].tail = node;
last = &bit[TOMMY_CHAIN_BIT_MAX];
bit[TOMMY_CHAIN_BIT_MAX].head = node;
bit[TOMMY_CHAIN_BIT_MAX].tail = node;
next = node->next;
/* add the bit, propagating the carry */
@@ -201,7 +206,7 @@ tommy_inline void tommy_chain_mergesort(tommy_chain* chain, tommy_compare_func*
}
/* merge the buckets */
i = tommy_ctz(counter);
i = tommy_ctz_u32(counter);
mask = counter >> i;
while (mask != 1) {
mask >>= 1;

View File

@@ -92,22 +92,22 @@ tommy_uint32_t tommy_hash_u32(tommy_uint32_t init_val, const void* void_key, tom
b += tommy_le_uint32_read(key + 4);
a += tommy_le_uint32_read(key + 0);
break;
case 11 : c += ((tommy_uint32_t)key[10]) << 16; /* fallthrough */
case 10 : c += ((tommy_uint32_t)key[9]) << 8; /* fallthrough */
case 9 : c += key[8]; /* fallthrough */
case 11 : c += ((tommy_uint32_t)key[10]) << 16;
case 10 : c += ((tommy_uint32_t)key[9]) << 8;
case 9 : c += key[8];
case 8 :
b += tommy_le_uint32_read(key + 4);
a += tommy_le_uint32_read(key + 0);
break;
case 7 : b += ((tommy_uint32_t)key[6]) << 16; /* fallthrough */
case 6 : b += ((tommy_uint32_t)key[5]) << 8; /* fallthrough */
case 5 : b += key[4]; /* fallthrough */
case 7 : b += ((tommy_uint32_t)key[6]) << 16;
case 6 : b += ((tommy_uint32_t)key[5]) << 8;
case 5 : b += key[4];
case 4 :
a += tommy_le_uint32_read(key + 0);
break;
case 3 : a += ((tommy_uint32_t)key[2]) << 16; /* fallthrough */
case 2 : a += ((tommy_uint32_t)key[1]) << 8; /* fallthrough */
case 1 : a += key[0]; /* fallthrough */
case 3 : a += ((tommy_uint32_t)key[2]) << 16;
case 2 : a += ((tommy_uint32_t)key[1]) << 8;
case 1 : a += key[0];
}
tommy_final(a, b, c);
@@ -142,22 +142,22 @@ tommy_uint64_t tommy_hash_u64(tommy_uint64_t init_val, const void* void_key, tom
b += tommy_le_uint32_read(key + 4);
a += tommy_le_uint32_read(key + 0);
break;
case 11 : c += ((tommy_uint32_t)key[10]) << 16; /* fallthrough */
case 10 : c += ((tommy_uint32_t)key[9]) << 8; /* fallthrough */
case 9 : c += key[8]; /* fallthrough */
case 11 : c += ((tommy_uint32_t)key[10]) << 16;
case 10 : c += ((tommy_uint32_t)key[9]) << 8;
case 9 : c += key[8];
case 8 :
b += tommy_le_uint32_read(key + 4);
a += tommy_le_uint32_read(key + 0);
break;
case 7 : b += ((tommy_uint32_t)key[6]) << 16; /* fallthrough */
case 6 : b += ((tommy_uint32_t)key[5]) << 8; /* fallthrough */
case 5 : b += key[4]; /* fallthrough */
case 7 : b += ((tommy_uint32_t)key[6]) << 16;
case 6 : b += ((tommy_uint32_t)key[5]) << 8;
case 5 : b += key[4];
case 4 :
a += tommy_le_uint32_read(key + 0);
break;
case 3 : a += ((tommy_uint32_t)key[2]) << 16; /* fallthrough */
case 2 : a += ((tommy_uint32_t)key[1]) << 8; /* fallthrough */
case 1 : a += key[0]; /* fallthrough */
case 3 : a += ((tommy_uint32_t)key[2]) << 16;
case 2 : a += ((tommy_uint32_t)key[1]) << 8;
case 1 : a += key[0];
}
tommy_final(a, b, c);

View File

@@ -37,6 +37,11 @@
/******************************************************************************/
/* hash */
/**
* Hash type used in hashtables.
*/
typedef tommy_key_t tommy_hash_t;
/**
* Hash function with a 32 bits result.
* Implementation of the Robert Jenkins "lookup3" hash 32 bits version,

View File

@@ -35,7 +35,7 @@ void tommy_hashdyn_init(tommy_hashdyn* hashdyn)
{
/* fixed initial size */
hashdyn->bucket_bit = TOMMY_HASHDYN_BIT;
hashdyn->bucket_max = (tommy_size_t)1 << hashdyn->bucket_bit;
hashdyn->bucket_max = 1 << hashdyn->bucket_bit;
hashdyn->bucket_mask = hashdyn->bucket_max - 1;
hashdyn->bucket = tommy_cast(tommy_hashdyn_node**, tommy_calloc(hashdyn->bucket_max, sizeof(tommy_hashdyn_node*)));
@@ -50,18 +50,18 @@ void tommy_hashdyn_done(tommy_hashdyn* hashdyn)
/**
* Resize the bucket vector.
*/
static void tommy_hashdyn_resize(tommy_hashdyn* hashdyn, tommy_size_t new_bucket_bit)
static void tommy_hashdyn_resize(tommy_hashdyn* hashdyn, tommy_count_t new_bucket_bit)
{
tommy_size_t bucket_bit;
tommy_size_t bucket_max;
tommy_size_t new_bucket_max;
tommy_size_t new_bucket_mask;
tommy_count_t bucket_bit;
tommy_count_t bucket_max;
tommy_count_t new_bucket_max;
tommy_count_t new_bucket_mask;
tommy_hashdyn_node** new_bucket;
bucket_bit = hashdyn->bucket_bit;
bucket_max = hashdyn->bucket_max;
new_bucket_max = (tommy_size_t)1 << new_bucket_bit;
new_bucket_max = 1 << new_bucket_bit;
new_bucket_mask = new_bucket_max - 1;
/* allocate the new vector using malloc() and not calloc() */
@@ -70,7 +70,7 @@ static void tommy_hashdyn_resize(tommy_hashdyn* hashdyn, tommy_size_t new_bucket
/* reinsert all the elements */
if (new_bucket_bit > bucket_bit) {
tommy_size_t i;
tommy_count_t i;
/* grow */
for (i = 0; i < bucket_max; ++i) {
@@ -84,7 +84,7 @@ static void tommy_hashdyn_resize(tommy_hashdyn* hashdyn, tommy_size_t new_bucket
j = hashdyn->bucket[i];
while (j) {
tommy_hashdyn_node* j_next = j->next;
tommy_size_t pos = j->index & new_bucket_mask;
tommy_count_t pos = j->key & new_bucket_mask;
if (new_bucket[pos])
tommy_list_insert_tail_not_empty(new_bucket[pos], j);
else
@@ -93,7 +93,7 @@ static void tommy_hashdyn_resize(tommy_hashdyn* hashdyn, tommy_size_t new_bucket
}
}
} else {
tommy_size_t i;
tommy_count_t i;
/* shrink */
for (i = 0; i < new_bucket_max; ++i) {
@@ -136,11 +136,11 @@ tommy_inline void hashdyn_shrink_step(tommy_hashdyn* hashdyn)
void tommy_hashdyn_insert(tommy_hashdyn* hashdyn, tommy_hashdyn_node* node, void* data, tommy_hash_t hash)
{
tommy_size_t pos = hash & hashdyn->bucket_mask;
tommy_count_t pos = hash & hashdyn->bucket_mask;
tommy_list_insert_tail(&hashdyn->bucket[pos], node, data);
node->index = hash;
node->key = hash;
++hashdyn->count;
@@ -149,7 +149,7 @@ void tommy_hashdyn_insert(tommy_hashdyn* hashdyn, tommy_hashdyn_node* node, void
void* tommy_hashdyn_remove_existing(tommy_hashdyn* hashdyn, tommy_hashdyn_node* node)
{
tommy_size_t pos = node->index & hashdyn->bucket_mask;
tommy_count_t pos = node->key & hashdyn->bucket_mask;
tommy_list_remove_existing(&hashdyn->bucket[pos], node);
@@ -162,12 +162,12 @@ void* tommy_hashdyn_remove_existing(tommy_hashdyn* hashdyn, tommy_hashdyn_node*
void* tommy_hashdyn_remove(tommy_hashdyn* hashdyn, tommy_search_func* cmp, const void* cmp_arg, tommy_hash_t hash)
{
tommy_size_t pos = hash & hashdyn->bucket_mask;
tommy_count_t pos = hash & hashdyn->bucket_mask;
tommy_hashdyn_node* node = hashdyn->bucket[pos];
while (node) {
/* we first check if the hash matches, as in the same bucket we may have multiples hash values */
if (node->index == hash && cmp(cmp_arg, node->data) == 0) {
if (node->key == hash && cmp(cmp_arg, node->data) == 0) {
tommy_list_remove_existing(&hashdyn->bucket[pos], node);
--hashdyn->count;
@@ -184,9 +184,9 @@ void* tommy_hashdyn_remove(tommy_hashdyn* hashdyn, tommy_search_func* cmp, const
void tommy_hashdyn_foreach(tommy_hashdyn* hashdyn, tommy_foreach_func* func)
{
tommy_size_t bucket_max = hashdyn->bucket_max;
tommy_count_t bucket_max = hashdyn->bucket_max;
tommy_hashdyn_node** bucket = hashdyn->bucket;
tommy_size_t pos;
tommy_count_t pos;
for (pos = 0; pos < bucket_max; ++pos) {
tommy_hashdyn_node* node = bucket[pos];
@@ -201,9 +201,9 @@ void tommy_hashdyn_foreach(tommy_hashdyn* hashdyn, tommy_foreach_func* func)
void tommy_hashdyn_foreach_arg(tommy_hashdyn* hashdyn, tommy_foreach_arg_func* func, void* arg)
{
tommy_size_t bucket_max = hashdyn->bucket_max;
tommy_count_t bucket_max = hashdyn->bucket_max;
tommy_hashdyn_node** bucket = hashdyn->bucket;
tommy_size_t pos;
tommy_count_t pos;
for (pos = 0; pos < bucket_max; ++pos) {
tommy_hashdyn_node* node = bucket[pos];

View File

@@ -160,10 +160,10 @@ typedef tommy_node tommy_hashdyn_node;
*/
typedef struct tommy_hashdyn_struct {
tommy_hashdyn_node** bucket; /**< Hash buckets. One list for each hash modulus. */
tommy_size_t bucket_max; /**< Number of buckets. */
tommy_size_t bucket_mask; /**< Bit mask to access the buckets. */
tommy_size_t count; /**< Number of elements. */
tommy_uint_t bucket_bit; /**< Bits used in the bit mask. */
tommy_count_t bucket_max; /**< Number of buckets. */
tommy_count_t bucket_mask; /**< Bit mask to access the buckets. */
tommy_count_t count; /**< Number of elements. */
} tommy_hashdyn;
/**
@@ -226,7 +226,7 @@ tommy_inline void* tommy_hashdyn_search(tommy_hashdyn* hashdyn, tommy_search_fun
while (i) {
/* we first check if the hash matches, as in the same bucket we may have multiples hash values */
if (i->index == hash && cmp(cmp_arg, i->data) == 0)
if (i->key == hash && cmp(cmp_arg, i->data) == 0)
return i->data;
i = i->next;
}
@@ -281,7 +281,7 @@ void tommy_hashdyn_foreach_arg(tommy_hashdyn* hashdyn, tommy_foreach_arg_func* f
/**
* Gets the number of elements.
*/
tommy_inline tommy_size_t tommy_hashdyn_count(tommy_hashdyn* hashdyn)
tommy_inline tommy_count_t tommy_hashdyn_count(tommy_hashdyn* hashdyn)
{
return hashdyn->count;
}

View File

@@ -226,6 +226,24 @@ tommy_inline void tommy_list_insert_tail(tommy_list* list, tommy_node* node, voi
node->data = data;
}
/** \internal
* Removes an element from the head of a not empty list.
* \param list The list. The list cannot be empty.
* \return The node removed.
*/
tommy_inline tommy_node* tommy_list_remove_head_not_empty(tommy_list* list)
{
tommy_node* head = tommy_list_head(list);
/* remove from the "circular" prev list */
head->next->prev = head->prev;
/* remove from the "0 terminated" next list */
*list = head->next; /* the new head, in case 0 */
return head;
}
/**
* Removes an element from the list.
* You must already have the address of the element to remove.
@@ -311,9 +329,9 @@ tommy_inline tommy_bool_t tommy_list_empty(tommy_list* list)
* Gets the number of elements.
* \note This operation is O(n).
*/
tommy_inline tommy_size_t tommy_list_count(tommy_list* list)
tommy_inline tommy_count_t tommy_list_count(tommy_list* list)
{
tommy_size_t count = 0;
tommy_count_t count = 0;
tommy_node* i = tommy_list_head(list);
while (i) {

View File

@@ -39,10 +39,10 @@ void tommy_tree_init(tommy_tree* tree, tommy_compare_func* cmp)
tree->cmp = cmp;
}
static tommy_ssize_t tommy_tree_delta(tommy_tree_node* root)
static int tommy_tree_delta(tommy_tree_node* root)
{
tommy_ssize_t left_height = root->prev ? root->prev->index : 0;
tommy_ssize_t right_height = root->next ? root->next->index : 0;
int left_height = root->prev ? root->prev->key : 0;
int right_height = root->next ? root->next->key : 0;
return left_height - right_height;
}
@@ -84,7 +84,7 @@ static tommy_tree_node* tommy_tree_move_right(tommy_tree_node* root, tommy_tree_
static tommy_tree_node* tommy_tree_balance(tommy_tree_node* root)
{
tommy_ssize_t delta = tommy_tree_delta(root);
int delta = tommy_tree_delta(root);
if (delta < -1) {
if (tommy_tree_delta(root->next) > 0)
@@ -99,16 +99,16 @@ static tommy_tree_node* tommy_tree_balance(tommy_tree_node* root)
}
/* recompute key */
root->index = 0;
root->key = 0;
if (root->prev && root->prev->index > root->index)
root->index = root->prev->index;
if (root->prev && root->prev->key > root->key)
root->key = root->prev->key;
if (root->next && root->next->index > root->index)
root->index = root->next->index;
if (root->next && root->next->key > root->key)
root->key = root->next->key;
/* count itself */
root->index += 1;
root->key += 1;
return root;
}
@@ -145,7 +145,7 @@ void* tommy_tree_insert(tommy_tree* tree, tommy_tree_node* node, void* data)
insert->data = data;
insert->prev = 0;
insert->next = 0;
insert->index = 0;
insert->key = 0;
tree->root = tommy_tree_insert_node(tree->cmp, tree->root, &insert);

View File

@@ -117,8 +117,8 @@ typedef tommy_node tommy_tree_node;
*/
typedef struct tommy_tree_struct {
tommy_tree_node* root; /**< Root node. */
tommy_count_t count; /**< Number of elements. */
tommy_compare_func* cmp; /**< Comparison function. */
tommy_size_t count; /**< Number of elements. */
} tommy_tree;
/**
@@ -213,7 +213,7 @@ void tommy_tree_foreach_arg(tommy_tree* tree, tommy_foreach_arg_func* func, void
/**
* Gets the number of elements.
*/
tommy_inline tommy_size_t tommy_tree_count(tommy_tree* tree)
tommy_inline tommy_count_t tommy_tree_count(tommy_tree* tree)
{
return tree->count;
}

View File

@@ -24,6 +24,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/** \file
* Generic types.
*/
@@ -36,37 +37,17 @@
#include <stddef.h>
#ifdef _MSC_VER
#if defined(_MSC_VER)
typedef unsigned tommy_uint32_t; /**< Generic uint32_t type. */
typedef unsigned _int64 tommy_uint64_t; /**< Generic uint64_t type. */
typedef size_t tommy_uintptr_t; /**< Generic uintptr_t type. */
#ifdef _WIN64
#define TOMMY_SIZE_BIT 64
typedef unsigned _int64_t tommy_size_t; /**< Generic size_t type. */
typedef _int64_t tommy_ssize_t; /**< Generic ssize_t type. */
#else
#define TOMMY_SIZE_BIT 32
typedef unsigned tommy_size_t; /**< Generic size_t type. */
typedef int tommy_ssize_t; /**< Generic ssize_t type. */
#endif
#else
#include <stdint.h>
typedef uint32_t tommy_uint32_t; /**< Generic uint32_t type. */
typedef uint64_t tommy_uint64_t; /**< Generic uint64_t type. */
typedef uintptr_t tommy_uintptr_t; /**< Generic uintptr_t type. */
#if SIZE_MAX == UINT64_MAX
#define TOMMY_SIZE_BIT 64
typedef uint64_t tommy_size_t; /**< Generic size_t type. */
typedef int64_t tommy_ssize_t; /**< Generic ssize_t type. */
#elif SIZE_MAX == UINT32_MAX
#define TOMMY_SIZE_BIT 32
typedef uint32_t tommy_size_t; /**< Generic size_t type. */
typedef int32_t tommy_ssize_t; /**< Generic ssize_t type. */
#else
#error Unsupported SIZE_MAX
#endif
#endif
typedef size_t tommy_size_t; /**< Generic size_t type. */
typedef ptrdiff_t tommy_ptrdiff_t; /**< Generic ptrdiff_t type. */
typedef int tommy_bool_t; /**< Generic boolean type. */
@@ -78,6 +59,13 @@ typedef int tommy_bool_t; /**< Generic boolean type. */
*/
typedef tommy_uint32_t tommy_uint_t;
/**
* Generic unsigned integer for counting objects.
*
* TommyDS doesn't support more than 2^32-1 objects.
*/
typedef tommy_uint32_t tommy_count_t;
/** \internal
* Type cast required for the C++ compilation.
* When compiling in C++ we cannot convert a void* pointer to another pointer.
@@ -164,17 +152,17 @@ typedef tommy_uint32_t tommy_uint_t;
#endif
/******************************************************************************/
/* key/hash */
/* key */
/**
* Type used in indexed data structures to store the key of a object.
* Key type used in indexed data structures to store the key or the hash value.
*/
typedef tommy_size_t tommy_key_t;
typedef tommy_uint32_t tommy_key_t;
/**
* Type used in hashtables to store the hash of a object.
* Bits into the ::tommy_key_t type.
*/
typedef tommy_size_t tommy_hash_t;
#define TOMMY_KEY_BIT (sizeof(tommy_key_t) * 8)
/******************************************************************************/
/* node */
@@ -212,12 +200,11 @@ typedef struct tommy_node_struct {
void* data;
/**
* Index of the node.
* With tries this field is used to store the key.
* Key used to store the node.
* With hashtables this field is used to store the hash value.
* With lists this field is not used.
*/
tommy_size_t index;
tommy_key_t key;
} tommy_node;
/******************************************************************************/
@@ -315,10 +302,6 @@ typedef void tommy_foreach_arg_func(void* arg, void* obj);
#include <intrin.h>
#pragma intrinsic(_BitScanReverse)
#pragma intrinsic(_BitScanForward)
#if TOMMY_SIZE_BIT == 64
#pragma intrinsic(_BitScanReverse64)
#pragma intrinsic(_BitScanForward64)
#endif
#endif
/** \internal
@@ -380,29 +363,6 @@ tommy_inline tommy_uint_t tommy_ilog2_u32(tommy_uint32_t value)
#endif
}
#if TOMMY_SIZE_BIT == 64
/**
* Bit scan reverse or integer log2 for 64 bits.
*/
tommy_inline tommy_uint_t tommy_ilog2_u64(tommy_uint64_t value)
{
#if defined(_MSC_VER)
unsigned long count;
_BitScanReverse64(&count, value);
return count;
#elif defined(__GNUC__)
return __builtin_clzll(value) ^ 63;
#else
uint32_t l = value & 0xFFFFFFFFU;
uint32_t h = value >> 32;
if (h)
return tommy_ilog2_u32(h) + 32;
else
return tommy_ilog2_u32(l);
#endif
}
#endif
/**
* Bit scan forward or trailing zero count.
* Return the bit index of the least significant 1 bit.
@@ -431,29 +391,6 @@ tommy_inline tommy_uint_t tommy_ctz_u32(tommy_uint32_t value)
#endif
}
#if TOMMY_SIZE_BIT == 64
/**
* Bit scan forward or trailing zero count for 64 bits.
*/
tommy_inline tommy_uint_t tommy_ctz_u64(tommy_uint64_t value)
{
#if defined(_MSC_VER)
unsigned long count;
_BitScanForward64(&count, value);
return count;
#elif defined(__GNUC__)
return __builtin_ctzll(value);
#else
uint32_t l = value & 0xFFFFFFFFU;
uint32_t h = value >> 32;
if (l)
return tommy_ctz_u32(l);
else
return tommy_ctz_u32(h) + 32;
#endif
}
#endif
/**
* Rounds up to the next power of 2.
* For the value 0, the result is undefined.
@@ -475,23 +412,6 @@ tommy_inline tommy_uint32_t tommy_roundup_pow2_u32(tommy_uint32_t value)
return value;
}
/**
* Rounds up to the next power of 2 for 64 bits.
*/
tommy_inline tommy_uint64_t tommy_roundup_pow2_u64(tommy_uint64_t value)
{
--value;
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
value |= value >> 32;
++value;
return value;
}
/**
* Check if the specified word has a byte at 0.
* \return 0 or 1.
@@ -500,19 +420,5 @@ tommy_inline int tommy_haszero_u32(tommy_uint32_t value)
{
return ((value - 0x01010101) & ~value & 0x80808080) != 0;
}
/*
* Bit depth mapping.
*/
#if TOMMY_SIZE_BIT == 64
#define tommy_ilog2 tommy_ilog2_u64
#define tommy_ctz tommy_ctz_u64
#define tommy_roundup_pow2 tommy_roundup_pow2_u64
#else
#define tommy_ilog2 tommy_ilog2_u32
#define tommy_ctz tommy_ctz_u32
#define tommy_roundup_pow2 tommy_roundup_pow2_u32
#endif
#endif