summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.bzrignore5
-rw-r--r--CMakeLists.txt59
-rw-r--r--config.h.in4
-rw-r--r--default.c242
-rw-r--r--fastwriter.c18
-rw-r--r--fastwriter.pc.in10
-rw-r--r--fastwriter.spec.in76
-rw-r--r--memcpy.c344
-rw-r--r--memcpy.h63
-rw-r--r--sysinfo.c4
10 files changed, 756 insertions, 69 deletions
diff --git a/.bzrignore b/.bzrignore
index a437ac0..d4b4492 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -7,3 +7,8 @@ Makefile
cmake_install.cmake
CMakeCache.txt
*.so.*
+CPackConfig.cmake
+CPackSourceConfig.cmake
+_CPack_Packages
+fastwriter.spec
+*.tar.bz2
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 81c6c40..79bd891 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,13 +1,16 @@
-project(fastwriter)
+project(fastwriter C)
+set(RELEASE "0")
set(FASTWRITER_VERSION "0.0.2")
set(FASTWRITER_ABI_VERSION "0")
cmake_minimum_required(VERSION 2.8)
+set(DISABLE_AIO TRUE CACHE BOOL "Use kernel AIO writer")
set(DISABLE_XFS_REALTIME FALSE CACHE BOOL "Disable support of RealTime XFS partition")
+set(USE_CUSTOM_MEMCPY FALSE CACHE BOOL "Use custom memcpy routine instead of stanadrd")
-
+include(GNUInstallDirs)
include(CheckIncludeFiles)
check_include_files("linux/falloc.h" HAVE_LINUX_FALLOC_H)
@@ -31,7 +34,21 @@ include_directories(
add_definitions("-fPIC --std=c99 -Wall -O2 -pthread")
set(HEADERS fastwriter.h sysinfo.h default.h private.h)
-add_library(fastwriter SHARED fastwriter.c sysinfo.c default.c)
+set(SOURCES fastwriter.c sysinfo.c default.c)
+
+if (USE_CUSTOM_MEMCPY)
+ set(HEADERS ${HEADERS} memcpy.h)
+ set(SOURCES ${SOURCES} memcpy.c)
+endif (USE_CUSTOM_MEMCPY)
+
+if (NOT DISABLE_AIO)
+ check_include_files("libaio.h" HAVE_LIBAIO_H)
+ if (NOT HAVE_LIBAIO_H)
+ message(FATAL_ERROR "error: libaio.h is not found...")
+ endif (NOT HAVE_LIBAIO_H)
+endif (NOT DISABLE_AIO)
+
+add_library(fastwriter SHARED ${SOURCES})
set_target_properties(fastwriter PROPERTIES
VERSION ${FASTWRITER_VERSION}
@@ -39,6 +56,10 @@ set_target_properties(fastwriter PROPERTIES
LINK_FLAGS "-pthread"
)
+if (NOT DISABLE_AIO)
+ target_link_libraries(fastwriter aio)
+endif (NOT DISABLE_AIO)
+
set(TARNAME "fastwriter")
set(PACKAGE_VERSION ${FASTWRITER_VERSION})
set(PACKAGE_NAME "${TARNAME}")
@@ -46,34 +67,34 @@ set(PACKAGE_TARNAME "${TARNAME}")
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
set(PACKAGE_BUGREPORT "http://ufo.kit.edu/ufo/newticket")
-if(NOT DEFINED BIN_INSTALL_DIR)
- set(BIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/bin")
-endif(NOT DEFINED BIN_INSTALL_DIR)
-
-if(NOT DEFINED LIB_INSTALL_DIR)
- set(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib")
-endif(NOT DEFINED LIB_INSTALL_DIR)
+set(CPACK_SOURCE_GENERATOR "TBZ2")
+set(CPACK_PACKAGE_CONTACT "Suren A. Chilingaryan <csa@suren.me>")
+if (${RELEASE} GREATER 0)
+ set(CPACK_PACKAGE_VERSION "${PACKAGE_VERSION}.${RELEASE}")
+else (${RELEASE} GREATER 0)
+ set(CPACK_PACKAGE_VERSION "${PACKAGE_VERSION}")
+endif (${RELEASE} GREATER 0)
+set(CPACK_SOURCE_IGNORE_FILES "/.bzr/;CMakeFiles;_CPack_Packages;cmake_install.cmake;CPack.*.cmake;CMakeCache.txt;install_manifest.txt;config.h$;.pc$;Makefile;.tar.bz2$;~$;${CPACK_SOURCE_IGNORE_FILES}")
+set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${CPACK_PACKAGE_VERSION}")
+include(CPack)
-if(NOT DEFINED INCLUDE_INSTALL_DIR)
- set(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include")
-endif(NOT DEFINED INCLUDE_INSTALL_DIR)
+add_custom_target(dist_clean COMMAND ${CMAKE_MAKE_PROGRAM} clean WORKING_DIRECTORY ${CMAKE_CURRENT_DIR})
+add_custom_target(dist DEPENDS dist_clean COMMAND ${CMAKE_MAKE_PROGRAM} package_source)
-if(NOT DEFINED LOCALE_INSTALL_DIR)
- set(LOCALE_INSTALL_DIR "${DATA_INSTALL_DIR}/locale/")
-endif(NOT DEFINED LOCALE_INSTALL_DIR)
configure_file(fastwriter.pc.in ${CMAKE_CURRENT_BINARY_DIR}/fastwriter.pc)
+configure_file(fastwriter.spec.in ${CMAKE_CURRENT_BINARY_DIR}/fastwriter.spec)
configure_file(config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
install(TARGETS fastwriter
- LIBRARY DESTINATION lib${LIB_SUFFIX}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
install(FILES fastwriter.h
- DESTINATION include
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/fastwriter.pc
- DESTINATION ${LIB_INSTALL_DIR}/pkgconfig
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
)
diff --git a/config.h.in b/config.h.in
index 3627160..59332fc 100644
--- a/config.h.in
+++ b/config.h.in
@@ -1,2 +1,4 @@
#cmakedefine HAVE_LINUX_FALLOC_H
-#cmakedefine DISABLE_XFS_REALTIME \ No newline at end of file
+#cmakedefine DISABLE_XFS_REALTIME
+#cmakedefine DISABLE_AIO
+#cmakedefine USE_CUSTOM_MEMCPY
diff --git a/default.c b/default.c
index 5109608..4c55144 100644
--- a/default.c
+++ b/default.c
@@ -31,6 +31,7 @@
# include <xfs/xfs.h>
#endif /* !DISABLE_XFS_REALTIME */
+
#include "fastwriter.h"
#include "private.h"
#include "sysinfo.h"
@@ -40,18 +41,57 @@
#define HAVE_FALLOCATE
#define EXT4_WRITEBLOCK 4194304
#define EXT4_PREALLOCATE 1073741824
+#define OCFS_WRITEBLOCK 262144
+#define AIO_QUEUE_LENGTH 4
+#define AIO_BUFFERS 8
+
+#ifndef DISABLE_AIO
+# include <libaio.h>
+# if AIO_QUEUE_LENGTH > AIO_BUFFERS
+# error "AIO_QUEUE_LENGTH > AIO_BUFFERS"
+# endif
+#endif /* DISABLE_AIO */
+
+
+#ifndef DISABLE_AIO
+typedef struct {
+ size_t offset;
+ size_t size;
+ int ios;
+ int ready; /**< 0 - unused, 1 - processing, 2 - done */
+} fastwriter_data_t;
+#endif /* !DISABLE_AIO */
typedef struct {
int fd;
- int sync_mode;
+ int sync_mode; /**< Open with O_DIRECT flag to avoid caches */
+ int aio_mode; /**< Use kernel AIO (libaio.h) */
size_t prior_size; /**< original size of file */
size_t preallocated; /**< preallocated bytes */
size_t wr_block; /**< minimal block of data to write */
size_t pa_block; /**< preallocation setp */
+
+#ifndef DISABLE_AIO
+ io_context_t aio;
+
+ int ios_ready_n;
+ int ios_ready[AIO_QUEUE_LENGTH];
+ struct iocb ios[AIO_QUEUE_LENGTH];
+
+ int data_head, data_tail;
+ fastwriter_data_t data[AIO_BUFFERS];
+
+ int ios_status[AIO_QUEUE_LENGTH];
+
+ size_t sched; /**< how far we ahead of currently writted head */
+ size_t fd_offset; /**< current file offset */
+
+ int page_size;
+#endif /* !DISABLE_AIO */
} fastwriter_default_t;
@@ -89,9 +129,6 @@ int fastwriter_default_open(fastwriter_t *fw, const char *name, fastwriter_flags
ctx->wr_block = EXT4_WRITEBLOCK;
ctx->pa_block = 0;
ctx->prior_size = (size_t)-1;
-#ifdef SYNC_MODE
-// ctx->sync_mode = 0;
-#endif /* SYNC_MODE */
open_flags &= ~(O_CREAT|O_NOATIME|O_LARGEFILE);
} else if (!strcmp(fs, "ext4")) {
ctx->wr_block = EXT4_WRITEBLOCK;
@@ -102,22 +139,37 @@ int fastwriter_default_open(fastwriter_t *fw, const char *name, fastwriter_flags
} else if (!strcmp(fs, "xfs")) {
ctx->wr_block = EXT4_WRITEBLOCK;
ctx->pa_block = EXT4_PREALLOCATE;
- } else {
+ } else if (!strcmp(fs, "ocfs2")) {
+#ifndef DISABLE_AIO
+ ctx->aio_mode = 1;
+ ctx->sync_mode = 0;
+ ctx->wr_block = OCFS_WRITEBLOCK;
+#else /* !DISABLE_AIO */
ctx->wr_block = EXT4_WRITEBLOCK;
+#endif /* !DISABLE_AIO */
+ ctx->pa_block = EXT4_PREALLOCATE;
+/* } else if (!strcmp(fs, "fhgfs")) {
+ ctx->sync_mode = 0;
+ ctx->wr_block = OCFS_WRITEBLOCK;
+ ctx->pa_block = EXT4_PREALLOCATE;
+ } else if (strstr(fs, "gluster")) {
+ ctx->sync_mode = 0;
+ ctx->wr_block = OCFS_WRITEBLOCK;
+ ctx->pa_block = EXT4_PREALLOCATE;*/
+ } else {
+ ctx->sync_mode = 0;
+ ctx->wr_block = OCFS_WRITEBLOCK;
ctx->pa_block = 0;
}
-
-#ifdef SYNC_MODE
+
if (ctx->sync_mode) {
open_flags |= O_DIRECT;
}
-#endif /* SYNC_MODE */
if (flags&FASTWRITER_FLAGS_OVERWRITE)
open_flags |= O_TRUNC;
ctx->fd = open(name, open_flags, open_mode);
-#ifdef SYNC_MODE
if (ctx->fd < 0) {
// Running as normal user, try to disable direct mode
if ((errno == EINVAL)&&(ctx->sync_mode)) {
@@ -125,26 +177,23 @@ int fastwriter_default_open(fastwriter_t *fw, const char *name, fastwriter_flags
open_flags &= ~O_DIRECT;
ctx->fd = open(name, open_flags, open_mode);
}
-#endif /* SYNC_MODE */
if (ctx->fd < 0) return errno;
-#ifdef SYNC_MODE
}
-#endif /* SYNC_MODE */
if (((open_flags&FASTWRITER_FLAGS_OVERWRITE)==0)&&(strcmp(fs, "raw"))) {
- ctx->prior_size = lseek(ctx->fd, 0, SEEK_END);
-# ifdef SYNC_MODE
+ ctx->prior_size = lseek64(ctx->fd, 0, SEEK_END);
+
if (ctx->prior_size%FASTWRITER_SYNCIO_ALIGN) {
close(ctx->fd);
ctx->fd = open(name, open_flags&~O_DIRECT, open_mode);
if (ctx->fd < 0) return errno;
- ctx->prior_size = lseek(ctx->fd, 0, SEEK_END);
+ ctx->prior_size = lseek64(ctx->fd, 0, SEEK_END);
ctx->sync_mode = 0;
+ ctx->aio_mode = 0;
}
-# endif /* SYNC_MODE */
}
#ifndef DISABLE_XFS_REALTIME
@@ -153,11 +202,30 @@ int fastwriter_default_open(fastwriter_t *fw, const char *name, fastwriter_flags
if (!err) {
attr.fsx_xflags |= XFS_XFLAG_REALTIME;
err = xfsctl (name, ctx->fd, XFS_IOC_FSSETXATTR, (void *) &attr);
-// if (!err) puts("Real-time");
+ if (err) fprintf(stderr, "Error initializing XFS real-time mode (%i), disabling...\n", err);
}
}
#endif /* !DISABLE_XFS_REALTIME */
+#ifndef DISABLE_AIO
+ if (ctx->aio_mode) {
+ int i;
+ ctx->page_size = getpagesize();
+ ctx->fd_offset = ctx->prior_size;
+
+ ctx->ios_ready_n = AIO_QUEUE_LENGTH;
+ for (i = 0; i < AIO_QUEUE_LENGTH; i++) {
+ ctx->ios_ready[i] = i;
+ }
+
+ err = io_queue_init(AIO_QUEUE_LENGTH, &ctx->aio);
+ if (err) {
+ fprintf(stderr, "Error initializing AIO mode (%i), disabling...\n", -err);
+ ctx->aio_mode = 0;
+ }
+ }
+#endif /* !DISABLE_AIO */
+
ctx->preallocated = 0;
return 0;
@@ -169,11 +237,31 @@ void fastwriter_default_close(fastwriter_t *fw) {
fastwriter_default_t *ctx = (fastwriter_default_t*)fw->ctx;
if (ctx->fd >= 0) {
-#if defined(SYNC_MODE)||!defined(HAVE_LINUX_FALLOC_H)
+#ifndef DISABLE_AIO
+ if ((ctx->aio_mode)&&(ctx->aio)) {
+ int n_ev;
+ struct io_event ev[AIO_QUEUE_LENGTH];
+
+ while (ctx->ios_ready_n < AIO_QUEUE_LENGTH) {
+ n_ev = io_getevents(ctx->aio, 1, AIO_QUEUE_LENGTH, &ev[0], NULL);
+ if (n_ev <= 0) {
+ fprintf(stderr, "AIO io_getevents have failed (%i)", -n_ev);
+ break;
+ }
+ ctx->ios_ready_n += n_ev;
+ }
+
+ io_queue_release(ctx->aio);
+ }
+#endif /* DISABLE_AIO */
+
+#ifdef HAVE_LINUX_FALLOC_H
if (ctx->prior_size != (size_t)-1) {
+#else /* HAVE_LINUX_FALLOC_H */
+ if ((ctx->prior_size != (size_t)-1)&&((ctx->sync_mode)||(ctx->aio_mode))) {
+#endif /* HAVE_LINUX_FALLOC_H */
ftruncate(ctx->fd, ctx->prior_size + fw->written);
}
-#endif
close(ctx->fd);
}
@@ -194,10 +282,9 @@ int fastwriter_default_write(fastwriter_t *fw, fastwriter_write_flags_t flags, s
*written = 0;
return 0;
}
-
+
size -= size % ctx->wr_block;
}
-
if ((ctx->pa_block)&&((fw->written + size) > ctx->preallocated)) {
#ifdef HAVE_LINUX_FALLOC_H
@@ -211,27 +298,110 @@ int fastwriter_default_write(fastwriter_t *fw, fastwriter_write_flags_t flags, s
}
}
-#ifdef SYNC_MODE
// we expect this to happen only at last iteration (buffer is multiply of the required align)
- if ((ctx->sync_mode)&&(size%FASTWRITER_SYNCIO_ALIGN)) {
+ if (((ctx->aio_mode)||(ctx->sync_mode))&&(size%FASTWRITER_SYNCIO_ALIGN)) {
delta = FASTWRITER_SYNCIO_ALIGN - size%FASTWRITER_SYNCIO_ALIGN;
}
-#endif /* SYNC_MODE */
- do {
- res = write(ctx->fd, data + sum, size + delta - sum);
- if (res < 0) {
- *written = sum;
- return errno;
- }
+#ifndef DISABLE_AIO
+ if (ctx->aio_mode) {
+ int err;
+ size_t done = 0;
+ size_t sched = 0;
+
+ fastwriter_data_t *iodata;
+ struct iocb *newio;
+ size_t wr_block = ctx->wr_block;
+
+ do {
+ if (!ctx->ios_ready_n) {
+ int i, n_ev;
+ struct io_event ev[AIO_QUEUE_LENGTH];
+
+ n_ev = io_getevents(ctx->aio, 1, AIO_QUEUE_LENGTH, &ev[0], NULL);
+ if (n_ev <= 0) {
+ fprintf(stderr, "AIO io_getevents have failed (%i)", -n_ev);
+ return -n_ev;
+ }
+
+ for (i = 0; i < n_ev; i++) {
+ fastwriter_data_t *ev_data = (fastwriter_data_t *)(ev[i].data);
+ if ((ev[i].res2)||(ev[i].res < ev_data->size)) {
+ fprintf(stderr, "AIO write failed (res: %li, res2: %li, expected: %zu), no handling data will be corrupted...\n", ev[i].res, ev[i].res2, ev_data->size);
+ return -ev[i].res2;
+ }
+
+ ctx->ios_ready[ctx->ios_ready_n++] = ev_data->ios;
+// printf("Data: %i (ios %i)\n", ev_data->ready, ev_data->ios);
+ ev_data->ready = 2;
+ }
+
+ while (ctx->data[ctx->data_tail].ready > 1) {
+// printf("Done: %i %zu\n", ctx->data_tail, ctx->data[ctx->data_tail].offset);
+ ctx->data[ctx->data_tail].ready = 0;
+
+ done += ctx->data[ctx->data_tail].size;
+ if ((++ctx->data_tail) == AIO_BUFFERS) ctx->data_tail = 0;
+ }
+ }
+
+ if ((ctx->sched + sched) < size) {
+ if ((ctx->data_head == ctx->data_tail)&&(ctx->data[ctx->data_head].ready)) continue;
+
+ newio = (struct iocb*)&ctx->ios[ctx->ios_ready[--ctx->ios_ready_n]];
+ iodata = &ctx->data[ctx->data_head];
+
+ if (wr_block > ((size + delta) - (ctx->sched + sched))) {
+ wr_block = (size + delta) - (ctx->sched + sched);
+ if (wr_block % ctx->page_size) {
+ fprintf(stderr, "We need to write incomplete page (%zu bytes). This is no supported yet...\n", wr_block);
+ return -1;
+ }
+ }
+
+// printf("Sched: %lu => %lu (%lu) [tail %lu, head %lu]\n", ctx->sched + sched, ctx->fd_offset, wr_block, ctx->data_tail, ctx->data_head);
+
+ iodata->offset = ctx->fd_offset;
+ iodata->size = wr_block;
+ iodata->ios = ctx->ios_ready_n;
+
+ io_prep_pwrite(newio, ctx->fd, data + ctx->sched + sched, wr_block, ctx->fd_offset);
+ io_set_callback(newio, (void*)iodata);
+ err = io_submit(ctx->aio, 1, &newio);
+ if (err != 1) {
+ fprintf(stderr, "Error submiting AIO job (%i)\n", -err);
+ return -err;
+ }
+
+ iodata->ready = 1;
+ sched += wr_block;
+ ctx->fd_offset += wr_block;
+ if ((++ctx->data_head) == AIO_BUFFERS) ctx->data_head = 0;
+ }
+ } while (!done);
+
+ ctx->sched += sched - done;
+ size = done;
+ } else {
+#endif /* !DISABLE_AIO */
+ do {
+ res = write(ctx->fd, data + sum, size + delta - sum);
+ if (res < 0) {
+ *written = sum;
+ return errno;
+ }
- sum += res;
- } while (sum < size);
+ sum += res;
+ } while (sum < size);
+#ifndef DISABLE_AIO
+ }
+#endif /* !DISABLE_AIO */
+
+ if ((ctx->sync_mode)||(ctx->aio_mode)) {
+ posix_fadvise(ctx->fd, fw->written, size, POSIX_FADV_DONTNEED);
+ }
-#ifdef SYNC_MODE
- posix_fadvise(ctx->fd, fw->written, size, POSIX_FADV_DONTNEED);
-#endif /* SYNC_MODE */
-
*written = size;
+
return 0;
}
diff --git a/fastwriter.c b/fastwriter.c
index e812681..dd48493 100644
--- a/fastwriter.c
+++ b/fastwriter.c
@@ -15,11 +15,17 @@
#include <fcntl.h>
-
#include "private.h"
#include "default.h"
#include "sysinfo.h"
+#ifdef USE_CUSTOM_MEMCPY
+# include "memcpy.h"
+#else /* USE_CUSTOM_MEMCPY */
+# define fast_memcpy memcpy
+#endif /* USE_CUSTOM_MEMCPY */
+
+
fastwriter_t *fastwriter_init(const char *fs, fastwriter_flags_t flags) {
fastwriter_t *ctx;
@@ -58,8 +64,8 @@ int fastwriter_open(fastwriter_t *ctx, const char *name, fastwriter_flags_t flag
break;
case FASTWRITER_BUFFER_MAX:
ctx->size = fastwriter_get_free_memory();
-
- if ((ctx->size - FASTWRITER_RESERVE_MEMORY) < FASTWRITER_DEFAULT_BUFFER_SIZE)
+
+ if ((ctx->size == (size_t)-1)||((ctx->size - FASTWRITER_RESERVE_MEMORY) < FASTWRITER_DEFAULT_BUFFER_SIZE))
ctx->size = FASTWRITER_DEFAULT_BUFFER_SIZE;
else
ctx->size -= FASTWRITER_RESERVE_MEMORY;
@@ -275,11 +281,11 @@ int fastwriter_push(fastwriter_t *ctx, size_t size, const void *data) {
if (part1 < size) {
// tail < pos (we have checked for free space)
end = size - part1;
- memcpy(ctx->buffer + ctx->pos, data, part1);
- memcpy(ctx->buffer, data + part1, end);
+ fast_memcpy(ctx->buffer + ctx->pos, data, part1);
+ fast_memcpy(ctx->buffer, data + part1, end);
ctx->pos = end;
} else {
- memcpy(ctx->buffer + ctx->pos, data, size);
+ fast_memcpy(ctx->buffer + ctx->pos, data, size);
ctx->pos += size;
if (ctx->pos == ctx->size) ctx->pos = 0;
diff --git a/fastwriter.pc.in b/fastwriter.pc.in
index ceaa4d6..59a7a70 100644
--- a/fastwriter.pc.in
+++ b/fastwriter.pc.in
@@ -1,10 +1,10 @@
prefix=${CMAKE_INSTALL_PREFIX}
-exec_prefix=${BIN_INSTALL_DIR}
-libdir=${LIB_INSTALL_DIR}
-includedir=${INCLUDE_INSTALL_DIR}
+exec_prefix=${CMAKE_INSTALL_FULL_BINDIR}
+libdir=${CMAKE_INSTALL_FULL_LIBDIR}
+includedir=${CMAKE_INSTALL_FULL_INCLUDEDIR}
Name: ${TARNAME}
Description: Fast Streaming Storage Library
Version: ${PACKAGE_VERSION}
-Libs: -L${LIB_INSTALL_DIR} -lfastwriter
-Cflags: -I${INCLUDE_INSTALL_DIR}
+Libs: -L${CMAKE_INSTALL_FULL_LIBDIR} -lfastwriter
+Cflags: -I${CMAKE_INSTALL_FULL_INCLUDEDIR}
diff --git a/fastwriter.spec.in b/fastwriter.spec.in
new file mode 100644
index 0000000..680dbc3
--- /dev/null
+++ b/fastwriter.spec.in
@@ -0,0 +1,76 @@
+Summary: Fast data streaming library
+Name: ${PACKAGE_NAME}
+Version: ${CPACK_PACKAGE_VERSION}
+Release: csa
+License: GPL-3.0
+Group: Development/Libraries
+Source: ${CPACK_SOURCE_PACKAGE_FILE_NAME}.tar.bz2
+BuildRoot: %{_tmppath}/%{name}-%{version}-root
+URL: http://darksoft.org
+Prefix: %{_prefix}
+Docdir: %{_docdir}
+BuildRequires: xfsprogs-devel libuuid-devel
+BuildRequires: pkg-config libtool cmake
+Vendor: Institute for Data Processing and Electronics, KIT
+Packager: Suren A. Chilingaryan <csa@suren.me>
+
+%description
+Fast data streaming library (nothing goes here...)
+
+%package -n lib${PACKAGE_NAME}${FASTWRITER_ABI_VERSION}
+Summary: Fast data streaming library
+Group: Development/Libraries
+Provides: libfastwriter = %{version}
+Requires: xfsprogs
+
+%description -n lib${PACKAGE_NAME}${FASTWRITER_ABI_VERSION}
+Standard C storage routines are not efficient if a single, but fast stream of
+data have to be written on the disk. The fastwriter is optimized for this use
+case. The following methods are used to speed-up writting.
+ * Linux AIO is used to avoid intermediate file caches
+ * The large extents are pre-allocated and the file system is hinted that more
+ data will follow
+ * For XFS volumes, the real-time mode can be used
+
+
+%package -n lib${PACKAGE_NAME}-devel
+Summary: Fast data streaming library
+Group: Development/Libraries
+Requires: lib${PACKAGE_NAME}${FASTWRITER_ABI_VERSION} = %{version}
+
+%description -n lib${PACKAGE_NAME}-devel
+Development files for fastwriter
+
+
+%prep
+%setup -q
+
+%build
+cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBDIR=%{_libdir} -DCMAKE_INSTALL_BINDIR=%{_bindir} -DCMAKE_INSTALL_DATADIR=%{_datadir} -DCMAKE_INSTALL_DATAROOTDIR=%{_datadir} -DCMAKE_INSTALL_INCLUDEDIR=%{_includedir} -DCMAKE_BUILD_TYPE=Release .
+make
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make install DESTDIR=$RPM_BUILD_ROOT
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post -n lib${PACKAGE_NAME}${FASTWRITER_ABI_VERSION} -p /sbin/ldconfig
+
+%postun -n lib${PACKAGE_NAME}${FASTWRITER_ABI_VERSION} -p /sbin/ldconfig
+
+%files -n lib${PACKAGE_NAME}${FASTWRITER_ABI_VERSION}
+%defattr(-, root, root)
+%{_libdir}/lib${PACKAGE_NAME}.so.*
+
+%files -n lib${PACKAGE_NAME}-devel
+%defattr(-, root, root)
+%{_includedir}/*
+%{_libdir}/lib*.so
+%{_libdir}/pkgconfig/*.pc
+%exclude %{_libdir}/*.a
+
+%changelog
+* Fri Mar 4 2016 Suren A. Chilingaryan <csa@suren.me> - ${CPACK_PACKAGE_VERSION}
+- Added spec file to the sources
diff --git a/memcpy.c b/memcpy.c
new file mode 100644
index 0000000..5c29d01
--- /dev/null
+++ b/memcpy.c
@@ -0,0 +1,344 @@
+/********************************************************************
+ ** File: memcpy.c
+ **
+ ** Copyright (C) 1999-2010 Daniel Vik
+ **
+ ** This software is provided 'as-is', without any express or implied
+ ** warranty. In no event will the authors be held liable for any
+ ** damages arising from the use of this software.
+ ** Permission is granted to anyone to use this software for any
+ ** purpose, including commercial applications, and to alter it and
+ ** redistribute it freely, subject to the following restrictions:
+ **
+ ** 1. The origin of this software must not be misrepresented; you
+ ** must not claim that you wrote the original software. If you
+ ** use this software in a product, an acknowledgment in the
+ ** use this software in a product, an acknowledgment in the
+ ** product documentation would be appreciated but is not
+ ** required.
+ **
+ ** 2. Altered source versions must be plainly marked as such, and
+ ** must not be misrepresented as being the original software.
+ **
+ ** 3. This notice may not be removed or altered from any source
+ ** distribution.
+ **
+ **
+ ** Description: Implementation of the standard library function memcpy.
+ ** This implementation of memcpy() is ANSI-C89 compatible.
+ **
+ ** The following configuration options can be set:
+ **
+ ** LITTLE_ENDIAN - Uses processor with little endian
+ ** addressing. Default is big endian.
+ **
+ ** PRE_INC_PTRS - Use pre increment of pointers.
+ ** Default is post increment of
+ ** pointers.
+ **
+ ** INDEXED_COPY - Copying data using array indexing.
+ ** Using this option, disables the
+ ** PRE_INC_PTRS option.
+ **
+ ** MEMCPY_64BIT - Compiles memcpy for 64 bit
+ ** architectures
+ **
+ **
+ ** Best Settings:
+ **
+ ** Intel x86: LITTLE_ENDIAN and INDEXED_COPY
+ **
+ *******************************************************************/
+
+
+
+/********************************************************************
+ ** Configuration definitions.
+ *******************************************************************/
+
+#define LITTLE_ENDIAN
+#define INDEXED_COPY
+
+
+/********************************************************************
+ ** Includes for size_t definition
+ *******************************************************************/
+
+#include <stddef.h>
+
+
+/********************************************************************
+ ** Typedefs
+ *******************************************************************/
+
+typedef unsigned char UInt8;
+typedef unsigned short UInt16;
+typedef unsigned int UInt32;
+#ifdef _WIN32
+typedef unsigned __int64 UInt64;
+#else
+typedef unsigned long long UInt64;
+#endif
+
+#ifdef MEMCPY_64BIT
+typedef UInt64 UIntN;
+#define TYPE_WIDTH 8L
+#else
+typedef UInt32 UIntN;
+#define TYPE_WIDTH 4L
+#endif
+
+
+/********************************************************************
+ ** Remove definitions when INDEXED_COPY is defined.
+ *******************************************************************/
+
+#if defined (INDEXED_COPY)
+#if defined (PRE_INC_PTRS)
+#undef PRE_INC_PTRS
+#endif /*PRE_INC_PTRS*/
+#endif /*INDEXED_COPY*/
+
+
+
+/********************************************************************
+ ** Definitions for pre and post increment of pointers.
+ *******************************************************************/
+
+#if defined (PRE_INC_PTRS)
+
+#define START_VAL(x) (x)--
+#define INC_VAL(x) *++(x)
+#define CAST_TO_U8(p, o) ((UInt8*)p + o + TYPE_WIDTH)
+#define WHILE_DEST_BREAK (TYPE_WIDTH - 1)
+#define PRE_LOOP_ADJUST - (TYPE_WIDTH - 1)
+#define PRE_SWITCH_ADJUST + 1
+
+#else /*PRE_INC_PTRS*/
+
+#define START_VAL(x)
+#define INC_VAL(x) *(x)++
+#define CAST_TO_U8(p, o) ((UInt8*)p + o)
+#define WHILE_DEST_BREAK 0
+#define PRE_LOOP_ADJUST
+#define PRE_SWITCH_ADJUST
+
+#endif /*PRE_INC_PTRS*/
+
+
+
+/********************************************************************
+ ** Definitions for endians
+ *******************************************************************/
+
+#if defined (LITTLE_ENDIAN)
+
+#define SHL >>
+#define SHR <<
+
+#else /* LITTLE_ENDIAN */
+
+#define SHL <<
+#define SHR >>
+
+#endif /* LITTLE_ENDIAN */
+
+
+
+/********************************************************************
+ ** Macros for copying words of different alignment.
+ ** Uses incremening pointers.
+ *******************************************************************/
+
+#define CP_INCR() { \
+ INC_VAL(dstN) = INC_VAL(srcN); \
+}
+
+#define CP_INCR_SH(shl, shr) { \
+ dstWord = srcWord SHL shl; \
+ srcWord = INC_VAL(srcN); \
+ dstWord |= srcWord SHR shr; \
+ INC_VAL(dstN) = dstWord; \
+}
+
+
+
+/********************************************************************
+ ** Macros for copying words of different alignment.
+ ** Uses array indexes.
+ *******************************************************************/
+
+#define CP_INDEX(idx) { \
+ dstN[idx] = srcN[idx]; \
+}
+
+#define CP_INDEX_SH(x, shl, shr) { \
+ dstWord = srcWord SHL shl; \
+ srcWord = srcN[x]; \
+ dstWord |= srcWord SHR shr; \
+ dstN[x] = dstWord; \
+}
+
+
+
+/********************************************************************
+ ** Macros for copying words of different alignment.
+ ** Uses incremening pointers or array indexes depending on
+ ** configuration.
+ *******************************************************************/
+
+#if defined (INDEXED_COPY)
+
+#define CP(idx) CP_INDEX(idx)
+#define CP_SH(idx, shl, shr) CP_INDEX_SH(idx, shl, shr)
+
+#define INC_INDEX(p, o) ((p) += (o))
+
+#else /* INDEXED_COPY */
+
+#define CP(idx) CP_INCR()
+#define CP_SH(idx, shl, shr) CP_INCR_SH(shl, shr)
+
+#define INC_INDEX(p, o)
+
+#endif /* INDEXED_COPY */
+
+
+#define COPY_REMAINING(count) { \
+ START_VAL(dst8); \
+ START_VAL(src8); \
+ \
+ switch (count) { \
+ case 7: INC_VAL(dst8) = INC_VAL(src8); \
+ case 6: INC_VAL(dst8) = INC_VAL(src8); \
+ case 5: INC_VAL(dst8) = INC_VAL(src8); \
+ case 4: INC_VAL(dst8) = INC_VAL(src8); \
+ case 3: INC_VAL(dst8) = INC_VAL(src8); \
+ case 2: INC_VAL(dst8) = INC_VAL(src8); \
+ case 1: INC_VAL(dst8) = INC_VAL(src8); \
+ case 0: \
+ default: break; \
+ } \
+}
+
+#define COPY_NO_SHIFT() { \
+ UIntN* dstN = (UIntN*)(dst8 PRE_LOOP_ADJUST); \
+ UIntN* srcN = (UIntN*)(src8 PRE_LOOP_ADJUST); \
+ size_t length = count / TYPE_WIDTH; \
+ \
+ while (length & 7) { \
+ CP_INCR(); \
+ length--; \
+ } \
+ \
+ length /= 8; \
+ \
+ while (length--) { \
+ CP(0); \
+ CP(1); \
+ CP(2); \
+ CP(3); \
+ CP(4); \
+ CP(5); \
+ CP(6); \
+ CP(7); \
+ \
+ INC_INDEX(dstN, 8); \
+ INC_INDEX(srcN, 8); \
+ } \
+ \
+ src8 = CAST_TO_U8(srcN, 0); \
+ dst8 = CAST_TO_U8(dstN, 0); \
+ \
+ COPY_REMAINING(count & (TYPE_WIDTH - 1)); \
+ \
+ return dest; \
+}
+
+
+
+#define COPY_SHIFT(shift) { \
+ UIntN* dstN = (UIntN*)((((UIntN)dst8) PRE_LOOP_ADJUST) & \
+ ~(TYPE_WIDTH - 1)); \
+ UIntN* srcN = (UIntN*)((((UIntN)src8) PRE_LOOP_ADJUST) & \
+ ~(TYPE_WIDTH - 1)); \
+ size_t length = count / TYPE_WIDTH; \
+ UIntN srcWord = INC_VAL(srcN); \
+ UIntN dstWord; \
+ \
+ while (length & 7) { \
+ CP_INCR_SH(8 * shift, 8 * (TYPE_WIDTH - shift)); \
+ length--; \
+ } \
+ \
+ length /= 8; \
+ \
+ while (length--) { \
+ CP_SH(0, 8 * shift, 8 * (TYPE_WIDTH - shift)); \
+ CP_SH(1, 8 * shift, 8 * (TYPE_WIDTH - shift)); \
+ CP_SH(2, 8 * shift, 8 * (TYPE_WIDTH - shift)); \
+ CP_SH(3, 8 * shift, 8 * (TYPE_WIDTH - shift)); \
+ CP_SH(4, 8 * shift, 8 * (TYPE_WIDTH - shift)); \
+ CP_SH(5, 8 * shift, 8 * (TYPE_WIDTH - shift)); \
+ CP_SH(6, 8 * shift, 8 * (TYPE_WIDTH - shift)); \
+ CP_SH(7, 8 * shift, 8 * (TYPE_WIDTH - shift)); \
+ \
+ INC_INDEX(dstN, 8); \
+ INC_INDEX(srcN, 8); \
+ } \
+ \
+ src8 = CAST_TO_U8(srcN, (shift - TYPE_WIDTH)); \
+ dst8 = CAST_TO_U8(dstN, 0); \
+ \
+ COPY_REMAINING(count & (TYPE_WIDTH - 1)); \
+ \
+ return dest; \
+}
+
+
+/********************************************************************
+ **
+ ** void *memcpy(void *dest, const void *src, size_t count)
+ **
+ ** Args: dest - pointer to destination buffer
+ ** src - pointer to source buffer
+ ** count - number of bytes to copy
+ **
+ ** Return: A pointer to destination buffer
+ **
+ ** Purpose: Copies count bytes from src to dest.
+ ** No overlap check is performed.
+ **
+ *******************************************************************/
+
+void *fast_memcpy(void *dest, const void *src, size_t count)
+{
+ UInt8* dst8 = (UInt8*)dest;
+ UInt8* src8 = (UInt8*)src;
+
+ if (count < 8) {
+ COPY_REMAINING(count);
+ return dest;
+ }
+
+ START_VAL(dst8);
+ START_VAL(src8);
+
+ while (((UIntN)dst8 & (TYPE_WIDTH - 1)) != WHILE_DEST_BREAK) {
+ INC_VAL(dst8) = INC_VAL(src8);
+ count--;
+ }
+
+ switch ((((UIntN)src8) PRE_SWITCH_ADJUST) & (TYPE_WIDTH - 1)) {
+ case 0: COPY_NO_SHIFT(); break;
+ case 1: COPY_SHIFT(1); break;
+ case 2: COPY_SHIFT(2); break;
+ case 3: COPY_SHIFT(3); break;
+#if TYPE_WIDTH > 4
+ case 4: COPY_SHIFT(4); break;
+ case 5: COPY_SHIFT(5); break;
+ case 6: COPY_SHIFT(6); break;
+ case 7: COPY_SHIFT(7); break;
+#endif
+ }
+}
diff --git a/memcpy.h b/memcpy.h
new file mode 100644
index 0000000..0714823
--- /dev/null
+++ b/memcpy.h
@@ -0,0 +1,63 @@
+/********************************************************************
+ ** File: memcpy.h
+ **
+ ** Copyright (C) 2005 Daniel Vik
+ **
+ ** This software is provided 'as-is', without any express or implied
+ ** warranty. In no event will the authors be held liable for any
+ ** damages arising from the use of this software.
+ ** Permission is granted to anyone to use this software for any
+ ** purpose, including commercial applications, and to alter it and
+ ** redistribute it freely, subject to the following restrictions:
+ **
+ ** 1. The origin of this software must not be misrepresented; you
+ ** must not claim that you wrote the original software. If you
+ ** use this software in a product, an acknowledgment in the
+ ** use this software in a product, an acknowledgment in the
+ ** product documentation would be appreciated but is not
+ ** required.
+ **
+ ** 2. Altered source versions must be plainly marked as such, and
+ ** must not be misrepresented as being the original software.
+ **
+ ** 3. This notice may not be removed or altered from any source
+ ** distribution.
+ **
+ **
+ ** Description: Implementation of the standard library function memcpy.
+ ** This implementation of memcpy() is ANSI-C89 compatible.
+ **
+ *******************************************************************/
+
+
+/********************************************************************
+ ** Includes for size_t definition
+ *******************************************************************/
+
+#include <stddef.h>
+
+
+/********************************************************************
+ **
+ ** void *memcpy(void *dest, const void *src, size_t count)
+ **
+ ** Args: dest - pointer to destination buffer
+ ** src - pointer to source buffer
+ ** count - number of bytes to copy
+ **
+ ** Return: A pointer to destination buffer
+ **
+ ** Purpose: Copies count bytes from src to dest. No overlap check
+ ** is performed.
+ **
+ *******************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *fast_memcpy(void *dest, const void *src, size_t count);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/sysinfo.c b/sysinfo.c
index 52354e7..cde53d0 100644
--- a/sysinfo.c
+++ b/sysinfo.c
@@ -26,13 +26,13 @@
if ((fd = open(filename, O_RDONLY)) == -1) { \
fputs(BAD_OPEN_MESSAGE, stderr); \
fflush(NULL); \
- _exit(102); \
+ return -102; \
} \
lseek(fd, 0L, SEEK_SET); \
if ((local_n = read(fd, buf, sizeof buf - 1)) < 0) { \
perror(filename); \
fflush(NULL); \
- _exit(103); \
+ return -103; \
} \
buf[local_n] = '\0'; \
close(fd); \