update from v1.4.10 to v1.4.15

Signed-off-by: zhouhaifeng <kutcher.zhou@huawei.com>
This commit is contained in:
zhouhaifeng
2023-03-22 10:12:17 +08:00
parent ad7d94d213
commit d153aaad1e
111 changed files with 8911 additions and 2435 deletions
+13
View File
@@ -0,0 +1,13 @@
[*]
charset=utf-8
end_of_line=lf
insert_final_newline=false
trim_trailing_whitespace = true
indent_style=space
indent_size=2
[Makefile]
indent_style = tab
[*.{c,cpp,cc,h,hpp}]
insert_final_newline=true
+18
View File
@@ -0,0 +1,18 @@
cd ./build/src/utils/tests
#set args -c
set follow-fork-mode parent
set detach-on-fork on
set print elements 4096
define lb
set breakpoint pending on
source .breakpoints
set breakpoint pending auto
echo breakpoints loaded\n
end
define sb
save breakpoints .breakpoints
echo breakpoints saved\n
end
+117
View File
@@ -0,0 +1,117 @@
.cache
hints.txt
tmp/
git.diff
.vscode/.ropeproject
.vscode/ipch
.codelite/
.cmaketools.json
*.tags
*.dll
#iowow.project
#iowow.workspace
build/
cmake-build*
.cmake_dirty
Makefile
Testing/
compile_commands.json
iowow.mk
.tern*
*.iml
*.dat
*.fsm
*.db
# Created by https://www.gitignore.io/api/jetbrains
# Edit at https://www.gitignore.io/?templates=jetbrains
### JetBrains ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### JetBrains Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
# *.iml
# modules.xml
# .idea/misc.xml
# *.ipr
# Sonarlint plugin
.idea/**/sonarlint/
# SonarQube Plugin
.idea/**/sonarIssues.xml
# Markdown Navigator plugin
.idea/**/markdown-navigator.xml
.idea/**/markdown-navigator/
# End of https://www.gitignore.io/api/jetbrains
View File
+2
View File
@@ -0,0 +1,2 @@
mxe/
+25
View File
@@ -0,0 +1,25 @@
" Local vim rc
if exists('g:build_dir')
finish
endif
let g:build_type = get(g:, 'build_type', 'Debug')
let g:build_tests = get(g:, 'build_tests', 'ON')
let g:cc = get(g:, 'cc', 'clang')
let g:cxx = get(g:, 'cxx', 'clang++')
let g:root_dir = g:localvimrc_script_dir_unresolved
let $ROOT_DIR = g:root_dir
let $UNCRUSTIFY_CONFIG = g:root_dir.'/uncrustify.cfg'
let g:build_dir = g:root_dir.'/build'
let &g:makeprg = 'cd '.g:build_dir.' && make -j4'
packadd termdebug
let g:termdebug_wide=1
nnoremap <leader>c :call asyncrun#run('',
\ {'mode':'terminal','cwd':g:build_dir,'save':2},
\ 'cmake .. -DCMAKE_BUILD_TYPE='.g:build_type.' -DBUILD_TESTS='.g:build_tests.' -DCMAKE_CXX_COMPILER='.g:cxx.' -DCMAKE_C_COMPILER='.g:cc.' -DCMAKE_EXPORT_COMPILE_COMMANDS=ON')
\<CR>
+3
View File
@@ -99,10 +99,13 @@ ohos_shared_library("iowow") {
"src/utils/iwconv.c",
"src/utils/iwhmap.c",
"src/utils/iwpool.c",
"src/utils/iwrb.c",
"src/utils/iwre.c",
"src/utils/iwsha2.c",
"src/utils/iwstree.c",
"src/utils/iwstw.c",
"src/utils/iwth.c",
"src/utils/iwtp.c",
"src/utils/iwutils.c",
"src/utils/iwuuid.c",
"src/utils/iwxstr.c",
+3 -2
View File
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/")
include(CMakeToolsHelpers OPTIONAL)
@@ -121,8 +121,9 @@ if(CPACK_GENERATORS)
"\\\\.workspace$"
"\\\\.iml$"
"\\\\.mk$"
"\\\\.astylerc$"
"\\\\.editorconfig$"
"\\\\.astylerc$"
"uncrustify\\\\.cfg$"
"/Makefile$"
)
set(PROJECT_ARCH "${CMAKE_SYSTEM_PROCESSOR}")
+74 -1
View File
@@ -1,5 +1,78 @@
iowow (1.4.15) testing; urgency=medium
* Added format checking __attribute__ to all printf like functions.
-- Anton Adamansky <adamansky@gmail.com> Fri, 18 Feb 2022 21:54:04 +0700
iowow (1.4.14) testing; urgency=medium
* Used ftruncate() instead of posix_fallocate() due to EINVAL on ZFS (unix.c)
* Enable XOPEN_SOURCE only for linux
* Fixed incorrect selection of `strerror_r` for musl builds.
* Set appropriate _XOPEN_SOURCE=700 level for `nftw` (unix.c)
* iwxstr_printf() now conforms to stdlib printf function (iwxstr.h)
* Moved some useful defs from iwutil.h into basedefs.h
* Fixed iwre_match() function signatute allowing `const char* input`
(iwre.h)
* Added lightweight regexp implementation (iwre.h)
* Added `size_t iwxstr_asize(IWXSTR*)` (iwxstr.h)
* Added locale independed strtod: iwstrtod() (iwconv.h)
-- Anton Adamansky <adamansky@gmail.com> Mon, 14 Feb 2022 18:01:17 +0700
iowow (1.4.13) testing; urgency=medium
* Fixed SEGV in iwkv_cursor_open with zero-length key and IWDB_VNUM64_KEYS (#42)
* Fixed Heap UAF in iwkv_close after invoking iwkv_db_set_meta on a database (#41)
* Added `iwxstr_wrap()` (iwxstr.h)
* Added `RCT()` checker for pthread routines (basedefs.h)
* Added iwbin2hex() (iwconv.h)
* iwxstr_clear() sets value of intgernal string buffer to zero (iwxstr.h)
* Added user data store capability to iwxstr (iwxstr.h)
* Added iwpool_strdup2(), iwpool_strndup2() (iwpool.h)
* Added iwp_set_current_thread_name() (iwp.h)
* Added RCENO define (basedefs.h)
* Thread poll, single thread worker fixes
* Added IW_MIN, IW_MAX, IW_XSTR defines
-- Anton Adamansky <adamansky@gmail.com> Fri, 03 Sep 2021 16:03:05 +0700
iowow (1.4.12) testing; urgency=medium
* Added IW_ERROR_UNSUPPORTED error code
* Added IW_ALLOC __attribute__((malloc)) optimization
* Added ring buffer implementation (iwrb.h)
* Added `queue_blocking` argument `iwstw_start()` (iwstw.h)
* Minor changes in iwlog.h api
* `memcpy` replaced by `memmove` for overlaping cases (iwarr.c)
-- Anton Adamansky <adamansky@gmail.com> Mon, 19 Jul 2021 10:09:05 +0700
iowow (1.4.11) testing; urgency=medium
* Fixed typo (qsort_r => sort_r) (iwarr.c)
* Added simple threads pool implementation (iwtp.h)
* Added IW_ERROR_NOT_ALLOWED error code (iwlog.h)
* Added RCR() error checking macro (basedefs.h)
* Added iwlist_sort(), iwulist_sort() (iwarr.h)
* Added iwstw_schedule_empty_only() (iwstw.h)
* Added iwstw_queue_size() (iwstw.h)
* Set O_CLOEXEC flag on all file open() calls
* Added IW_ERROR_UNEXPECTED_RESPONSE error code (iwlog.h)
* Added iwxstr_set_size(), iwxstr_destroy_keep_ptr() (iwxstr.h)
* Added iwlist_at2() (iwarr.h)
* Added handy ZRET definition (basedefs.h)
* Added handy ZGO definition (basedefs.h)
* Project code reformatted using uncrustify
* Updated copyright headers
* Fixed build errors on macOS
* Removed dependency on glibc specific features
* Added new iwxstr_pop() (iwxstr.h)
-- Anton Adamansky <adamansky@gmail.com> Mon, 10 May 2021 16:43:52 +0700
iowow (1.4.10) testing; urgency=medium
* Fixed behavior of iwp_tmpdir() accourding to #47
* Tuned iwkv file resizing policy
* Fixed misuse of `IWKV_OPTS.file_lock_fail_fast` (#35)
* Correct handling of EINTR, EAGAIN in read/write functions (unix.c)
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+48
View File
@@ -66,6 +66,7 @@ Note:If the text contains special characters, please escape them according to th
<filefilter name="defaultPolicyFilter" desc="Filters for compatibilitylicense header policies">
<filteritem type="filepath" name="release.sh" desc="the header of the file is not license" />
<filteritem type="filepath" name="src/bindings/ejdb2_flutter/ios/ejdb2_flutter.podspec" desc="the header of the file is not license" />
<filteritem type="filepath" name="src/utils/iwre.c" desc="the header of the file is not license" />
</filefilter>
<filefilter name="copyrightPolicyFilter" desc="Filters for copyright header policies">
</filefilter>
@@ -156,6 +157,53 @@ Note:If the text contains special characters, please escape them according to th
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
desc=""/>
</licensematcher>
<licensematcher name="BSD-3-Clause" desc="">
<licensetext name="
Copyright (c) 2011, Willem-Hendrik Thiart
Copyright (c) 2012-2022 Softmotions Ltd &gt; info@softmotions.com &gt;
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* The names of its contributors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &gt; AS IS &gt; AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL WILLEM-HENDRIK THIART BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
desc=""/>
</licensematcher>
<licensematcher name="Khronos License" desc="">
<licensetext name="
Copyright (c) 2014 by Ian Piumarta
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the &gt;Software&gt;),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, provided that the above copyright notice(s) and this
permission notice appear in all copies of the Software. Acknowledgement
of the use of this Software in supporting documentation would be
appreciated but is not required.
THE SOFTWARE IS PROVIDED &gt;AS IS&gt;. USE ENTIRELY AT YOUR OWN RISK."
desc=""/>
</licensematcher>
</licensematcherlist>
</oatconfig>
</configuration>
+1 -1
View File
@@ -3,7 +3,7 @@
"Name": "IOWOW",
"License": "MIT License",
"License File": "LICENSE",
"Version Number": "v1.4.10",
"Version Number": "v1.4.15",
"Owner": "kutcher.zhou@huawei.com",
"Upstream URL": "https://github.com/Softmotions/iowow",
"Description": "The skiplist based persistent key/value storage engine"
+1 -2
View File
@@ -1,10 +1,9 @@
IOWOW - The C11 persistent key/value database engine based on [skip list](https://en.wikipedia.org/wiki/Skip_list)
==================================================================================================================
![Build Status](https://dev.softmotions.com/jenkins/buildStatus/icon?job=iowow_test)
[![Join ejdb2 telegram](https://img.shields.io/badge/join-ejdb2%20telegram-0088cc.svg)](https://t.me/ejdb2)
[![license](https://img.shields.io/github/license/Softmotions/ejdb.svg)](https://github.com/Softmotions/iowow/blob/master/LICENSE)
![Maintained](https://img.shields.io/maintenance/yes/2020.svg)
![Maintained](https://img.shields.io/maintenance/yes/2022.svg)
Website http://iowow.io
+18 -22
View File
@@ -1,24 +1,20 @@
# Find the CUnit headers and libraries
#
# CUNIT_INCLUDE_DIRS - The CUnit include directory (directory where CUnit/CUnit.h was found)
# CUNIT_LIBRARIES - The libraries needed to use CUnit
# CUNIT_FOUND - True if CUnit found in system
FIND_PATH(CUNIT_INCLUDE_DIR NAMES CUnit/CUnit.h)
MARK_AS_ADVANCED(CUNIT_INCLUDE_DIR)
FIND_LIBRARY(CUNIT_LIBRARY NAMES
cunit
libcunit
cunitlib
)
MARK_AS_ADVANCED(CUNIT_LIBRARY)
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(CUnit DEFAULT_MSG CUNIT_LIBRARY CUNIT_INCLUDE_DIR)
IF(CUNIT_FOUND)
SET(CUNIT_LIBRARIES ${CUNIT_LIBRARY})
SET(CUNIT_INCLUDE_DIRS ${CUNIT_INCLUDE_DIR})
ENDIF(CUNIT_FOUND)
# CUNIT_INCLUDE_DIRS - The CUnit include directory (directory where
# CUnit/CUnit.h was found) CUNIT_LIBRARIES - The libraries needed to use
# CUnit CUNIT_FOUND - True if CUnit found in system
find_path(CUNIT_INCLUDE_DIR NAMES CUnit/CUnit.h)
mark_as_advanced(CUNIT_INCLUDE_DIR)
find_library(CUNIT_LIBRARY NAMES cunit libcunit cunitlib)
mark_as_advanced(CUNIT_LIBRARY)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(CUnit DEFAULT_MSG CUNIT_LIBRARY
CUNIT_INCLUDE_DIR)
if(CUNIT_FOUND)
set(CUNIT_LIBRARIES ${CUNIT_LIBRARY})
set(CUNIT_INCLUDE_DIRS ${CUNIT_INCLUDE_DIR})
endif(CUNIT_FOUND)
+5
View File
@@ -0,0 +1,5 @@
#include <stdlib.h>
int main(int argc, char **argv) {
qsort_r(0, 0, 0, 0, 0);
return 0;
}
+7
View File
@@ -0,0 +1,7 @@
if (NOT DEFINED HAVE_QSORT_R)
try_compile(HAVE_QSORT_R
"${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/"
"${CMAKE_CURRENT_LIST_DIR}/TestQSortR.c")
endif()
+24
View File
@@ -0,0 +1,24 @@
# See https://github.com/richfelker/musl-cross-make
if(NOT MUSL_HOME)
set(MUSL_HOME $ENV{MUSL_HOME})
endif()
if(NOT MUSL_HOME)
message(FATAL_ERROR "Please setup MUSL_HOME environment variable")
endif()
set(MUSL_CFG x86_64-linux-musl)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR x86_64)
set(CROSS_HOST x86_64-unknown-linux)
set(CMAKE_FIND_ROOT_PATH "${MUSL_HOME}/${MUSL_CFG};${FIND_ROOT};${CMAKE_BINARY_DIR}")
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_C_COMPILER ${MUSL_HOME}/bin/${MUSL_CFG}-gcc)
set(CMAKE_CXX_COMPILER ${MUSL_HOME}/bin/${MUSL_CFG}-g++)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static")
+28 -2
View File
@@ -24,6 +24,7 @@ include(CheckIncludeFile)
include(CheckIncludeFiles)
include(CheckLibraryExists)
include(TestBigEndian)
include(TestQsortR)
if (OWNER_PROJECT_NAME)
set(IW_PUBLIC_HEADER_DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${OWNER_PROJECT_NAME}/${PROJECT_NAME})
@@ -40,6 +41,10 @@ if (IS_BIG_ENDIAN EQUAL 1)
add_definitions(-DIW_BIGENDIAN)
endif()
if (HAVE_QSORT_R)
add_definitions(-DIW_HAVE_QSORT_R)
endif()
if(CMAKE_SIZEOF_VOID_P MATCHES 8)
add_definitions(-DIW_64)
else()
@@ -106,6 +111,11 @@ if (HAVE_CLOCK_MONOTONIC)
add_definitions(-DIW_HAVE_CLOCK_MONOTONIC)
endif()
check_symbol_exists(basename_r libgen.h HAVE_BASENAME_R)
if (HAVE_BASENAME_R)
set_source_files_properties(log/iwlog.c PROPERTIES COMPILE_FLAGS -DIW_HAVE_BASENAME_R)
endif()
foreach(HF IN ITEMS stdlib stddef stdint stdbool stdatomic unistd dirent)
string(TOUPPER "${HF}" UHF)
check_include_file(${HF}.h "IW_HAVE_${UHF}")
@@ -114,9 +124,17 @@ foreach(HF IN ITEMS stdlib stddef stdint stdbool stdatomic unistd dirent)
endif()
endforeach(HF)
add_definitions(-D_GNU_SOURCE)
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
# Needed by Linux in order to use nftw() but fail to build on FreeBSD due to __BSD_VISIBLE define state.
add_definitions(-D_XOPEN_SOURCE=700)
endif()
add_definitions(-D_DEFAULT_SOURCE)
add_definitions(-D_LARGEFILE_SOURCE)
add_definitions(-D_FILE_OFFSET_BITS=64)
if(APPLE)
add_definitions(-D_DARWIN_C_SOURCE)
endif(APPLE)
list(APPEND ALL_SRC ${CMAKE_CURRENT_SOURCE_DIR}/iowow.c)
@@ -151,6 +169,9 @@ list(APPEND PUB_HDRS ${CMAKE_CURRENT_SOURCE_DIR}/basedefs.h
${CMAKE_CURRENT_SOURCE_DIR}/utils/iwuuid.h
${CMAKE_CURRENT_SOURCE_DIR}/utils/iwxstr.h
${CMAKE_CURRENT_SOURCE_DIR}/utils/murmur3.h
${CMAKE_CURRENT_SOURCE_DIR}/utils/iwtp.h
${CMAKE_CURRENT_SOURCE_DIR}/utils/iwrb.h
${CMAKE_CURRENT_SOURCE_DIR}/utils/iwre.h
)
list(REMOVE_DUPLICATES PROJECT_LLIBRARIES)
@@ -199,7 +220,12 @@ file(GLOB PROJECT_GENERATED_HDRS ${PROJECT_GENERATED_DIR}/*.h)
list(APPEND ALL_HDRS ${PROJECT_GENERATED_HDRS})
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tmpl/libiowow.pc.in ${PROJECT_GENERATED_DIR}/libiowow.pc @ONLY)
install(FILES ${PROJECT_GENERATED_DIR}/libiowow.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
if (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
install(FILES ${PROJECT_GENERATED_DIR}/libiowow.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}data/pkgconfig)
else()
install(FILES ${PROJECT_GENERATED_DIR}/libiowow.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
endif()
foreach(MODULE IN LISTS MODULES)
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE}/CMakeLists.txt)
+186 -7
View File
@@ -6,7 +6,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -35,12 +35,19 @@
#ifdef __cplusplus
#define IW_EXTERN_C_START extern "C" {
#define IW_EXTERN_C_END }
#define IW_EXTERN_C_END }
#else
#define IW_EXTERN_C_START
#define IW_EXTERN_C_END
#endif
#define IW_XSTR(s) IW_STR(s)
#define IW_STR(s) #s
#define IW_MAX(X__, Y__) ({ __typeof__(X__) x = (X__); __typeof__(Y__) y = (Y__); x < y ? y : x; })
#define IW_MIN(X__, Y__) ({ __typeof__(X__) x = (X__); __typeof__(Y__) y = (Y__); x < y ? x : y; })
#define IW_LLEN(L__) (sizeof(L__) - 1)
#if (defined(_WIN32) || defined(_WIN64))
#if (defined(IW_NODLL) || defined(IW_STATIC))
#define IW_EXPORT
@@ -68,13 +75,15 @@
#define IW_SOFT_INLINE static inline
#if __GNUC__ >= 4
#define WUR __attribute__((__warn_unused_result__))
#define WUR __attribute__((__warn_unused_result__))
#define IW_ALLOC __attribute__((malloc)) __attribute__((warn_unused_result))
#else
#define WUR
#define IW_ALLOC
#endif
#define IW_ARR_STATIC static
#define IW_ARR_CONST const
#define IW_ARR_CONST const
#ifdef _WIN32
#include <windows.h>
@@ -98,6 +107,16 @@ typedef int HANDLE;
#define IW_LINE_SEP "\n"
#endif
#define ZGO(label__, val__) \
({ __typeof__(val__) v__ = (val__); \
if (!v__) goto label__; \
v__; })
#define ZRET(ret__, val__) \
({ __typeof__(val__) v__ = (val__); \
if (!v__) return ret__; \
v__; })
#ifdef __GNUC__
#define RCGO(rc__, label__) if (__builtin_expect((!!(rc__)), 0)) goto label__
#else
@@ -110,16 +129,16 @@ typedef int HANDLE;
goto label__; \
}
#define RCHECK(rc__, label__, expr__) \
#define RCHECK(rc__, label__, expr__) \
rc__ = expr__; \
RCGO(rc__, label__)
#define RCC(rc__, label__, expr__) RCHECK(rc__, label__, expr__)
#define RCC(rc__, label__, expr__) RCHECK(rc__, label__, expr__)
#ifndef RCGA
#define RCGA(v__, label__) \
if (!(v__)) { \
rc = iwrc_set_errno(IW_ERROR_ALLOC, errno); \
rc = iwrc_set_errno(IW_ERROR_ALLOC, errno); \
goto label__; \
}
#endif
@@ -128,12 +147,37 @@ typedef int HANDLE;
#define RCA(v__, label__) RCGA(v__, label__)
#endif
#ifndef RCB
#define RCB(label__, v__) RCGA(v__, label__)
#endif
#ifndef RCN
#define RCN(label__, v__) \
if ((v__) < 0) { \
rc = iwrc_set_errno(IW_ERROR_ERRNO, errno); \
goto label__; \
}
#endif
#ifndef RCT
#define RCT(label__, val__) \
({ __typeof__(val__) v__ = (val__); \
if (v__) { \
rc = iwrc_set_errno(IW_ERROR_THREADING_ERRNO, v__); \
goto label__; \
} \
})
#endif
#ifdef __GNUC__
#define RCRET(rc__) if (__builtin_expect((!!(rc__)), 0)) return (rc__)
#else
#define RCRET(rc__) if (rc__) return (rc__)
#endif
#define RCR(expr__) \
({ iwrc rc__ = (expr__); RCRET(rc__); 0; })
#ifdef __GNUC__
#define RCBREAK(rc__) if (__builtin_expect((!!(rc__)), 0)) break
#else
@@ -154,9 +198,144 @@ typedef int HANDLE;
#define MAX(a_, b_) ((a_) > (b_) ? (a_) : (b_))
#endif
/* Align x_ with v_. v_ must be simple power for 2 value. */
#define IW_ROUNDUP(x_, v_) (((x_) + (v_) - 1) & ~((v_) - 1))
/* Round down align x_ with v_. v_ must be simple power for 2 value. */
#define IW_ROUNDOWN(x_, v_) ((x_) - ((x_) & ((v_) - 1)))
#ifdef __GNUC__
#define IW_LIKELY(x_) __builtin_expect(!!(x_), 1)
#define IW_UNLIKELY(x_) __builtin_expect(!!(x_), 0)
#else
#define IW_LIKELY(x_)
#define IW_UNLIKELY(x_)
#endif
#if defined(NDEBUG)
#define IW_DODEBUG(IW_expr_) \
do { \
} while (0)
#else
#define IW_DODEBUG(IW_expr_) \
{ IW_expr_; }
#endif
#if __GNUC__ >= 5
#define IW_SWAB16(num_) __builtin_bswap16(num_)
#else
#define IW_SWAB16(num_) \
((((num_) & 0x00ffU) << 8) | (((num_) & 0xff00U) >> 8))
#endif
#if __GNUC__ >= 4
#define IW_SWAB32(num_) __builtin_bswap32(num_)
#else
#define IW_SWAB32(num_) \
((((num_) & 0x000000ffUL) << 24) | (((num_) & 0x0000ff00UL) << 8) \
| (((num_) & 0x00ff0000UL) >> 8) | (((num_) & 0xff000000UL) >> 24))
#endif
#if __GNUC__ >= 4
#define IW_SWAB64(num_) __builtin_bswap64(num_)
#else
#define IW_SWAB64(num_) \
((((num_) & 0x00000000000000ffULL) << 56) \
| (((num_) & 0x000000000000ff00ULL) << 40) \
| (((num_) & 0x0000000000ff0000ULL) << 24) \
| (((num_) & 0x00000000ff000000ULL) << 8) \
| (((num_) & 0x000000ff00000000ULL) >> 8) \
| (((num_) & 0x0000ff0000000000ULL) >> 24) \
| (((num_) & 0x00ff000000000000ULL) >> 40) \
| (((num_) & 0xff00000000000000ULL) >> 56))
#endif
#ifdef IW_BIGENDIAN
#define IW_HTOIS(num_) IW_SWAB16(num_)
#define IW_HTOIL(num_) IW_SWAB32(num_)
#define IW_HTOILL(num_) IW_SWAB64(num_)
#define IW_ITOHS(num_) IW_SWAB16(num_)
#define IW_ITOHL(num_) IW_SWAB32(num_)
#define IW_ITOHLL(num_) IW_SWAB64(num_)
#else
#define IW_HTOIS(num_) (num_)
#define IW_HTOIL(num_) (num_)
#define IW_HTOILL(num_) (num_)
#define IW_ITOHS(num_) (num_)
#define IW_ITOHL(num_) (num_)
#define IW_ITOHLL(num_) (num_)
#endif
#define IW_WRITEBV(ptr_, v_, m_) \
static_assert(sizeof(v_) == 1, "Mismatch v_ size"); \
(v_) = (m_); \
memcpy(ptr_, &(v_), 1); \
(ptr_) += 1
#define IW_WRITESV(ptr_, v_, m_) \
static_assert(sizeof(v_) == 2, "Mismatch v_ size"); \
(v_) = (m_); \
(v_) = IW_HTOIS(v_); \
memcpy(ptr_, &(v_), 2); \
(ptr_) += 2
#define IW_WRITELV(ptr_, v_, m_) \
static_assert(sizeof(v_) == 4, "Mismatch v_ size"); \
(v_) = (m_); \
(v_) = IW_HTOIL(v_); \
memcpy(ptr_, &(v_), 4); \
(ptr_) += 4
#define IW_WRITELLV(ptr_, v_, m_) \
static_assert(sizeof(v_) == 8, "Mismatch v_ size"); \
(v_) = (m_); \
(v_) = IW_HTOILL(v_); \
memcpy((ptr_), &(v_), 8); \
(ptr_) += 8
#define IW_READBV(ptr_, t_, m_) \
static_assert(sizeof(t_) == 1, "Mismatch t_ size"); \
(t_) = 0; \
memcpy(&(t_), ptr_, 1); \
(m_) = (t_); \
(ptr_) += 1
#define IW_READSV(ptr_, t_, m_) \
static_assert(sizeof(t_) == 2, "Mismatch t_ size"); \
(t_) = 0; \
memcpy(&(t_), ptr_, 2); \
(m_) = IW_ITOHS(t_); \
(ptr_) += 2
#define IW_READLV(ptr_, t_, m_) \
static_assert(sizeof(t_) == 4, "Mismatch t_ size"); \
(t_) = 0; \
memcpy(&(t_), ptr_, 4); \
(m_) = IW_ITOHL(t_); \
(ptr_) += 4
#define IW_READLLV(ptr_, t_, m_) \
static_assert(sizeof(t_) == 8, "Mismatch t_ size"); \
(t_) = 0; \
memcpy(&(t_), ptr_, 8); \
(m_) = IW_ITOHLL(t_); \
(ptr_) += 8
#ifndef SIZE_T_MAX
#define SIZE_T_MAX ((size_t) -1)
#endif
#ifndef OFF_T_MIN
#define OFF_T_MIN ((off_t) (((uint64_t) 1) << (8 * sizeof(off_t) - 1)))
#endif
#ifndef OFF_T_MAX
#define OFF_T_MAX ((off_t) ~(((uint64_t) 1) << (8 * sizeof(off_t) - 1)))
#endif
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <sys/types.h>
#ifdef _WIN32
typedef _locale_t locale_t;
+7 -8
View File
@@ -18,27 +18,27 @@ typedef struct IWDLSNR {
* @param path File path
* @param mode File open mode same as in open(2)
*/
iwrc(*onopen)(struct IWDLSNR *self, const char *path, int mode);
iwrc (*onopen)(struct IWDLSNR *self, const char *path, int mode);
/**
* @brief Before file been closed.
*/
iwrc(*onclosing)(struct IWDLSNR *self);
iwrc (*onclosing)(struct IWDLSNR *self);
/**
* @brief Write @a val value starting at @a off @a len bytes
*/
iwrc(*onset)(struct IWDLSNR *self, off_t off, uint8_t val, off_t len, int flags);
iwrc (*onset)(struct IWDLSNR *self, off_t off, uint8_t val, off_t len, int flags);
/**
* @brief Copy @a len bytes from @a off offset to @a noff offset
*/
iwrc(*oncopy)(struct IWDLSNR *self, off_t off, off_t len, off_t noff, int flags);
iwrc (*oncopy)(struct IWDLSNR *self, off_t off, off_t len, off_t noff, int flags);
/**
* @brief Write @buf of @a len bytes at @a off
*/
iwrc(*onwrite)(struct IWDLSNR *self, off_t off, const void *buf, off_t len, int flags);
iwrc (*onwrite)(struct IWDLSNR *self, off_t off, const void *buf, off_t len, int flags);
/**
* @brief File need to be resized.
@@ -47,13 +47,12 @@ typedef struct IWDLSNR {
* @param nsize New file size
* @param [out] handled File resizing handled by llistener.
*/
iwrc(*onresize)(struct IWDLSNR *self, off_t osize, off_t nsize, int flags, bool *handled);
iwrc (*onresize)(struct IWDLSNR *self, off_t osize, off_t nsize, int flags, bool *handled);
/**
* @brief File sync successful
*/
iwrc(*onsynced)(struct IWDLSNR *self, int flags);
iwrc (*onsynced)(struct IWDLSNR *self, int flags);
} IWDLSNR;
IW_EXTERN_C_END
+67 -52
View File
@@ -3,7 +3,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -39,35 +39,37 @@
struct MMAPSLOT;
typedef struct IWFS_EXT_IMPL {
IWFS_FILE file; /**< Underlying file */
IWDLSNR *dlsnr; /**< Data events listener */
IWDLSNR *dlsnr; /**< Data events listener */
pthread_rwlock_t *rwlock; /**< Thread RW lock */
struct MMAPSLOT *mmslots; /**< Memory mapping slots */
struct MMAPSLOT *mmslots; /**< Memory mapping slots */
void *rspolicy_ctx; /**< Custom opaque data for policy functions */
IW_EXT_RSPOLICY rspolicy; /**< File resize policy function ptr */
uint64_t fsize; /**< Current file size */
uint64_t maxoff; /**< Maximum allowed file offset. Unlimited if zero.
If maximum offset is reached `IWFS_ERROR_MAXOFF` will be reported. */
size_t psize; /**< System page size */
HANDLE fh; /**< File handle */
size_t psize; /**< System page size */
HANDLE fh; /**< File handle */
iwfs_omode omode; /**< File open mode */
bool use_locks; /**< Use rwlocks to guard method access */
bool use_locks; /**< Use rwlocks to guard method access */
} EXF;
typedef struct MMAPSLOT {
off_t off; /**< Offset to a memory mapped region */
off_t off; /**< Offset to a memory mapped region */
size_t len; /**< Actual size of memory mapped region. */
size_t maxlen; /**< Maximum length of memory mapped region */
iwfs_ext_mmap_opts_t mmopts;
struct MMAPSLOT *prev; /**< Previous mmap slot. */
struct MMAPSLOT *next; /**< Next mmap slot. */
uint8_t *mmap; /**< Pointer to a mmaped address space
in the case if file data is memory mapped. */
struct MMAPSLOT *prev; /**< Previous mmap slot. */
struct MMAPSLOT *next; /**< Next mmap slot. */
uint8_t *mmap; /**< Pointer to a mmaped address space
in the case if file data is memory mapped. */
} MMAPSLOT;
IW_INLINE iwrc _exfile_wlock(IWFS_EXT *f) {
struct IWFS_EXT_IMPL *impl = f->impl;
if (impl) {
if (!impl->use_locks) return 0;
if (!impl->use_locks) {
return 0;
}
if (impl->rwlock) {
int rv = pthread_rwlock_wrlock(impl->rwlock);
return rv ? iwrc_set_errno(IW_ERROR_THREADING_ERRNO, rv) : 0;
@@ -79,7 +81,9 @@ IW_INLINE iwrc _exfile_wlock(IWFS_EXT *f) {
IW_INLINE iwrc _exfile_rlock(IWFS_EXT *f) {
struct IWFS_EXT_IMPL *impl = f->impl;
if (impl) {
if (!impl->use_locks) return 0;
if (!impl->use_locks) {
return 0;
}
if (impl->rwlock) {
int rv = pthread_rwlock_rdlock(impl->rwlock);
return rv ? iwrc_set_errno(IW_ERROR_THREADING_ERRNO, rv) : 0;
@@ -91,7 +95,9 @@ IW_INLINE iwrc _exfile_rlock(IWFS_EXT *f) {
IW_INLINE iwrc _exfile_unlock(IWFS_EXT *f) {
struct IWFS_EXT_IMPL *impl = f->impl;
if (impl) {
if (!impl->use_locks) return 0;
if (!impl->use_locks) {
return 0;
}
if (impl->rwlock) {
int rv = pthread_rwlock_unlock(impl->rwlock);
return rv ? iwrc_set_errno(IW_ERROR_THREADING_ERRNO, rv) : 0;
@@ -102,7 +108,9 @@ IW_INLINE iwrc _exfile_unlock(IWFS_EXT *f) {
IW_INLINE iwrc _exfile_unlock2(EXF *impl) {
if (impl) {
if (!impl->use_locks) return 0;
if (!impl->use_locks) {
return 0;
}
if (impl->rwlock) {
int rv = pthread_rwlock_unlock(impl->rwlock);
return rv ? iwrc_set_errno(IW_ERROR_THREADING_ERRNO, rv) : 0;
@@ -112,8 +120,12 @@ IW_INLINE iwrc _exfile_unlock2(EXF *impl) {
}
static iwrc _exfile_destroylocks(EXF *impl) {
if (!impl) return IW_ERROR_INVALID_STATE;
if (!impl->rwlock) return 0;
if (!impl) {
return IW_ERROR_INVALID_STATE;
}
if (!impl->rwlock) {
return 0;
}
int rv = pthread_rwlock_destroy(impl->rwlock);
free(impl->rwlock);
impl->rwlock = 0;
@@ -134,7 +146,7 @@ static iwrc _exfile_initmmap_slot_lw(struct IWFS_EXT *f, MMAPSLOT *s) {
}
if (s->len) { // unmap me first
assert(s->mmap);
if (!(s->mmopts & IWFS_MMAP_PRIVATE) && msync(s->mmap, s->len, 0) == -1) {
if (!(s->mmopts & IWFS_MMAP_PRIVATE) && (msync(s->mmap, s->len, 0) == -1)) {
s->len = 0;
return iwrc_set_errno(IW_ERROR_ERRNO, errno);
}
@@ -160,6 +172,9 @@ static iwrc _exfile_initmmap_slot_lw(struct IWFS_EXT *f, MMAPSLOT *s) {
iwlog_ecode_error3(rc);
return rc;
}
#ifdef MADV_DONTFORK
madvise(s->mmap, s->len, MADV_DONTFORK);
#endif
}
return 0;
}
@@ -197,7 +212,7 @@ static iwrc _exfile_truncate_lw(struct IWFS_EXT *f, off_t size) {
if (!(omode & IWFS_OWRITE)) {
return IW_ERROR_READONLY;
}
if (impl->maxoff && size > impl->maxoff) {
if (impl->maxoff && (size > impl->maxoff)) {
return IWFS_ERROR_MAXOFF;
}
if (impl->dlsnr) {
@@ -241,10 +256,10 @@ static iwrc _exfile_ensure_size_lw(struct IWFS_EXT *f, off_t sz) {
return 0;
}
off_t nsz = impl->rspolicy(sz, impl->fsize, f, &impl->rspolicy_ctx);
if (nsz < sz || ((uint64_t) nsz & (impl->psize - 1))) {
if ((nsz < sz) || ((uint64_t) nsz & (impl->psize - 1))) {
return IWFS_ERROR_RESIZE_POLICY_FAIL;
}
if (impl->maxoff && nsz > impl->maxoff) {
if (impl->maxoff && (nsz > impl->maxoff)) {
nsz = impl->maxoff;
if (nsz < sz) {
return IWFS_ERROR_MAXOFF;
@@ -260,9 +275,9 @@ static iwrc _exfile_sync(struct IWFS_EXT *f, iwfs_sync_flags flags) {
int mflags = MS_SYNC;
MMAPSLOT *s = impl->mmslots;
while (s) {
if (s->mmap && s->mmap != MAP_FAILED
&& !(s->mmopts & IWFS_MMAP_PRIVATE)
&& msync(s->mmap, s->len, mflags) == -1) {
if ( s->mmap && (s->mmap != MAP_FAILED)
&& !(s->mmopts & IWFS_MMAP_PRIVATE)
&& (msync(s->mmap, s->len, mflags) == -1)) {
rc = iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
}
s = s->next;
@@ -279,10 +294,10 @@ static iwrc _exfile_write(struct IWFS_EXT *f, off_t off, const void *buf, size_t
off_t wp = siz, len;
*sp = 0;
if (off < 0 || end < 0) {
if ((off < 0) || (end < 0)) {
return IW_ERROR_OUT_OF_BOUNDS;
}
if (impl->maxoff && off + siz > impl->maxoff) {
if (impl->maxoff && (off + siz > impl->maxoff)) {
return IWFS_ERROR_MAXOFF;
}
iwrc rc = _exfile_rlock(f);
@@ -299,30 +314,30 @@ static iwrc _exfile_write(struct IWFS_EXT *f, off_t off, const void *buf, size_t
}
s = impl->mmslots;
while (s && wp > 0) {
if (!s->len || wp + off <= s->off) {
if (!s->len || (wp + off <= s->off)) {
break;
}
if (s->off > off) {
len = MIN(wp, s->off - off);
rc = impl->file.write(&impl->file, off, (const char *) buf + (siz - wp), (size_t) len, sp);
rc = impl->file.write(&impl->file, off, (const char*) buf + (siz - wp), (size_t) len, sp);
RCGO(rc, finish);
wp = wp - *sp;
off = off + *sp;
}
if (wp > 0 && s->off <= off && s->off + s->len > off) {
if ((wp > 0) && (s->off <= off) && (s->off + s->len > off)) {
len = MIN(wp, s->off + s->len - off);
if (impl->dlsnr) {
rc = impl->dlsnr->onwrite(impl->dlsnr, off - s->off, (const char *) buf + (siz - wp), len, 0);
rc = impl->dlsnr->onwrite(impl->dlsnr, off - s->off, (const char*) buf + (siz - wp), len, 0);
RCGO(rc, finish);
}
memcpy(s->mmap + (off - s->off), (const char *) buf + (siz - wp), (size_t) len);
memcpy(s->mmap + (off - s->off), (const char*) buf + (siz - wp), (size_t) len);
wp -= len;
off += len;
}
s = s->next;
}
if (wp > 0) {
rc = impl->file.write(&impl->file, off, (const char *) buf + (siz - wp), (size_t) wp, sp);
rc = impl->file.write(&impl->file, off, (const char*) buf + (siz - wp), (size_t) wp, sp);
RCGO(rc, finish);
wp = wp - *sp;
}
@@ -342,7 +357,7 @@ static iwrc _exfile_read(struct IWFS_EXT *f, off_t off, void *buf, size_t siz, s
off_t end = off + siz;
off_t rp = siz, len;
*sp = 0;
if (off < 0 || end < 0) {
if ((off < 0) || (end < 0)) {
return IW_ERROR_OUT_OF_BOUNDS;
}
iwrc rc = _exfile_rlock(f);
@@ -350,30 +365,30 @@ static iwrc _exfile_read(struct IWFS_EXT *f, off_t off, void *buf, size_t siz, s
impl = f->impl;
s = impl->mmslots;
if (end > impl->fsize) {
siz = (size_t)(impl->fsize - off);
siz = (size_t) (impl->fsize - off);
rp = siz;
}
while (s && rp > 0) {
if (!s->len || rp + off <= s->off) {
if (!s->len || (rp + off <= s->off)) {
break;
}
if (s->off > off) {
len = MIN(rp, s->off - off);
rc = impl->file.read(&impl->file, off, (char *) buf + (siz - rp), (size_t) len, sp);
rc = impl->file.read(&impl->file, off, (char*) buf + (siz - rp), (size_t) len, sp);
RCGO(rc, finish);
rp = rp - *sp;
off = off + *sp;
}
if (rp > 0 && s->off <= off && s->off + s->len > off) {
if ((rp > 0) && (s->off <= off) && (s->off + s->len > off)) {
len = MIN(rp, s->off + s->len - off);
memcpy((char *) buf + (siz - rp), s->mmap + (off - s->off), (size_t) len);
memcpy((char*) buf + (siz - rp), s->mmap + (off - s->off), (size_t) len);
rp -= len;
off += len;
}
s = s->next;
}
if (rp > 0) {
rc = impl->file.read(&impl->file, off, (char *) buf + (siz - rp), (size_t) rp, sp);
rc = impl->file.read(&impl->file, off, (char*) buf + (siz - rp), (size_t) rp, sp);
RCGO(rc, finish);
rp = rp - *sp;
}
@@ -401,7 +416,7 @@ static iwrc _exfile_copy(struct IWFS_EXT *f, off_t off, size_t siz, off_t noff)
RCRET(rc);
EXF *impl = f->impl;
MMAPSLOT *s = impl->mmslots;
if (s && s->mmap && s->off == 0 && s->len >= noff + siz) { // fully mmaped file
if (s && s->mmap && (s->off == 0) && (s->len >= noff + siz)) { // fully mmaped file
rc = _exfile_ensure_size_lw(f, noff + siz);
RCRET(rc);
if (impl->dlsnr) {
@@ -514,10 +529,10 @@ static iwrc _exfile_add_mmap_lw(struct IWFS_EXT *f, off_t off, size_t maxlen, iw
goto finish;
}
if (OFF_T_MAX - off < maxlen) {
maxlen = (size_t)(OFF_T_MAX - off);
maxlen = (size_t) (OFF_T_MAX - off);
}
tmp = IW_ROUNDUP(maxlen, impl->psize);
if (tmp < maxlen || OFF_T_MAX - off < tmp) {
if ((tmp < maxlen) || (OFF_T_MAX - off < tmp)) {
maxlen = IW_ROUNDOWN(maxlen, impl->psize);
} else {
maxlen = tmp;
@@ -688,9 +703,9 @@ static iwrc _exfile_sync_mmap_lr(struct IWFS_EXT *f, off_t off, iwfs_sync_flags
rc = IWFS_ERROR_NOT_MMAPED;
break;
}
if (s->mmap && s->mmap != MAP_FAILED) {
if (!(s->mmopts & IWFS_MMAP_PRIVATE)
&& msync(s->mmap, s->len, mflags) == -1) {
if (s->mmap && (s->mmap != MAP_FAILED)) {
if ( !(s->mmopts & IWFS_MMAP_PRIVATE)
&& (msync(s->mmap, s->len, mflags) == -1)) {
rc = iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
}
break;
@@ -760,7 +775,7 @@ off_t iw_exfile_szpolicy_mul(off_t nsize, off_t csize, struct IWFS_EXT *f, void
if (nsize == -1) {
return 0;
}
if (!mul || !mul->dn || mul->n < mul->dn) {
if (!mul || !mul->dn || (mul->n < mul->dn)) {
iwlog_error2(
"Invalid iw_exfile_szpolicy_mul context arguments, fallback to the "
"default resize policy");
@@ -787,7 +802,7 @@ static iwrc _exfile_initlocks(IWFS_EXT *f) {
if (!impl->rwlock) {
return iwrc_set_errno(IW_ERROR_ALLOC, errno);
}
int rv = pthread_rwlock_init(impl->rwlock, (void *) 0);
int rv = pthread_rwlock_init(impl->rwlock, (void*) 0);
if (rv) {
free(impl->rwlock);
impl->rwlock = 0;
@@ -812,7 +827,7 @@ iwrc iwfs_exfile_open(IWFS_EXT *f, const IWFS_EXT_OPTS *opts) {
f->write = _exfile_write;
f->sync = _exfile_sync;
f->state = _exfile_state;
f->copy = _exfile_copy;
f->copy = _exfile_copy;
f->ensure_size = _exfile_ensure_size;
@@ -886,13 +901,13 @@ finish:
return rc;
}
static const char *_exfile_ecodefn(locale_t locale, uint32_t ecode) {
if (!(ecode > _IWFS_EXT_ERROR_START && ecode < _IWFS_EXT_ERROR_END)) {
static const char* _exfile_ecodefn(locale_t locale, uint32_t ecode) {
if (!((ecode > _IWFS_EXT_ERROR_START) && (ecode < _IWFS_EXT_ERROR_END))) {
return 0;
}
switch (ecode) {
case IWFS_ERROR_MMAP_OVERLAP:
return "Region is mmaped already, mmaping overlaps. "
case IWFS_ERROR_MMAP_OVERLAP
: return "Region is mmaped already, mmaping overlaps. "
"(IWFS_ERROR_MMAP_OVERLAP)";
case IWFS_ERROR_NOT_MMAPED:
return "Region is not mmaped. (IWFS_ERROR_NOT_MMAPED)";
+37 -33
View File
@@ -7,7 +7,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -79,12 +79,12 @@ typedef enum {
IWFS_ERROR_NOT_MMAPED, /**< Region is not mmaped */
IWFS_ERROR_RESIZE_POLICY_FAIL, /**< Invalid result of resize policy function.*/
IWFS_ERROR_MAXOFF, /**< Maximum file offset reached. */
_IWFS_EXT_ERROR_END
_IWFS_EXT_ERROR_END,
} iwfs_ext_ecode;
typedef uint8_t iwfs_ext_mmap_opts_t;
/** Use shared mmaping synchronized with file data */
#define IWFS_MMAP_SHARED ((iwfs_ext_mmap_opts_t) 0x00U)
#define IWFS_MMAP_SHARED ((iwfs_ext_mmap_opts_t) 0x00U)
/** Use private mmap */
#define IWFS_MMAP_PRIVATE ((iwfs_ext_mmap_opts_t) 0x01U)
@@ -107,24 +107,27 @@ typedef uint8_t iwfs_ext_mmap_opts_t;
*
* @return Computed new file size.
*/
typedef off_t (*IW_EXT_RSPOLICY)(off_t nsize, off_t csize, struct IWFS_EXT *f,
void **ctx);
typedef off_t (*IW_EXT_RSPOLICY)(
off_t nsize, off_t csize, struct IWFS_EXT *f,
void **ctx);
/**
* @brief Fibonacci resize file policy.
*
* New `file_size(n+1) = MAX(file_size(n) + file_size(n-1), nsize)`
*/
IW_EXPORT off_t iw_exfile_szpolicy_fibo(off_t nsize, off_t csize,
struct IWFS_EXT *f, void **ctx);
IW_EXPORT off_t iw_exfile_szpolicy_fibo(
off_t nsize, off_t csize,
struct IWFS_EXT *f, void **ctx);
/**
* @brief Rational number `IW_RNUM` file size multiplication policy.
*
* New `file_size = MAX(file_size * (N/D), nsize)`
*/
IW_EXPORT off_t iw_exfile_szpolicy_mul(off_t nsize, off_t csize,
struct IWFS_EXT *f, void **ctx);
IW_EXPORT off_t iw_exfile_szpolicy_mul(
off_t nsize, off_t csize,
struct IWFS_EXT *f, void **ctx);
/**
* @brief `IWFS_EXT` file options.
@@ -133,7 +136,7 @@ IW_EXPORT off_t iw_exfile_szpolicy_mul(off_t nsize, off_t csize,
typedef struct IWFS_EXT_OPTS {
IWFS_FILE_OPTS file; /**< Underlying file options */
off_t initial_size; /**< Initial file size */
bool use_locks; /**< If `true` file operations will be guarded by rw lock. Default: `false` */
bool use_locks; /**< If `true` file operations will be guarded by rw lock. Default: `false` */
IW_EXT_RSPOLICY rspolicy; /**< File resize policy function ptr. Default:
`exact size policy` */
@@ -176,14 +179,14 @@ typedef struct IWFS_EXT {
* @see off_t iw_exfile_szpolicy_mul(off_t nsize, off_t csize, struct IWFS_EXT
* *f, void **ctx)
*/
iwrc(*ensure_size)(struct IWFS_EXT *f, off_t off);
iwrc (*ensure_size)(struct IWFS_EXT *f, off_t off);
/**
* @brief Set the end of this file to the specified offset @a off exactly.
*/
iwrc(*truncate)(struct IWFS_EXT *f, off_t off);
iwrc (*truncate)(struct IWFS_EXT *f, off_t off);
iwrc(*truncate_unsafe)(struct IWFS_EXT *f, off_t off);
iwrc (*truncate_unsafe)(struct IWFS_EXT *f, off_t off);
/**
* @brief Register an address space specified by @a off and @a len as memory
@@ -211,9 +214,9 @@ typedef struct IWFS_EXT {
* @param len Length of mmaped region
* @return `0` on success or error code.
*/
iwrc(*add_mmap)(struct IWFS_EXT *f, off_t off, size_t len, iwfs_ext_mmap_opts_t opts);
iwrc (*add_mmap)(struct IWFS_EXT *f, off_t off, size_t len, iwfs_ext_mmap_opts_t opts);
iwrc(*add_mmap_unsafe)(struct IWFS_EXT *f, off_t off, size_t len, iwfs_ext_mmap_opts_t opts);
iwrc (*add_mmap_unsafe)(struct IWFS_EXT *f, off_t off, size_t len, iwfs_ext_mmap_opts_t opts);
/**
* @brief Retrieve mmaped region by its offset @a off and keep file as read locked.
@@ -232,19 +235,19 @@ typedef struct IWFS_EXT {
* @param [out] sp Length of region
* @return `0` on success or error code.
*/
iwrc(*acquire_mmap)(struct IWFS_EXT *f, off_t off, uint8_t **mm, size_t *sp);
iwrc (*acquire_mmap)(struct IWFS_EXT *f, off_t off, uint8_t **mm, size_t *sp);
/**
* @brief Retrieve mmaped region by its offset @a off
*/
iwrc(*probe_mmap)(struct IWFS_EXT *f, off_t off, uint8_t **mm, size_t *sp);
iwrc (*probe_mmap)(struct IWFS_EXT *f, off_t off, uint8_t **mm, size_t *sp);
iwrc(*probe_mmap_unsafe)(struct IWFS_EXT *f, off_t off, uint8_t **mm, size_t *sp);
iwrc (*probe_mmap_unsafe)(struct IWFS_EXT *f, off_t off, uint8_t **mm, size_t *sp);
/**
* @brief Release the lock acquired by successfull call of `acquire_mmap()`
*/
iwrc(*release_mmap)(struct IWFS_EXT *f);
iwrc (*release_mmap)(struct IWFS_EXT *f);
/**
* @brief Unmap mmaped region identified by @a off
@@ -256,9 +259,9 @@ typedef struct IWFS_EXT {
* @param off Region start offset
* @return `0` on success or error code.
*/
iwrc(*remove_mmap)(struct IWFS_EXT *f, off_t off);
iwrc (*remove_mmap)(struct IWFS_EXT *f, off_t off);
iwrc(*remove_mmap_unsafe)(struct IWFS_EXT *f, off_t off);
iwrc (*remove_mmap_unsafe)(struct IWFS_EXT *f, off_t off);
/**
* @brief Synchronize a file with a mmaped region identified by @a off offset.
@@ -271,39 +274,40 @@ typedef struct IWFS_EXT {
* @param flags Sync flags.
* @return `0` on success or error code.
*/
iwrc(*sync_mmap)(struct IWFS_EXT *f, off_t off, iwfs_sync_flags flags);
iwrc (*sync_mmap)(struct IWFS_EXT *f, off_t off, iwfs_sync_flags flags);
iwrc(*sync_mmap_unsafe)(struct IWFS_EXT *f, off_t off, iwfs_sync_flags flags);
iwrc (*sync_mmap_unsafe)(struct IWFS_EXT *f, off_t off, iwfs_sync_flags flags);
/**
* @brief Remap all mmaped regions.
*
* @param f `IWFS_EXT`
*/
iwrc(*remap_all)(struct IWFS_EXT *f);
iwrc (*remap_all)(struct IWFS_EXT *f);
/* See iwfile.h */
/** @see IWFS_FILE::write */
iwrc(*write)(struct IWFS_EXT *f, off_t off, const void *buf, size_t siz,
size_t *sp);
iwrc (*write)(
struct IWFS_EXT *f, off_t off, const void *buf, size_t siz,
size_t *sp);
/** @see IWFS_FILE::read */
iwrc(*read)(struct IWFS_EXT *f, off_t off, void *buf, size_t siz,
size_t *sp);
iwrc (*read)(
struct IWFS_EXT *f, off_t off, void *buf, size_t siz,
size_t *sp);
/** @see IWFS_FILE::close */
iwrc(*close)(struct IWFS_EXT *f);
iwrc (*close)(struct IWFS_EXT *f);
/** @see IWFS_FILE::sync */
iwrc(*sync)(struct IWFS_EXT *f, iwfs_sync_flags flags);
iwrc (*sync)(struct IWFS_EXT *f, iwfs_sync_flags flags);
/** @see IWFS_FILE::state */
iwrc(*state)(struct IWFS_EXT *f, IWFS_EXT_STATE *state);
iwrc (*state)(struct IWFS_EXT *f, IWFS_EXT_STATE *state);
/** @see IWFS_FILE::copy */
iwrc(*copy)(struct IWFS_EXT *f, off_t off, size_t siz, off_t noff);
iwrc (*copy)(struct IWFS_EXT *f, off_t off, size_t siz, off_t noff);
} IWFS_EXT;
/**
+12 -7
View File
@@ -3,7 +3,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -33,6 +33,11 @@
#include <fcntl.h>
#include <limits.h>
#include <unistd.h>
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif
#ifdef _WIN32
#include <libiberty/libiberty.h>
#define strndup xstrndup
@@ -41,7 +46,7 @@
typedef struct IWFS_FILE_IMPL {
HANDLE fh; /**< File handle. */
iwfs_openstatus ostatus; /**< File open status. */
IWFS_FILE_OPTS opts; /**< File open options. */
IWFS_FILE_OPTS opts; /**< File open options. */
} IWF;
static iwrc _iwfs_write(struct IWFS_FILE *f, off_t off, const void *buf, size_t siz, size_t *sp) {
@@ -86,7 +91,7 @@ static iwrc _iwfs_close(struct IWFS_FILE *f) {
}
IWRC(iwp_closefh(impl->fh), rc);
if (opts->path) {
free((char *) opts->path);
free((char*) opts->path);
opts->path = 0;
}
free(f->impl);
@@ -184,8 +189,8 @@ iwrc iwfs_file_open(IWFS_FILE *f, const IWFS_FILE_OPTS *_opts) {
if (opts->dlsnr) {
IWDLSNR *l = opts->dlsnr;
if (!l->onopen || !l->onclosing || !l->oncopy || !l->onresize ||
!l->onset || !l->onsynced || !l->onwrite) {
if ( !l->onopen || !l->onclosing || !l->oncopy || !l->onresize
|| !l->onset || !l->onsynced || !l->onwrite) {
iwlog_ecode_error2(IW_ERROR_INVALID_ARGS, "Invalid 'opts->dlsnr' specified");
return IW_ERROR_INVALID_ARGS;
}
@@ -241,7 +246,7 @@ iwrc iwfs_file_open(IWFS_FILE *f, const IWFS_FILE_OPTS *_opts) {
impl->ostatus = IWFS_OPEN_NEW;
}
rc = 0;
mode = O_RDONLY;
mode = O_RDONLY | O_CLOEXEC;
if (omode & IWFS_OWRITE) {
mode = O_RDWR;
if (omode & IWFS_OCREATE) {
@@ -297,7 +302,7 @@ finish:
if (rc) {
impl->ostatus = IWFS_OPEN_FAIL;
if (opts->path) {
free((char *) opts->path);
free((char*) opts->path);
}
f->impl = 0;
free(impl);
+22 -23
View File
@@ -7,7 +7,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -71,33 +71,33 @@ IW_EXTERN_C_START
/** File open mode */
typedef uint8_t iwfs_omode;
/** Open file as a reader.*/
#define IWFS_OREAD ((iwfs_omode) 0x01U)
#define IWFS_OREAD ((iwfs_omode) 0x01U)
/** Open file as a writer. */
#define IWFS_OWRITE ((iwfs_omode) 0x02U)
#define IWFS_OWRITE ((iwfs_omode) 0x02U)
/** If file is missing it will be created on open. */
#define IWFS_OCREATE ((iwfs_omode) 0x04U)
#define IWFS_OCREATE ((iwfs_omode) 0x04U)
/** Truncate file on open. */
#define IWFS_OTRUNC ((iwfs_omode) 0x08U)
#define IWFS_OTRUNC ((iwfs_omode) 0x08U)
/** Unlink(delete) file on close */
#define IWFS_OUNLINK ((iwfs_omode) 0x10U)
#define IWFS_OUNLINK ((iwfs_omode) 0x10U)
/** Temp file will be created, in this case specified file name will act as temp file name prefix */
#define IWFS_OTMP ((iwfs_omode) 0x20U)
#define IWFS_OTMP ((iwfs_omode) 0x20U)
/** Status of an open file operation */
typedef uint8_t iwfs_openstatus;
/** Open failed. */
#define IWFS_OPEN_FAIL ((iwfs_openstatus) 0x00U)
/** Open success, new file've been created. */
#define IWFS_OPEN_NEW ((iwfs_openstatus) 0x01U)
#define IWFS_OPEN_NEW ((iwfs_openstatus) 0x01U)
/** Open success, existing file've been opened. */
#define IWFS_OPEN_EXISTING ((iwfs_openstatus) 0x02U)
#define IWFS_OPEN_EXISTING ((iwfs_openstatus) 0x02U)
/** Sync file data options */
typedef uint8_t iwfs_sync_flags;
#define IWFS_SYNCDEFAULT ((iwfs_sync_flags) 0x00U)
#define IWFS_FDATASYNC ((iwfs_sync_flags) 0x01U)
#define IWFS_SYNCDEFAULT ((iwfs_sync_flags) 0x00U)
#define IWFS_FDATASYNC ((iwfs_sync_flags) 0x01U)
#define IWFS_DEFAULT_OMODE (IWFS_OCREATE)
#define IWFS_DEFAULT_OMODE (IWFS_OCREATE)
#define IWFS_DEFAULT_LOCKMODE (IWP_NOLOCK)
#define IWFS_DEFAULT_FILEMODE \
00666 /**< Default permission of created files */
@@ -107,12 +107,12 @@ typedef uint8_t iwfs_sync_flags;
* @see iwrc iwfs_file_open(IWFS_FILE *f, const IWFS_FILE_OPTS *opts)
*/
typedef struct {
const char *path; /**< Required file path. */
iwfs_omode omode; /**< File open mode. */
const char *path; /**< Required file path. */
iwfs_omode omode; /**< File open mode. */
iwp_lockmode lock_mode; /**< File locking mode. */
/**< Specifies the permissions to use in case a new file is created,
`int open(const char *pathname, int flags, mode_t mode)` */
int filemode;
int filemode;
IWDLSNR *dlsnr; /**< Optional data listener */
} IWFS_FILE_OPTS;
@@ -123,7 +123,7 @@ typedef struct {
typedef struct {
int is_open; /**< `1` if file in open state */
iwfs_openstatus ostatus; /**< File open status. */
IWFS_FILE_OPTS opts; /**< File open options. */
IWFS_FILE_OPTS opts; /**< File open options. */
HANDLE fh; /**< File handle */
} IWFS_FILE_STATE;
@@ -144,7 +144,7 @@ typedef struct IWFS_FILE {
* @param [out] sp Number of bytes actually written
* @return `0` on success or error code.
*/
iwrc(*write)(struct IWFS_FILE *f, off_t off, const void *buf, size_t siz, size_t *sp);
iwrc (*write)(struct IWFS_FILE *f, off_t off, const void *buf, size_t siz, size_t *sp);
/**
* @brief Read @a siz bytes into @a buf at the specified offset @a off
@@ -156,20 +156,20 @@ typedef struct IWFS_FILE {
* @param [out] sp Number of bytes actually read.
* @return `0` on success or error code.
*/
iwrc(*read)(struct IWFS_FILE *f, off_t off, void *buf, size_t siz, size_t *sp);
iwrc (*read)(struct IWFS_FILE *f, off_t off, void *buf, size_t siz, size_t *sp);
/**
* @brief Closes this file.
* @return `0` on success or error code.
*/
iwrc(*close)(struct IWFS_FILE *f);
iwrc (*close)(struct IWFS_FILE *f);
/**
* @brief Sync file data with fs.
* @param f `struct IWFS_FILE` pointer.
* @param opts File sync options.
*/
iwrc(*sync)(struct IWFS_FILE *f, iwfs_sync_flags flags);
iwrc (*sync)(struct IWFS_FILE *f, iwfs_sync_flags flags);
/**
* @brief Return current file state.
@@ -179,7 +179,7 @@ typedef struct IWFS_FILE {
*
* @see struct IWFS_FILE_STATE
*/
iwrc(*state)(struct IWFS_FILE *f, IWFS_FILE_STATE *state);
iwrc (*state)(struct IWFS_FILE *f, IWFS_FILE_STATE *state);
/**
* @brief Copy data within a file
@@ -188,8 +188,7 @@ typedef struct IWFS_FILE {
* @param siz Data size
* @param noff New data offset
*/
iwrc(*copy)(struct IWFS_FILE *f, off_t off, size_t siz, off_t noff);
iwrc (*copy)(struct IWFS_FILE *f, off_t off, size_t siz, off_t noff);
} IWFS_FILE;
/**
+1 -1
View File
@@ -3,7 +3,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+132 -112
View File
@@ -3,7 +3,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -48,12 +48,15 @@ typedef struct {
/** Additional options for `_fsm_set_bit_status_lw` routine */
typedef uint8_t fsm_bmopts_t;
/** No options. */
#define FSM_BM_NONE ((fsm_bmopts_t) 0x00U)
#define FSM_BM_NONE ((fsm_bmopts_t) 0x00U)
/** Do not modify bitmap. */
#define FSM_BM_DRY_RUN ((fsm_bmopts_t) 0x01U)
#define FSM_BM_DRY_RUN ((fsm_bmopts_t) 0x01U)
/** Perform strict checking of bitmap consistency */
#define FSM_BM_STRICT ((fsm_bmopts_t) 0x02U)
#define FSM_BM_STRICT ((fsm_bmopts_t) 0x02U)
/* Maximum size of block: 1Mb */
#define FSM_MAX_BLOCK_POW 20
@@ -74,32 +77,33 @@ typedef uint8_t fsm_bmopts_t;
////////////////////////////////////////////////////////////////////////////////////////////////////
IW_INLINE int _fsm_cmp_ptr(const FSMBK *a, const FSMBK *b);
#define _fsm_cmp(a_, b_) (_fsm_cmp_ptr(&(a_), &(b_)))
// -V:KBTREE_INIT:522, 641
KBTREE_INIT(fsm, FSMBK, _fsm_cmp)
struct IWFS_FSM_IMPL {
IWFS_EXT pool; /**< Underlying rwl file. */
uint64_t bmlen; /**< Free-space bitmap block length in bytes. */
uint64_t bmoff; /**< Free-space bitmap block offset in bytes. */
uint64_t lfbkoff; /**< Offset in blocks of free block chunk with the largest offset. */
uint64_t lfbklen; /**< Length in blocks of free block chunk with the largest offset. */
uint64_t crzsum; /**< Cumulative sum all allocated blocks */
uint64_t crzvar; /**< Record sizes standard variance (deviation^2 * N) */
uint32_t hdrlen; /**< Length of custom file header */
uint32_t crznum; /**< Number of all allocated continuous areas acquired by `allocate` */
IWFS_FSM *f; /**< Self reference. */
IWDLSNR *dlsnr; /**< Data events listener */
kbtree_t(fsm) *fsm; /**< Free-space tree */
pthread_rwlock_t *ctlrwlk; /**< Methods RW lock */
size_t aunit; /**< System allocation unit size.
- Page size on *NIX
- Minimal allocation unit for WIN32 */
iwfs_fsm_openflags oflags; /**< Operation mode flags. */
iwfs_omode omode; /**< Open mode. */
uint8_t bpow; /**< Block size power for 2 */
bool mmap_all; /**< Mmap all file data */
IWFS_EXT pool; /**< Underlying rwl file. */
uint64_t bmlen; /**< Free-space bitmap block length in bytes. */
uint64_t bmoff; /**< Free-space bitmap block offset in bytes. */
uint64_t lfbkoff; /**< Offset in blocks of free block chunk with the largest offset. */
uint64_t lfbklen; /**< Length in blocks of free block chunk with the largest offset. */
uint64_t crzsum; /**< Cumulative sum all allocated blocks */
uint64_t crzvar; /**< Record sizes standard variance (deviation^2 * N) */
uint32_t hdrlen; /**< Length of custom file header */
uint32_t crznum; /**< Number of all allocated continuous areas acquired by `allocate` */
IWFS_FSM *f; /**< Self reference. */
IWDLSNR *dlsnr; /**< Data events listener */
kbtree_t(fsm) * fsm; /**< Free-space tree */
pthread_rwlock_t *ctlrwlk; /**< Methods RW lock */
size_t aunit; /**< System allocation unit size.
- Page size on *NIX
- Minimal allocation unit for WIN32 */
iwfs_fsm_openflags oflags; /**< Operation mode flags. */
iwfs_omode omode; /**< Open mode. */
uint8_t bpow; /**< Block size power for 2 */
bool mmap_all; /**< Mmap all file data */
iwfs_ext_mmap_opts_t mmap_opts; /**< Defaul mmap options used in `add_mmap` */
};
@@ -142,12 +146,12 @@ IW_INLINE iwrc _fsm_bmptr(FSM *impl, uint64_t **bmptr) {
if (sp < impl->bmoff + impl->bmlen) {
return IWFS_ERROR_NOT_MMAPED;
}
*bmptr = (uint64_t *)(mm + impl->bmoff);
*bmptr = (uint64_t*) (mm + impl->bmoff);
} else {
if (sp < impl->bmlen) {
return IWFS_ERROR_NOT_MMAPED;
}
*bmptr = (uint64_t *) mm;
*bmptr = (uint64_t*) mm;
}
return 0;
}
@@ -158,8 +162,8 @@ IW_INLINE iwrc _fsm_bmptr(FSM *impl, uint64_t **bmptr) {
* and @a length values.
*/
IW_INLINE WUR iwrc _fsm_init_fbk(FSMBK *bk, uint64_t offset_blk, uint64_t len_blk) {
if (offset_blk > ((uint32_t) - 1) ||
len_blk > ((uint32_t) - 1)) {
if ( (offset_blk > ((uint32_t) -1))
|| (len_blk > ((uint32_t) -1))) {
return IW_ERROR_OVERFLOW;
}
bk->off = (uint32_t) offset_blk;
@@ -240,10 +244,11 @@ IW_INLINE iwrc _fsm_put_fbk(FSM *impl, uint64_t offset_blk, uint64_t length_blk)
* @param opts Allocation opts
* @return `0` if matching block is not found.
*/
IW_INLINE FSMBK *_fsm_find_matching_fblock_lw(FSM *impl,
uint64_t offset_blk,
uint64_t length_blk,
iwfs_fsm_aflags opts) {
IW_INLINE FSMBK* _fsm_find_matching_fblock_lw(
FSM *impl,
uint64_t offset_blk,
uint64_t length_blk,
iwfs_fsm_aflags opts) {
FSMBK k, *uk, *lk;
iwrc rc = _fsm_init_fbk(&k, offset_blk, length_blk);
if (rc) {
@@ -276,11 +281,13 @@ IW_INLINE FSMBK *_fsm_find_matching_fblock_lw(FSM *impl,
* @param bit_status If `1` bits will be set to `1` otherwise `0`
* @param opts Operation options
*/
static iwrc _fsm_set_bit_status_lw(FSM *impl,
const uint64_t offset_bits,
const uint64_t length_bits_,
const int bit_status,
const fsm_bmopts_t opts) {
static iwrc _fsm_set_bit_status_lw(
FSM *impl,
const uint64_t offset_bits,
const uint64_t length_bits_,
const int bit_status,
const fsm_bmopts_t opts) {
iwrc rc;
size_t sp;
uint8_t *mm;
@@ -311,7 +318,7 @@ static iwrc _fsm_set_bit_status_lw(FSM *impl,
return IWFS_ERROR_NOT_MMAPED;
}
}
p = ((uint64_t *) mm) + offset_bits / 64;
p = ((uint64_t*) mm) + offset_bits / 64;
set_bits = 64 - (offset_bits & (64 - 1)); // NOLINT
set_mask = (~((uint64_t) 0) << (offset_bits & (64 - 1)));
@@ -354,7 +361,7 @@ static iwrc _fsm_set_bit_status_lw(FSM *impl,
*p = IW_HTOILL(pv);
}
} else {
if ((opts & FSM_BM_STRICT) && (pv & set_mask) != set_mask) {
if ((opts & FSM_BM_STRICT) && ((pv & set_mask) != set_mask)) {
rc = IWFS_ERROR_FSM_SEGMENTATION;
}
if ((opts & FSM_BM_DRY_RUN) == 0) {
@@ -395,7 +402,7 @@ static iwrc _fsm_set_bit_status_lw(FSM *impl,
*p |= set_mask;
}
} else {
if ((opts & FSM_BM_STRICT) && (*p & set_mask) != set_mask) {
if ((opts & FSM_BM_STRICT) && ((*p & set_mask) != set_mask)) {
rc = IWFS_ERROR_FSM_SEGMENTATION;
}
if ((opts & FSM_BM_DRY_RUN) == 0) {
@@ -408,7 +415,9 @@ static iwrc _fsm_set_bit_status_lw(FSM *impl,
uint64_t so = offset_bits / 8;
uint64_t lb = length_bits_ + offset_bits % 8;
uint64_t dl = lb / 8;
if (lb % 8) ++dl;
if (lb % 8) {
++dl;
}
rc = impl->dlsnr->onwrite(impl->dlsnr, impl->bmoff + so, mm + so, dl, 0);
}
return rc;
@@ -426,12 +435,13 @@ static iwrc _fsm_set_bit_status_lw(FSM *impl,
* @param max_offset_blk Maximal offset of allocated block.
* @param opts Allocation options.
*/
static iwrc _fsm_blk_allocate_aligned_lw(FSM *impl,
const uint64_t length_blk,
uint64_t *offset_blk,
uint64_t *olength_blk,
const uint64_t max_offset_blk,
const iwfs_fsm_aflags opts) {
static iwrc _fsm_blk_allocate_aligned_lw(
FSM *impl,
const uint64_t length_blk,
uint64_t *offset_blk,
uint64_t *olength_blk,
const uint64_t max_offset_blk,
const iwfs_fsm_aflags opts) {
FSMBK *nk;
fsm_bmopts_t bopts = FSM_BM_NONE;
size_t aunit_blk = (impl->aunit >> impl->bpow);
@@ -455,7 +465,7 @@ static iwrc _fsm_blk_allocate_aligned_lw(FSM *impl,
uint64_t aklen = FSMBK_LENGTH(nk);
uint64_t noff = IW_ROUNDUP(akoff, aunit_blk);
if (noff <= max_offset_blk && (noff < aklen + akoff) && (aklen - (noff - akoff) >= length_blk)) {
if ((noff <= max_offset_blk) && (noff < aklen + akoff) && (aklen - (noff - akoff) >= length_blk)) {
_fsm_del_fbk(impl, akoff, aklen);
aklen = aklen - (noff - akoff);
if (noff > akoff) {
@@ -560,7 +570,7 @@ static iwrc _fsm_write_meta_lw(FSM *impl) {
uint64_t llv;
size_t wlen;
uint32_t sp = 0, lv;
uint8_t hdr[IWFSM_CUSTOM_HDR_DATA_OFFSET] = {0};
uint8_t hdr[IWFSM_CUSTOM_HDR_DATA_OFFSET] = { 0 };
/*
[FSM_CTL_MAGICK u32][block pow u8]
@@ -568,7 +578,7 @@ static iwrc _fsm_write_meta_lw(FSM *impl) {
[u64 crzsum][u32 crznum][u64 crszvar][u256 reserved]
[custom header size u32][custom header data...]
[fsm data...]
*/
*/
/* magic */
lv = IW_HTOIL(IWFSM_MAGICK);
@@ -635,10 +645,11 @@ static iwrc _fsm_write_meta_lw(FSM *impl) {
* @brief Search for the first next set bit position
* starting from the specified offset bit (INCLUDED).
*/
static uint64_t _fsm_find_next_set_bit(const uint64_t *addr,
register uint64_t offset_bit,
const uint64_t max_offset_bit,
int *found) {
static uint64_t _fsm_find_next_set_bit(
const uint64_t *addr,
register uint64_t offset_bit,
const uint64_t max_offset_bit,
int *found) {
*found = 0;
register uint64_t bit, size;
register const uint64_t *p = addr + offset_bit / 64;
@@ -734,10 +745,11 @@ static uint64_t _fsm_find_next_set_bit(const uint64_t *addr,
* @brief Search for the first previous set bit position
* starting from the specified offset_bit (EXCLUDED).
*/
static uint64_t _fsm_find_prev_set_bit(const uint64_t *addr,
register uint64_t offset_bit,
const uint64_t min_offset_bit,
int *found) {
static uint64_t _fsm_find_prev_set_bit(
const uint64_t *addr,
register uint64_t offset_bit,
const uint64_t min_offset_bit,
int *found) {
register const uint64_t *p;
register uint64_t tmp, bit, size;
*found = 0;
@@ -832,9 +844,10 @@ static uint64_t _fsm_find_prev_set_bit(const uint64_t *addr,
* @param offset_blk Starting block number of the specified range.
* @param length_blk Range size in blocks.
*/
static iwrc _fsm_blk_deallocate_lw(FSM *impl,
const uint64_t offset_blk,
const uint64_t length_blk) {
static iwrc _fsm_blk_deallocate_lw(
FSM *impl,
const uint64_t offset_blk,
const uint64_t length_blk) {
iwrc rc;
uint64_t *bmptr;
uint64_t left, right;
@@ -857,7 +870,7 @@ static iwrc _fsm_blk_deallocate_lw(FSM *impl,
/* Merge with neighborhoods */
left = _fsm_find_prev_set_bit(bmptr, offset_blk, 0, &hasleft);
if (lfbkoff && lfbkoff == end_offset_blk) {
if (lfbkoff && (lfbkoff == end_offset_blk)) {
right = lfbkoff + impl->lfbklen;
hasright = 1;
} else {
@@ -881,7 +894,7 @@ static iwrc _fsm_blk_deallocate_lw(FSM *impl,
key_offset = rm_offset;
key_length += rm_length;
}
if (hasright && right > end_offset_blk) {
if (hasright && (right > end_offset_blk)) {
rm_offset = end_offset_blk;
rm_length = right - end_offset_blk;
_fsm_del_fbk(impl, rm_offset, rm_length);
@@ -955,7 +968,7 @@ static iwrc _fsm_init_lw(FSM *impl, uint64_t bmoff, uint64_t bmlen) {
mm2 = mm - bmoff + impl->bmoff;
} else {
rc = pool->probe_mmap(pool, impl->bmoff, &mm2, &sp2);
if (!rc && sp2 < impl->bmlen) {
if (!rc && (sp2 < impl->bmlen)) {
rc = IWFS_ERROR_NOT_MMAPED;
}
if (rc) {
@@ -1018,7 +1031,8 @@ static iwrc _fsm_init_lw(FSM *impl, uint64_t bmoff, uint64_t bmlen) {
}
return rc;
rollback: /* try to rollback previous bitmap state */
rollback:
/* try to rollback previous bitmap state */
impl->bmoff = old_bmoff;
impl->bmlen = old_bmlen;
if (old_bmlen && mm2) {
@@ -1043,8 +1057,8 @@ static iwrc _fsm_resize_fsm_bitmap_lw(FSM *impl, uint64_t size) {
}
bmlen = IW_ROUNDUP(size, impl->aunit); /* align to the system page size. */
rc = _fsm_blk_allocate_aligned_lw(
impl, (bmlen >> impl->bpow), &bmoffset, &sp, UINT64_MAX,
IWFSM_ALLOC_NO_STATS | IWFSM_ALLOC_NO_EXTEND | IWFSM_ALLOC_NO_OVERALLOCATE);
impl, (bmlen >> impl->bpow), &bmoffset, &sp, UINT64_MAX,
IWFSM_ALLOC_NO_STATS | IWFSM_ALLOC_NO_EXTEND | IWFSM_ALLOC_NO_OVERALLOCATE);
if (!rc) {
bmoffset = bmoffset << impl->bpow;
bmlen = sp << impl->bpow;
@@ -1073,11 +1087,12 @@ static iwrc _fsm_resize_fsm_bitmap_lw(FSM *impl, uint64_t size) {
* @param [out] olength_blk Assigned segment length in blocks.
* @param opts
*/
static iwrc _fsm_blk_allocate_lw(FSM *impl,
uint64_t length_blk,
uint64_t *offset_blk,
uint64_t *olength_blk,
iwfs_fsm_aflags opts) {
static iwrc _fsm_blk_allocate_lw(
FSM *impl,
uint64_t length_blk,
uint64_t *offset_blk,
uint64_t *olength_blk,
iwfs_fsm_aflags opts) {
iwrc rc;
FSMBK *nk;
fsm_bmopts_t bopts = FSM_BM_NONE;
@@ -1116,10 +1131,12 @@ start:
if (nlength > length_blk) { /* re-save rest of free-space */
if (!(opts & IWFSM_ALLOC_NO_OVERALLOCATE) && impl->crznum) {
/* todo use lognormal distribution? */
double_t d = ((double_t) impl->crzsum / (double_t) impl->crznum) /*avg*/
- (nlength - length_blk); /*rest blk size*/
double_t d = ((double_t) impl->crzsum / (double_t) impl->crznum) /*avg*/
- (nlength - length_blk); /*rest blk size*/
double_t s = ((double_t) impl->crzvar / (double_t) impl->crznum) * 6.0; /* blk size dispersion * 6 */
if (s > 1 && d > 0 && d * d > s) { /* its better to attach rest of block to the record */
if ((s > 1) && (d > 0) && (d * d > s)) {
/* its better to attach rest of block to
the record */
*olength_blk = nlength;
} else {
_fsm_put_fbk(impl, (*offset_blk + length_blk), (nlength - length_blk));
@@ -1152,8 +1169,8 @@ start:
++impl->crznum;
impl->crzsum += length_blk;
avg = (double_t) impl->crzsum / (double_t) impl->crznum; /* average */
impl->crzvar +=
(uint64_t)(((double_t) length_blk - avg) * ((double_t) length_blk - avg) + 0.5L); /* variance */
impl->crzvar
+= (uint64_t) (((double_t) length_blk - avg) * ((double_t) length_blk - avg) + 0.5L); /* variance */
}
if (!rc && (opts & IWFSM_SOLID_ALLOCATED_SPACE)) {
uint64_t bs = *offset_blk;
@@ -1185,10 +1202,10 @@ static iwrc _fsm_trim_tail_lw(FSM *impl) {
}
/* find free space for fsm with lesser offset than actual */
rc = _fsm_blk_allocate_aligned_lw(
impl, (impl->bmlen >> impl->bpow), &offset, &length, (impl->bmoff >> impl->bpow),
IWFSM_ALLOC_NO_EXTEND | IWFSM_ALLOC_NO_OVERALLOCATE | IWFSM_ALLOC_NO_STATS);
impl, (impl->bmlen >> impl->bpow), &offset, &length, (impl->bmoff >> impl->bpow),
IWFSM_ALLOC_NO_EXTEND | IWFSM_ALLOC_NO_OVERALLOCATE | IWFSM_ALLOC_NO_STATS);
if (rc && rc != IWFS_ERROR_NO_FREE_SPACE) {
if (rc && (rc != IWFS_ERROR_NO_FREE_SPACE)) {
return rc;
}
if (rc) {
@@ -1216,7 +1233,7 @@ static iwrc _fsm_trim_tail_lw(FSM *impl) {
lastblk = offset + 1;
}
rc = impl->pool.state(&impl->pool, &fstate);
if (!rc && fstate.fsize > (lastblk << impl->bpow)) {
if (!rc && (fstate.fsize > (lastblk << impl->bpow))) {
rc = impl->pool.truncate(&impl->pool, lastblk << impl->bpow);
}
@@ -1276,7 +1293,7 @@ static iwrc _fsm_read_meta_lr(FSM *impl) {
uint32_t lv;
uint64_t llv;
size_t sp, rp = 0;
uint8_t hdr[IWFSM_CUSTOM_HDR_DATA_OFFSET] = {0};
uint8_t hdr[IWFSM_CUSTOM_HDR_DATA_OFFSET] = { 0 };
/*
[FSM_CTL_MAGICK u32][block pow u8]
@@ -1284,7 +1301,7 @@ static iwrc _fsm_read_meta_lr(FSM *impl) {
[u64 crzsum][u32 crznum][u64 crszvar][u256 reserved]
[custom header size u32][custom header data...]
[fsm data...]
*/
*/
rc = impl->pool.read(&impl->pool, 0, hdr, IWFSM_CUSTOM_HDR_DATA_OFFSET, &sp);
if (rc) {
@@ -1445,7 +1462,7 @@ finish:
static iwrc _fsm_is_fully_allocated_lr(FSM *impl, uint64_t offset_blk, uint64_t length_blk, int *ret) {
uint64_t end = offset_blk + length_blk;
*ret = 1;
if (length_blk < 1 || end < offset_blk || end > (impl->bmlen << 3)) {
if ((length_blk < 1) || (end < offset_blk) || (end > (impl->bmlen << 3))) {
*ret = 0;
return 0;
}
@@ -1458,8 +1475,8 @@ static iwrc _fsm_is_fully_allocated_lr(FSM *impl, uint64_t offset_blk, uint64_t
}
/*************************************************************************************************
* Public API *
*************************************************************************************************/
* Public API *
*************************************************************************************************/
static iwrc _fsm_write(struct IWFS_FSM *f, off_t off, const void *buf, size_t siz, size_t *sp) {
FSM_ENSURE_OPEN2(f);
@@ -1615,7 +1632,7 @@ static iwrc _fsm_allocate(struct IWFS_FSM *f, off_t len, off_t *oaddr, off_t *ol
return IW_ERROR_INVALID_ARGS;
}
/* Required blocks number */
sbnum = (uint64_t) * oaddr >> impl->bpow;
sbnum = (uint64_t) *oaddr >> impl->bpow;
len = IW_ROUNDUP(len, 1ULL << impl->bpow);
rc = _fsm_ctrl_wlock(impl);
@@ -1642,8 +1659,8 @@ static iwrc _fsm_reallocate(struct IWFS_FSM *f, off_t nlen, off_t *oaddr, off_t
}
uint64_t sp;
uint64_t nlen_blk = IW_ROUNDUP((uint64_t) nlen, 1ULL << impl->bpow) >> impl->bpow;
uint64_t olen_blk = (uint64_t) * olen >> impl->bpow;
uint64_t oaddr_blk = (uint64_t) * oaddr >> impl->bpow;
uint64_t olen_blk = (uint64_t) *olen >> impl->bpow;
uint64_t oaddr_blk = (uint64_t) *oaddr >> impl->bpow;
uint64_t naddr_blk = oaddr_blk;
if (nlen_blk == olen_blk) {
@@ -1661,7 +1678,7 @@ static iwrc _fsm_reallocate(struct IWFS_FSM *f, off_t nlen, off_t *oaddr, off_t
rc = _fsm_blk_allocate_lw(impl, nlen_blk, &naddr_blk, &sp, opts);
RCGO(rc, finish);
if (naddr_blk != oaddr_blk) {
rc = impl->pool.copy(&impl->pool, *oaddr, (size_t) * olen, naddr_blk << impl->bpow);
rc = impl->pool.copy(&impl->pool, *oaddr, (size_t) *olen, naddr_blk << impl->bpow);
RCGO(rc, finish);
}
rc = _fsm_blk_deallocate_lw(impl, oaddr_blk, olen_blk);
@@ -1690,9 +1707,9 @@ static iwrc _fsm_deallocate(struct IWFS_FSM *f, off_t addr, off_t len) {
}
rc = _fsm_ctrl_wlock(impl);
RCRET(rc);
if (IW_RANGES_OVERLAP(offset_blk, offset_blk + length_blk, 0, (impl->hdrlen >> impl->bpow)) ||
IW_RANGES_OVERLAP(offset_blk, offset_blk + length_blk, (impl->bmoff >> impl->bpow),
(impl->bmoff >> impl->bpow) + (impl->bmlen >> impl->bpow))) {
if ( IW_RANGES_OVERLAP(offset_blk, offset_blk + length_blk, 0, (impl->hdrlen >> impl->bpow))
|| IW_RANGES_OVERLAP(offset_blk, offset_blk + length_blk, (impl->bmoff >> impl->bpow),
(impl->bmoff >> impl->bpow) + (impl->bmlen >> impl->bpow))) {
// Deny deallocations in header or free-space bitmap itself
IWRC(_fsm_ctrl_unlock(impl), rc);
return IWFS_ERROR_FSM_SEGMENTATION;
@@ -1711,9 +1728,9 @@ static iwrc _fsm_check_allocation_status(struct IWFS_FSM *f, off_t addr, off_t l
RCRET(rc);
off_t offset_blk = (uint64_t) addr >> impl->bpow;
off_t length_blk = (uint64_t) len >> impl->bpow;
if (IW_RANGES_OVERLAP(offset_blk, offset_blk + length_blk, 0, (impl->hdrlen >> impl->bpow)) ||
IW_RANGES_OVERLAP(offset_blk, offset_blk + length_blk, (impl->bmoff >> impl->bpow),
(impl->bmoff >> impl->bpow) + (impl->bmlen >> impl->bpow))) {
if ( IW_RANGES_OVERLAP(offset_blk, offset_blk + length_blk, 0, (impl->hdrlen >> impl->bpow))
|| IW_RANGES_OVERLAP(offset_blk, offset_blk + length_blk, (impl->bmoff >> impl->bpow),
(impl->bmoff >> impl->bpow) + (impl->bmlen >> impl->bpow))) {
IWRC(_fsm_ctrl_unlock(impl), rc);
return IWFS_ERROR_FSM_SEGMENTATION;
}
@@ -1727,7 +1744,9 @@ static iwrc _fsm_writehdr(struct IWFS_FSM *f, off_t off, const void *buf, off_t
FSM_ENSURE_OPEN2(f);
iwrc rc;
uint8_t *mm;
if (siz < 1) return 0;
if (siz < 1) {
return 0;
}
FSM *impl = f->impl;
if ((IWFSM_CUSTOM_HDR_DATA_OFFSET + off + siz) > impl->hdrlen) {
return IW_ERROR_OUT_OF_BOUNDS;
@@ -1747,7 +1766,9 @@ static iwrc _fsm_readhdr(struct IWFS_FSM *f, off_t off, void *buf, off_t siz) {
FSM_ENSURE_OPEN2(f);
iwrc rc;
uint8_t *mm;
if (siz < 1) return 0;
if (siz < 1) {
return 0;
}
FSM *impl = f->impl;
if ((IWFSM_CUSTOM_HDR_DATA_OFFSET + off + siz) > impl->hdrlen) {
return IW_ERROR_OUT_OF_BOUNDS;
@@ -1815,7 +1836,7 @@ static iwrc _fsm_state(struct IWFS_FSM *f, IWFS_FSM_STATE *state) {
iwrc iwfs_fsmfile_open(IWFS_FSM *f, const IWFS_FSM_OPTS *opts) {
assert(f && opts);
iwrc rc = 0;
IWFS_EXT_STATE fstate = {0};
IWFS_EXT_STATE fstate = { 0 };
const char *path = opts->exfile.file.path;
memset(f, 0, sizeof(*f));
@@ -1890,8 +1911,8 @@ finish:
return rc;
}
static const char *_fsmfile_ecodefn(locale_t locale, uint32_t ecode) {
if (!(ecode > _IWFS_FSM_ERROR_START && ecode < _IWFS_FSM_ERROR_END)) {
static const char* _fsmfile_ecodefn(locale_t locale, uint32_t ecode) {
if (!((ecode > _IWFS_FSM_ERROR_START) && (ecode < _IWFS_FSM_ERROR_END))) {
return 0;
}
switch (ecode) {
@@ -1929,8 +1950,8 @@ iwrc iwfs_fsmfile_init(void) {
}
/*************************************************************************************************
* Debug API *
*************************************************************************************************/
* Debug API *
*************************************************************************************************/
uint64_t iwfs_fsmdbg_number_of_free_areas(IWFS_FSM *f) {
int ret;
@@ -1942,13 +1963,15 @@ uint64_t iwfs_fsmdbg_number_of_free_areas(IWFS_FSM *f) {
return (uint64_t) ret;
}
uint64_t iwfs_fsmdbg_find_next_set_bit(const uint64_t *addr, uint64_t offset_bit, uint64_t max_offset_bit,
int *found) {
uint64_t iwfs_fsmdbg_find_next_set_bit(
const uint64_t *addr, uint64_t offset_bit, uint64_t max_offset_bit,
int *found) {
return _fsm_find_next_set_bit(addr, offset_bit, max_offset_bit, found);
}
uint64_t iwfs_fsmdbg_find_prev_set_bit(const uint64_t *addr, uint64_t offset_bit, uint64_t min_offset_bit,
int *found) {
uint64_t iwfs_fsmdbg_find_prev_set_bit(
const uint64_t *addr, uint64_t offset_bit, uint64_t min_offset_bit,
int *found) {
return _fsm_find_prev_set_bit(addr, offset_bit, min_offset_bit, found);
}
@@ -1970,8 +1993,7 @@ void iwfs_fsmdbg_dump_fsm_tree(IWFS_FSM *f, const char *hdr) {
#undef _fsm_traverse
}
const char *byte_to_binary(int x) {
const char* byte_to_binary(int x) {
static char b[9];
b[0] = '\0';
int z;
@@ -1981,7 +2003,6 @@ const char *byte_to_binary(int x) {
return b;
}
iwrc iwfs_fsmdb_dump_fsm_bitmap(IWFS_FSM *f) {
assert(f);
size_t sp;
@@ -2009,7 +2030,7 @@ iwrc iwfs_fsmdb_dump_fsm_bitmap(IWFS_FSM *f) {
// if (impl->bmoff == impl->aunit) {
// i += ((impl->bmlen >> impl->bpow) >> 3);
// }
for (; i < sp && i < impl->bmlen; ++i) {
for ( ; i < sp && i < impl->bmlen; ++i) {
uint8_t b = *(mm + i);
fprintf(stderr, "%s", byte_to_binary(b));
}
@@ -2017,7 +2038,6 @@ iwrc iwfs_fsmdb_dump_fsm_bitmap(IWFS_FSM *f) {
return 0;
}
iwrc iwfs_fsmdbg_state(IWFS_FSM *f, IWFS_FSMDBG_STATE *d) {
FSM_ENSURE_OPEN2(f);
FSM *impl = f->impl;
+62 -56
View File
@@ -7,7 +7,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -72,7 +72,7 @@
* - <b>crszvar</b> Allocated areas length standard variance (deviation^2 * N) (64 bit)
* - <b>reserved:</b> Reserved space.
* - <b>custom header size:</b> Length of custom header area. See
`IWFS_FSM::writehdr` and `IWFS_FSM::readhdr`
`IWFS_FSM::writehdr` and `IWFS_FSM::readhdr`
*/
#include "iwexfile.h"
@@ -87,34 +87,34 @@ IW_EXTERN_C_START
typedef uint8_t iwfs_fsm_aflags;
/** Use default allocation settings */
#define IWFSM_ALLOC_DEFAULTS ((iwfs_fsm_aflags) 0x00U)
#define IWFSM_ALLOC_DEFAULTS ((iwfs_fsm_aflags) 0x00U)
/** Do not @em overallocate a requested free space in order to reduce fragmentation */
#define IWFSM_ALLOC_NO_OVERALLOCATE ((iwfs_fsm_aflags) 0x01U)
#define IWFSM_ALLOC_NO_OVERALLOCATE ((iwfs_fsm_aflags) 0x01U)
/** Do not extend the file and its bitmap free space mapping in the case if
* file size expansion is required.
* In this case the `IWFS_ERROR_NO_FREE_SPACE` error will be raised.*/
#define IWFSM_ALLOC_NO_EXTEND ((iwfs_fsm_aflags) 0x02U)
#define IWFSM_ALLOC_NO_EXTEND ((iwfs_fsm_aflags) 0x02U)
/** Force offset of an allocated space to be page aligned. */
#define IWFSM_ALLOC_PAGE_ALIGNED ((iwfs_fsm_aflags) 0x04U)
#define IWFSM_ALLOC_PAGE_ALIGNED ((iwfs_fsm_aflags) 0x04U)
/** Do not collect internal allocation stats for this allocation. */
#define IWFSM_ALLOC_NO_STATS ((iwfs_fsm_aflags) 0x08U)
#define IWFSM_ALLOC_NO_STATS ((iwfs_fsm_aflags) 0x08U)
/** Force all of the allocated address space backed by real file address space. */
#define IWFSM_SOLID_ALLOCATED_SPACE ((iwfs_fsm_aflags) 0x10U)
#define IWFSM_SOLID_ALLOCATED_SPACE ((iwfs_fsm_aflags) 0x10U)
/** Do msync of bitmap allocation index. */
#define IWFSM_SYNC_BMAP ((iwfs_fsm_aflags) 0x20U)
#define IWFSM_SYNC_BMAP ((iwfs_fsm_aflags) 0x20U)
#define IWFSM_MAGICK 0x19cc7cc
#define IWFSM_CUSTOM_HDR_DATA_OFFSET \
(4 /*magic*/ + 1 /*block pow*/ + 8 /*fsm bitmap block offset */ + 8 /*fsm bitmap block length*/ + \
8 /*all allocated block length sum */ + 4 /*number of all allocated areas */ + \
8 /* allocated areas length standard variance (deviation^2 * N) */ + 32 /*reserved*/ + \
4 /*custom hdr size*/)
(4 /*magic*/ + 1 /*block pow*/ + 8 /*fsm bitmap block offset */ + 8 /*fsm bitmap block length*/ \
+ 8 /*all allocated block length sum */ + 4 /*number of all allocated areas */ \
+ 8 /* allocated areas length standard variance (deviation^2 * N) */ + 32 /*reserved*/ \
+ 4 /*custom hdr size*/)
/** File cleanup flags used in `IWFS_FSM::clear` */
typedef uint8_t iwfs_fsm_clrfalgs;
@@ -141,14 +141,16 @@ typedef enum {
_IWFS_FSM_ERROR_START = (IW_ERROR_START + 4000UL),
IWFS_ERROR_NO_FREE_SPACE, /**< No free space. */
IWFS_ERROR_INVALID_BLOCK_SIZE, /**< Invalid block size specified */
IWFS_ERROR_RANGE_NOT_ALIGNED, /**< Specified range/offset is not aligned with
page/block */
IWFS_ERROR_RANGE_NOT_ALIGNED,
/**< Specified range/offset is not aligned with
page/block */
IWFS_ERROR_FSM_SEGMENTATION, /**< Free-space map segmentation error */
IWFS_ERROR_INVALID_FILEMETA, /**< Invalid file-metadata */
IWFS_ERROR_PLATFORM_PAGE, /**< Platform page size incopatibility, data
migration required. */
IWFS_ERROR_PLATFORM_PAGE,
/**< Platform page size incopatibility, data
migration required. */
IWFS_ERROR_RESIZE_FAIL, /**< Failed to resize file */
_IWFS_FSM_ERROR_END
_IWFS_FSM_ERROR_END,
} iwfs_fsm_ecode;
/**
@@ -157,12 +159,12 @@ typedef enum {
*/
typedef struct IWFS_FSM_OPTS {
IWFS_EXT_OPTS exfile;
size_t bmlen; /**< Initial size of free-space bitmap */
size_t bmlen; /**< Initial size of free-space bitmap */
uint32_t hdrlen; /**< Length of custom file header.*/
iwfs_fsm_openflags oflags; /**< Operation mode flags */
iwfs_fsm_openflags oflags; /**< Operation mode flags */
iwfs_ext_mmap_opts_t mmap_opts; /**< Defaul mmap options used in `add_mmap` */
uint8_t bpow; /**< Block size power for 2 */
bool mmap_all; /**< Mmap all file data */
bool mmap_all; /**< Mmap all file data */
} IWFS_FSM_OPTS;
/**
@@ -170,11 +172,11 @@ typedef struct IWFS_FSM_OPTS {
* @see IWFS_FSM::state
*/
typedef struct IWFS_FSM_STATE {
IWFS_EXT_STATE exfile; /**< File pool state */
size_t block_size; /**< Size of data block in bytes. */
iwfs_fsm_openflags oflags; /**< Operation mode flags. */
uint32_t hdrlen; /**< Length of custom file header length in bytes */
uint64_t blocks_num; /**< Number of available data blocks. */
IWFS_EXT_STATE exfile; /**< File pool state */
size_t block_size; /**< Size of data block in bytes. */
iwfs_fsm_openflags oflags; /**< Operation mode flags. */
uint32_t hdrlen; /**< Length of custom file header length in bytes */
uint64_t blocks_num; /**< Number of available data blocks. */
uint64_t free_segments_num; /**< Number of free (deallocated) continuous data
segments. */
double_t avg_alloc_size; /**< Average allocation number of blocks */
@@ -183,10 +185,10 @@ typedef struct IWFS_FSM_STATE {
typedef struct IWFS_FSMDBG_STATE {
IWFS_FSM_STATE state;
uint64_t bmoff;
uint64_t bmlen;
uint64_t lfbklen;
uint64_t lfbkoff;
uint64_t bmoff;
uint64_t bmlen;
uint64_t lfbklen;
uint64_t lfbkoff;
} IWFS_FSMDBG_STATE;
/**
@@ -214,8 +216,9 @@ typedef struct IWFS_FSM {
* @param opts Allocation options bitmask flag @ref iwfs_fsm_aflags
* @return `0` on success or error code.
*/
iwrc(*allocate)(struct IWFS_FSM *f, off_t len, off_t *oaddr, off_t *olen,
iwfs_fsm_aflags opts);
iwrc (*allocate)(
struct IWFS_FSM *f, off_t len, off_t *oaddr, off_t *olen,
iwfs_fsm_aflags opts);
/**
* @brief Reallocate and adjust a size of an allocated block.
@@ -233,8 +236,9 @@ typedef struct IWFS_FSM {
* @param opts Allocation options bitmask flag @ref iwfs_fsm_aflags
* @return `0` on success or error code.
*/
iwrc(*reallocate)(struct IWFS_FSM *f, off_t nlen, off_t *oaddr, off_t *olen,
iwfs_fsm_aflags opts);
iwrc (*reallocate)(
struct IWFS_FSM *f, off_t nlen, off_t *oaddr, off_t *olen,
iwfs_fsm_aflags opts);
/**
* @brief Free a previously allocated area.
@@ -243,14 +247,14 @@ typedef struct IWFS_FSM {
* @param len Length of area to release.
* @return `0` on success or error code.
*/
iwrc(*deallocate)(struct IWFS_FSM *f, off_t addr, off_t len);
iwrc (*deallocate)(struct IWFS_FSM *f, off_t addr, off_t len);
/**
* @brief Check allocation status of region specified by @a addr and @a len
* @return `0` on success or error code.
*/
iwrc(*check_allocation_status)(struct IWFS_FSM *f, off_t addr, off_t len, bool allocated);
iwrc (*check_allocation_status)(struct IWFS_FSM *f, off_t addr, off_t len, bool allocated);
/**
* @brief Write a data to the custom file header.
@@ -263,7 +267,7 @@ typedef struct IWFS_FSM {
* @param siz Number of bytes of @a buf to write into header.
* @return `0` on success or error code.
*/
iwrc(*writehdr)(struct IWFS_FSM *f, off_t off, const void *buf, off_t siz);
iwrc (*writehdr)(struct IWFS_FSM *f, off_t off, const void *buf, off_t siz);
/**
* @brief Read a data from the custom file header.
@@ -275,7 +279,7 @@ typedef struct IWFS_FSM {
* @param [out] buf Data buffer to read into
* @param Number of bytes to read
*/
iwrc(*readhdr)(struct IWFS_FSM *f, off_t off, void *buf, off_t siz);
iwrc (*readhdr)(struct IWFS_FSM *f, off_t off, void *buf, off_t siz);
/**
* @brief Cleanup all allocated data blocks and reset the file to the initial
@@ -284,20 +288,20 @@ typedef struct IWFS_FSM {
* @param clrflags
* @return `0` on success or error code.
*/
iwrc(*clear)(struct IWFS_FSM *f, iwfs_fsm_clrfalgs clrflags);
iwrc (*clear)(struct IWFS_FSM *f, iwfs_fsm_clrfalgs clrflags);
/* See iwexfile.h */
/** @see IWFS_EXT::ensure_size */
iwrc(*ensure_size)(struct IWFS_FSM *f, off_t size);
iwrc (*ensure_size)(struct IWFS_FSM *f, off_t size);
/** @see IWFS_EXT::add_mmap */
iwrc(*add_mmap)(struct IWFS_FSM *f, off_t off, size_t maxlen, iwfs_ext_mmap_opts_t opts);
iwrc (*add_mmap)(struct IWFS_FSM *f, off_t off, size_t maxlen, iwfs_ext_mmap_opts_t opts);
/** @see IWFS_EXT::remap_all */
iwrc(*remap_all)(struct IWFS_FSM *f);
iwrc (*remap_all)(struct IWFS_FSM *f);
/**
* @brief Get a pointer to the registered mmap area starting at `off`.
@@ -309,46 +313,47 @@ typedef struct IWFS_FSM {
* @see IWFS_FSM::add_mmap
* @see IWFS_EXT::acquire_mmap
*/
iwrc(*acquire_mmap)(struct IWFS_FSM *f, off_t off, uint8_t **mm, size_t *sp);
iwrc (*acquire_mmap)(struct IWFS_FSM *f, off_t off, uint8_t **mm, size_t *sp);
/**
* @brief Retrieve mmaped region by its offset @a off
*/
iwrc(*probe_mmap)(struct IWFS_FSM *f, off_t off, uint8_t **mm, size_t *sp);
iwrc (*probe_mmap)(struct IWFS_FSM *f, off_t off, uint8_t **mm, size_t *sp);
/**
* @brief Release the lock acquired by successfull call of `acquire_mmap()`
*/
iwrc(*release_mmap)(struct IWFS_FSM *f);
iwrc (*release_mmap)(struct IWFS_FSM *f);
/** @see IWFS_EXT::remove_mmap */
iwrc(*remove_mmap)(struct IWFS_FSM *f, off_t off);
iwrc (*remove_mmap)(struct IWFS_FSM *f, off_t off);
/** @see IWFS_EXT::sync_mmap */
iwrc(*sync_mmap)(struct IWFS_FSM *f, off_t off, iwfs_sync_flags flags);
iwrc (*sync_mmap)(struct IWFS_FSM *f, off_t off, iwfs_sync_flags flags);
/* See iwfile.h */
/** @see IWFS_FILE::write */
iwrc(*write)(struct IWFS_FSM *f, off_t off, const void *buf, size_t siz,
size_t *sp);
iwrc (*write)(
struct IWFS_FSM *f, off_t off, const void *buf, size_t siz,
size_t *sp);
/** @see IWFS_FILE::read */
iwrc(*read)(struct IWFS_FSM *f, off_t off, void *buf, size_t siz,
size_t *sp);
iwrc (*read)(
struct IWFS_FSM *f, off_t off, void *buf, size_t siz,
size_t *sp);
/** @see IWFS_FILE::close */
iwrc(*close)(struct IWFS_FSM *f);
iwrc (*close)(struct IWFS_FSM *f);
/** @see IWFS_FILE::sync */
iwrc(*sync)(struct IWFS_FSM *f, iwfs_sync_flags flags);
iwrc (*sync)(struct IWFS_FSM *f, iwfs_sync_flags flags);
/** @see IWFS_FILE::state */
iwrc(*state)(struct IWFS_FSM *f, IWFS_FSM_STATE *state);
iwrc (*state)(struct IWFS_FSM *f, IWFS_FSM_STATE *state);
/** get access to the underlying iwextfile instance */
iwrc(*extfile)(struct IWFS_FSM *f, IWFS_EXT **ext);
iwrc (*extfile)(struct IWFS_FSM *f, IWFS_EXT **ext);
} IWFS_FSM;
/**
@@ -399,6 +404,7 @@ typedef struct IWFS_FSM {
* @relatesalso IWFS_FSM
*/
IW_EXPORT WUR iwrc iwfs_fsmfile_open(IWFS_FSM *f, const IWFS_FSM_OPTS *opts);
/**
* @brief Init `iwfsmfile` submodule.
*/
+21 -20
View File
@@ -4,7 +4,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -41,7 +41,6 @@
unlink("test_mmap1.dat"); \
unlink("test_fibo_inc.dat")
int init_suite() {
int rc = iw_init();
UNLINK();
@@ -59,12 +58,12 @@ void iwfs_exfile_test1() {
const char *path = "iwfs_exfile_test1.dat";
IWFS_EXT_OPTS opts = {
.file = {
.path = path,
.file = {
.path = path,
.lock_mode = IWP_WLOCK,
.omode = IWFS_DEFAULT_OMODE | IWFS_OTRUNC
.omode = IWFS_DEFAULT_OMODE | IWFS_OTRUNC
},
.use_locks = 1
.use_locks = 1
};
IWRC(iwfs_exfile_open(&ef, &opts), rc);
CU_ASSERT_EQUAL_FATAL(rc, 0);
@@ -126,8 +125,8 @@ void iwfs_exfile_test1_2() {
IWFS_EXT f;
const char *path = "exfile_test1_2-"; // Temp file prefix
IWFS_EXT_OPTS opts = {
.file = {
.path = path,
.file = {
.path = path,
.omode = IWFS_OTMP | IWFS_OUNLINK
}
};
@@ -159,17 +158,17 @@ void test_fibo_inc(void) {
const char *path = "test_fibo_inc.dat";
IWFS_EXT ef;
IWFS_EXT_OPTS opts = {
.file = {
.path = path,
.file = {
.path = path,
.lock_mode = IWP_WLOCK,
.omode = IWFS_DEFAULT_OMODE | IWFS_OTRUNC
.omode = IWFS_DEFAULT_OMODE | IWFS_OTRUNC
},
.use_locks = 0,
.rspolicy = iw_exfile_szpolicy_fibo
.use_locks = 0,
.rspolicy = iw_exfile_szpolicy_fibo
};
iwrc rc = 0;
size_t sp;
uint64_t wd = (uint64_t)(-1);
uint64_t wd = (uint64_t) (-1);
IWRC(iwfs_exfile_open(&ef, &opts), rc);
CU_ASSERT_EQUAL_FATAL(rc, 0);
@@ -220,7 +219,7 @@ void test_mmap1(void) {
const char *path = "test_mmap1.dat";
IWFS_EXT ef;
IWFS_EXT_OPTS opts = {.file = {.path = path, .omode = IWFS_OTRUNC}, .use_locks = 0};
IWFS_EXT_OPTS opts = { .file = { .path = path, .omode = IWFS_OTRUNC }, .use_locks = 0 };
for (int i = 0; i < dsize; ++i) {
data[i] = iwu_rand_range(256);
@@ -344,7 +343,9 @@ int main() {
CU_pSuite pSuite = NULL;
/* Initialize the CUnit test registry */
if (CUE_SUCCESS != CU_initialize_registry()) return CU_get_error();
if (CUE_SUCCESS != CU_initialize_registry()) {
return CU_get_error();
}
/* Add a suite to the registry */
pSuite = CU_add_suite("iwfs_test1", init_suite, clean_suite);
@@ -355,10 +356,10 @@ int main() {
}
/* Add the tests to the suite */
if ((NULL == CU_add_test(pSuite, "iwfs_exfile_test1", iwfs_exfile_test1)) ||
(NULL == CU_add_test(pSuite, "iwfs_exfile_test1_2", iwfs_exfile_test1_2)) ||
(NULL == CU_add_test(pSuite, "test_fibo_inc", test_fibo_inc)) ||
(NULL == CU_add_test(pSuite, "test_mmap1", test_mmap1))) {
if ( (NULL == CU_add_test(pSuite, "iwfs_exfile_test1", iwfs_exfile_test1))
|| (NULL == CU_add_test(pSuite, "iwfs_exfile_test1_2", iwfs_exfile_test1_2))
|| (NULL == CU_add_test(pSuite, "test_fibo_inc", test_fibo_inc))
|| (NULL == CU_add_test(pSuite, "test_mmap1", test_mmap1))) {
CU_cleanup_registry();
return CU_get_error();
}
+65 -62
View File
@@ -4,7 +4,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -61,14 +61,16 @@ int clean_suite(void) {
}
uint64_t iwfs_fsmdbg_number_of_free_areas(IWFS_FSM *f);
uint64_t iwfs_fsmdbg_find_next_set_bit(const uint64_t *addr,
uint64_t offset_bit,
uint64_t max_offset_bit,
int *found);
uint64_t iwfs_fsmdbg_find_prev_set_bit(const uint64_t *addr,
uint64_t offset_bit,
uint64_t min_offset_bit,
int *found);
uint64_t iwfs_fsmdbg_find_next_set_bit(
const uint64_t *addr,
uint64_t offset_bit,
uint64_t max_offset_bit,
int *found);
uint64_t iwfs_fsmdbg_find_prev_set_bit(
const uint64_t *addr,
uint64_t offset_bit,
uint64_t min_offset_bit,
int *found);
void iwfs_fsmdbg_dump_fsm_tree(IWFS_FSM *f, const char *hdr);
iwrc iwfs_fsmdbg_state(IWFS_FSM *f, IWFS_FSMDBG_STATE *d);
iwrc iwfs_fsmdb_dump_fsm_bitmap(IWFS_FSM *f, int blimit);
@@ -220,14 +222,14 @@ void test_fsm_bitmap(void) {
void test_fsm_open_close(void) {
iwrc rc;
IWFS_FSM_OPTS opts = {
.exfile = {
.file = {.path = "test_fsm_open_close.fsm", .lock_mode = IWP_WLOCK},
.rspolicy = iw_exfile_szpolicy_fibo,
.exfile = {
.file = { .path = "test_fsm_open_close.fsm", .lock_mode = IWP_WLOCK },
.rspolicy = iw_exfile_szpolicy_fibo,
.initial_size = 0
},
.bpow = 6,
.hdrlen = 64,
.oflags = IWFSM_STRICT
.bpow = 6,
.hdrlen = 64,
.oflags = IWFSM_STRICT
};
size_t aunit = iwp_alloc_unit();
@@ -260,14 +262,13 @@ void test_fsm_open_close(void) {
CU_ASSERT_FALSE_FATAL(rc);
}
void test_fsm_uniform_alloc_impl(int mmap_all);
void test_fsm_uniform_alloc(void) {
void test_fsm_uniform_alloc(void) {
test_fsm_uniform_alloc_impl(0);
}
void test_fsm_uniform_alloc_mmap_all(void) {
void test_fsm_uniform_alloc_mmap_all(void) {
test_fsm_uniform_alloc_impl(1);
}
@@ -275,18 +276,18 @@ void test_fsm_uniform_alloc_impl(int mmap_all) {
iwrc rc;
IWFS_FSMDBG_STATE state1, state2;
IWFS_FSM_OPTS opts = {
.exfile = {
.file = {
.path = "test_fsm_uniform_alloc.fsm",
.exfile = {
.file = {
.path = "test_fsm_uniform_alloc.fsm",
.lock_mode = IWP_WLOCK,
.omode = IWFS_OTRUNC
.omode = IWFS_OTRUNC
},
.rspolicy = iw_exfile_szpolicy_fibo
.rspolicy = iw_exfile_szpolicy_fibo
},
.bpow = 6,
.hdrlen = 64,
.oflags = IWFSM_STRICT,
.mmap_all = mmap_all
.bpow = 6,
.hdrlen = 64,
.oflags = IWFSM_STRICT,
.mmap_all = mmap_all
};
typedef struct {
@@ -348,7 +349,7 @@ void test_fsm_uniform_alloc_impl(int mmap_all) {
uint32_t ibuf;
off_t ilen;
rc = fsm.allocate(&fsm, sizeof(ibuf), (void *) &ibuf, &ilen, 0);
rc = fsm.allocate(&fsm, sizeof(ibuf), (void*) &ibuf, &ilen, 0);
CU_ASSERT_EQUAL(rc, IW_ERROR_READONLY);
rc = fsm.close(&fsm);
@@ -373,7 +374,7 @@ void test_fsm_uniform_alloc_impl(int mmap_all) {
}
int i = 0;
for (; i < bcnt; ++i) {
for ( ; i < bcnt; ++i) {
rc = fsm.deallocate(&fsm, aslots[i].addr, aslots[i].len);
if (rc) {
iwlog_ecode_error3(rc);
@@ -395,18 +396,18 @@ void test_fsm_uniform_alloc_impl(int mmap_all) {
typedef struct FSMREC {
int64_t offset;
int64_t length;
int locked;
int locked;
struct FSMREC *prev;
struct FSMREC *next;
} FSMREC;
typedef struct {
int maxrecs;
int avgrecsz;
int maxrecs;
int avgrecsz;
IWFS_FSM *fsm;
volatile int numrecs;
FSMREC *reclist;
FSMREC *head;
FSMREC *reclist;
FSMREC *head;
int blkpow;
} FSMRECTASK;
@@ -471,7 +472,7 @@ static void *recordsthr(void *op) {
while (rec && rec->prev) {
++i;
a = rand() % 3;
if (a == 0 || a == 1) { /* realloc */
if ((a == 0) || (a == 1)) { /* realloc */
pthread_mutex_lock(&records_mtx);
if (rec->locked) {
rec = rec->next;
@@ -517,7 +518,6 @@ static void *recordsthr(void *op) {
pthread_mutex_lock(&records_mtx);
rec->locked = 0;
pthread_mutex_unlock(&records_mtx);
} else {
// TODO
@@ -540,13 +540,13 @@ void test_block_allocation_impl(int mmap_all, int nthreads, int numrec, int avgr
pthread_t *tlist = malloc(nthreads * sizeof(pthread_t));
IWFS_FSM_OPTS opts = {
.exfile = {
.file = {.path = path, .omode = IWFS_OTRUNC},
.exfile = {
.file = { .path = path, .omode = IWFS_OTRUNC },
.rspolicy = iw_exfile_szpolicy_fibo
},
.bpow = blkpow,
.oflags = IWFSM_STRICT,
.mmap_all = mmap_all
.bpow = blkpow,
.oflags = IWFSM_STRICT,
.mmap_all = mmap_all
};
FSMRECTASK task;
@@ -584,11 +584,12 @@ void test_block_allocation_impl(int mmap_all, int nthreads, int numrec, int avgr
free(tlist);
}
void test_block_allocation1_impl(int mmap_all);
void test_block_allocation1(void) {
test_block_allocation1_impl(0);
}
void test_block_allocation1_mmap_all(void) {
test_block_allocation1_impl(1);
}
@@ -598,16 +599,16 @@ void test_block_allocation1_impl(int mmap_all) {
IWFS_FSM fsm;
int psize = iwp_alloc_unit();
IWFS_FSM_OPTS opts = {
.exfile = {
.file = {
.path = "test_block_allocation1.fsm",
.exfile = {
.file = {
.path = "test_block_allocation1.fsm",
.omode = IWFS_OTRUNC
}
},
.hdrlen = psize - 2 * 64,
.bpow = 6,
.oflags = IWFSM_STRICT,
.mmap_all = mmap_all
.hdrlen = psize - 2 * 64,
.bpow = 6,
.oflags = IWFSM_STRICT,
.mmap_all = mmap_all
};
off_t oaddr = 0;
@@ -686,7 +687,7 @@ void test_block_allocation1_impl(int mmap_all) {
// Test reallocate
/* Next alloc status:
*xxx*** */
* xxx*** */
rc = fsm.deallocate(&fsm, hoff + 4 * bsize, 3 * bsize);
CU_ASSERT_FALSE_FATAL(rc);
rc = fsm.deallocate(&fsm, hoff, 1 * bsize);
@@ -694,7 +695,7 @@ void test_block_allocation1_impl(int mmap_all) {
CU_ASSERT_EQUAL(iwfs_fsmdbg_number_of_free_areas(&fsm), 2);
/* Next alloc status:
*xx**** */
* xx**** */
oaddr = hoff + 1 * bsize;
olen = 3 * bsize;
rc = fsm.reallocate(&fsm, 2 * bsize, &oaddr, &olen, 0);
@@ -704,7 +705,7 @@ void test_block_allocation1_impl(int mmap_all) {
CU_ASSERT_EQUAL(iwfs_fsmdbg_number_of_free_areas(&fsm), 2);
/* Next alloc status:
*xxxxxx */
* xxxxxx */
// rc = fsm.reallocate(&fsm, 6 * bsize, &oaddr, &olen, 0);
// CU_ASSERT_FALSE_FATAL(rc);
// CU_ASSERT_EQUAL(oaddr, hoff + 1 * bsize);
@@ -727,9 +728,11 @@ void test_block_allocation1_impl(int mmap_all) {
}
void test_block_allocation2_impl(int mmap_all);
void test_block_allocation2() {
test_block_allocation2_impl(0);
}
void test_block_allocation2_mmap_all() {
test_block_allocation2_impl(1);
}
@@ -743,8 +746,9 @@ int main() {
CU_pSuite pSuite = NULL;
/* Initialize the CUnit test registry */
if (CUE_SUCCESS != CU_initialize_registry())
if (CUE_SUCCESS != CU_initialize_registry()) {
return CU_get_error();
}
/* Add a suite to the registry */
pSuite = CU_add_suite("iwfs_test2", init_suite, clean_suite);
@@ -755,15 +759,14 @@ int main() {
}
/* Add the tests to the suite */
if ((NULL == CU_add_test(pSuite, "test_fsm_bitmap", test_fsm_bitmap)) ||
(NULL == CU_add_test(pSuite, "test_fsm_open_close", test_fsm_open_close)) ||
(NULL == CU_add_test(pSuite, "test_fsm_uniform_alloc", test_fsm_uniform_alloc)) ||
(NULL == CU_add_test(pSuite, "test_fsm_uniform_alloc_mmap_all", test_fsm_uniform_alloc_mmap_all)) ||
(NULL == CU_add_test(pSuite, "test_block_allocation1", test_block_allocation1)) ||
(NULL == CU_add_test(pSuite, "test_block_allocation1_mmap_all", test_block_allocation1_mmap_all)) ||
(NULL == CU_add_test(pSuite, "test_block_allocation2", test_block_allocation2)) ||
NULL == CU_add_test(pSuite, "test_block_allocation2_mmap_all", test_block_allocation2_mmap_all)
) {
if ( (NULL == CU_add_test(pSuite, "test_fsm_bitmap", test_fsm_bitmap))
|| (NULL == CU_add_test(pSuite, "test_fsm_open_close", test_fsm_open_close))
|| (NULL == CU_add_test(pSuite, "test_fsm_uniform_alloc", test_fsm_uniform_alloc))
|| (NULL == CU_add_test(pSuite, "test_fsm_uniform_alloc_mmap_all", test_fsm_uniform_alloc_mmap_all))
|| (NULL == CU_add_test(pSuite, "test_block_allocation1", test_block_allocation1))
|| (NULL == CU_add_test(pSuite, "test_block_allocation1_mmap_all", test_block_allocation1_mmap_all))
|| (NULL == CU_add_test(pSuite, "test_block_allocation2", test_block_allocation2))
|| (NULL == CU_add_test(pSuite, "test_block_allocation2_mmap_all", test_block_allocation2_mmap_all))) {
CU_cleanup_registry();
return CU_get_error();
}
+23 -24
View File
@@ -12,7 +12,7 @@
#include "utils/kbtree.h"
#define NRECS 10000
#define RECSZ (10*1024)
#define RECSZ (10 * 1024)
#define UNLINK() \
unlink("test_fsm_stress.data"); \
@@ -20,13 +20,13 @@
unlink("test_fsm_stress2.fsm")
typedef struct SREC {
int id;
int id;
off_t addr;
off_t rsz;
off_t alc_addr;
off_t alc_len;
bool freed;
bool reallocated;
bool freed;
bool reallocated;
} SREC;
#define _srec_cmp(r1, r2) ((r1).id - (r2).id)
@@ -34,7 +34,7 @@ typedef struct SREC {
KBTREE_INIT(rt, SREC, _srec_cmp)
FILE *fstress1;
kbtree_t(rt) *rt;
kbtree_t(rt) * rt;
int init_suite(void) {
UNLINK();
@@ -48,7 +48,7 @@ int init_suite(void) {
rc = iwp_current_time_ms(&ts, false);
RCRET(rc);
ts = IW_SWAB64(ts);
ts >>= 32;
ts >>= 32;
iwu_rand_seed(ts);
printf("Generating stress data file: test_fsm_stress1.data, random seed: %" PRIu64, ts);
@@ -65,9 +65,9 @@ int init_suite(void) {
buf[j] = '\0';
fprintf(fstress1, "%08d:%s\n", i, buf);
SREC rec = {
.id = i,
.addr = addr,
.rsz = rsz,
.id = i,
.addr = addr,
.rsz = rsz,
.freed = false
};
addr += (8 + 1 + rsz + 1);
@@ -90,16 +90,16 @@ int clean_suite(void) {
void test_stress(char *path, int bpow, bool mmap_all) {
IWFS_FSM fsm;
IWFS_FSM_OPTS opts = {
.exfile = {
.file = {
.path = path,
.exfile = {
.file = {
.path = path,
.omode = IWFS_OTRUNC
}
},
.hdrlen = 62,
.bpow = bpow,
.oflags = IWFSM_STRICT,
.mmap_all = mmap_all
.hdrlen = 62,
.bpow = bpow,
.oflags = IWFSM_STRICT,
.mmap_all = mmap_all
};
iwrc rc = iwfs_fsmfile_open(&fsm, &opts);
CU_ASSERT_FALSE_FATAL(rc);
@@ -109,10 +109,10 @@ void test_stress(char *path, int bpow, bool mmap_all) {
char *buf = malloc(2 * RECSZ + 1);
for (int i = 0; i < NRECS; ++i) {
size_t sp;
SREC k = {.id = i};
SREC k = { .id = i };
iwfs_fsm_aflags aflags = IWFSM_SOLID_ALLOCATED_SPACE | IWFSM_ALLOC_NO_OVERALLOCATE;
uint32_t rop = iwu_rand_u32();
if (i > 0 && (!(rop % 3) || !(rop % 5))) {
if ((i > 0) && (!(rop % 3) || !(rop % 5))) {
k.id = iwu_rand_range(i);
SREC *pr = kb_getp(rt, rt, &k);
CU_ASSERT_PTR_NOT_NULL_FATAL(pr);
@@ -184,7 +184,7 @@ void test_stress(char *path, int bpow, bool mmap_all) {
char *buf2 = malloc(2 * RECSZ + 1);
for (int i = 0; i < NRECS; ++i) {
size_t sp;
SREC k = {.id = i};
SREC k = { .id = i };
SREC *r = kb_getp(rt, rt, &k);
CU_ASSERT_PTR_NOT_NULL_FATAL(r);
if (r->freed) {
@@ -234,8 +234,9 @@ int main() {
CU_pSuite pSuite = NULL;
/* Initialize the CUnit test registry */
if (CUE_SUCCESS != CU_initialize_registry())
if (CUE_SUCCESS != CU_initialize_registry()) {
return CU_get_error();
}
/* Add a suite to the registry */
pSuite = CU_add_suite("iwfs_test3", init_suite, clean_suite);
@@ -246,10 +247,8 @@ int main() {
}
/* Add the tests to the suite */
if (
(NULL == CU_add_test(pSuite, "test_stress1", test_stress1)) ||
(NULL == CU_add_test(pSuite, "test_stress2", test_stress2))
) {
if ( (NULL == CU_add_test(pSuite, "test_stress1", test_stress1))
|| (NULL == CU_add_test(pSuite, "test_stress2", test_stress2))) {
CU_cleanup_registry();
return CU_get_error();
}
+1 -1
View File
@@ -4,7 +4,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+2 -2
View File
@@ -7,7 +7,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -37,7 +37,7 @@ IW_EXTERN_C_START
*/
IW_EXPORT WUR iwrc iw_init(void);
IW_EXPORT const char* iowow_version_full(void);
IW_EXPORT const char *iowow_version_full(void);
IW_EXPORT unsigned int iowow_version_major(void);
+2 -2
View File
@@ -56,10 +56,10 @@
#error Unknown CPU bits
#endif
#define IOWOW_VERSION "1.4.10"
#define IOWOW_VERSION "1.4.15"
#define IOWOW_VERSION_MAJOR 1
#define IOWOW_VERSION_MINOR 4
#define IOWOW_VERSION_PATCH 10
#define IOWOW_VERSION_PATCH 15
#ifndef static_assert
#define static_assert _Static_assert
+24 -15
View File
@@ -68,8 +68,8 @@ static bool db_close(BMCTX *ctx) {
static bool db_put(BMCTX *ctx, const IWKV_val *key, const IWKV_val *val, bool sync) {
BM_BDB *bmdb = ctx->db;
DBT bkey = {.data = key->data, .size = key->size};
DBT bval = {.data = val->data, .size = val->size};
DBT bkey = { .data = key->data, .size = key->size };
DBT bval = { .data = val->data, .size = val->size };
int ret = bmdb->dbp->put(bmdb->dbp, 0, &bkey, &bval, 0);
if (ret) {
fprintf(stderr, "db_put: %s\n", db_strerror(ret));
@@ -87,8 +87,8 @@ static bool db_put(BMCTX *ctx, const IWKV_val *key, const IWKV_val *val, bool sy
static bool db_get(BMCTX *ctx, const IWKV_val *key, IWKV_val *val, bool *found) {
BM_BDB *bmdb = ctx->db;
DBT bkey = {.data = key->data, .size = key->size};
DBT bval = {.flags = DB_DBT_MALLOC};
DBT bkey = { .data = key->data, .size = key->size };
DBT bval = { .flags = DB_DBT_MALLOC };
int ret = bmdb->dbp->get(bmdb->dbp, 0, &bkey, &bval, 0);
val->data = bval.data;
val->size = bval.size;
@@ -104,10 +104,9 @@ static bool db_get(BMCTX *ctx, const IWKV_val *key, IWKV_val *val, bool *found)
return ret == 0;
}
static bool db_del(BMCTX *ctx, const IWKV_val *key, bool sync) {
BM_BDB *bmdb = ctx->db;
DBT bkey = {.data = key->data, .size = key->size};
DBT bkey = { .data = key->data, .size = key->size };
int ret = bmdb->dbp->del(bmdb->dbp, 0, &bkey, 0);
if (ret == DB_NOTFOUND) {
ret = 0;
@@ -128,8 +127,8 @@ static bool db_del(BMCTX *ctx, const IWKV_val *key, bool sync) {
static bool db_read_seq(BMCTX *ctx, bool reverse) {
BM_BDB *bmdb = ctx->db;
DBC *curp;
DBT bkey = {.flags = DB_DBT_MALLOC};
DBT bval = {.flags = DB_DBT_MALLOC};
DBT bkey = { .flags = DB_DBT_MALLOC };
DBT bval = { .flags = DB_DBT_MALLOC };
int ret = bmdb->dbp->cursor(bmdb->dbp, 0, &curp, 0);
if (ret) {
fprintf(stderr, "db_read_seq: %s\n", db_strerror(ret));
@@ -139,8 +138,12 @@ static bool db_read_seq(BMCTX *ctx, bool reverse) {
if (ret == DB_NOTFOUND) {
ret = 0;
}
if (bkey.data) free(bkey.data);
if (bval.data) free(bval.data);
if (bkey.data) {
free(bkey.data);
}
if (bval.data) {
free(bval.data);
}
for (int i = 0; i < bm.param_num - 1 && !ret; ++i) {
bkey.data = 0;
@@ -152,8 +155,12 @@ static bool db_read_seq(BMCTX *ctx, bool reverse) {
} else if (ret) {
fprintf(stderr, "db_read_seq: %s\n", db_strerror(ret));
}
if (bkey.data) free(bkey.data);
if (bval.data) free(bval.data);
if (bkey.data) {
free(bkey.data);
}
if (bval.data) {
free(bval.data);
}
}
curp->close(curp);
@@ -163,8 +170,8 @@ static bool db_read_seq(BMCTX *ctx, bool reverse) {
static bool db_cursor_to_key(BMCTX *ctx, const IWKV_val *key, IWKV_val *val, bool *found) {
BM_BDB *bmdb = ctx->db;
DBC *curp;
DBT bkey = {.data = key->data, .size = key->size};
DBT bval = {.flags = DB_DBT_MALLOC};
DBT bkey = { .data = key->data, .size = key->size };
DBT bval = { .flags = DB_DBT_MALLOC };
int ret = bmdb->dbp->cursor(bmdb->dbp, 0, &curp, 0);
if (ret) {
fprintf(stderr, "db_cursor_to_key: %s\n", db_strerror(ret));
@@ -187,7 +194,9 @@ static bool db_cursor_to_key(BMCTX *ctx, const IWKV_val *key, IWKV_val *val, boo
}
int main(int argc, char **argv) {
if (argc < 1) return -1;
if (argc < 1) {
return -1;
}
g_program = argv[0];
bm.env_setup = env_setup;
bm.db_size_bytes = db_size_bytes;
+99 -67
View File
@@ -11,45 +11,45 @@ uint32_t _execsize();
typedef struct _BMCTX BMCTX;
typedef bool (bench_method(BMCTX *bmctx));
typedef bool(bench_method (BMCTX *bmctx));
#define RND_DATA_SZ (10*1048576)
#define RND_DATA_SZ (10 * 1048576)
char RND_DATA[RND_DATA_SZ];
struct BM {
bool initiated;
int ksz;
int argc;
char **argv;
char *param_db;
int param_num;
int param_num_reads;
int param_value_size;
bool initiated;
int ksz;
int argc;
char **argv;
char *param_db;
int param_num;
int param_num_reads;
int param_value_size;
uint32_t param_seed;
char *param_benchmarks;
void (*val_free)(void *ptr);
void (*env_setup)(void);
void *(*db_open)(BMCTX *ctx);
bool (*db_close)(BMCTX *ctx);
bool (*db_put)(BMCTX *ctx, const IWKV_val *key, const IWKV_val *val, bool sync);
bool (*db_get)(BMCTX *ctx, const IWKV_val *key, IWKV_val *val, bool *found);
bool (*db_cursor_to_key)(BMCTX *ctx, const IWKV_val *key, IWKV_val *val, bool *found);
bool (*db_del)(BMCTX *ctx, const IWKV_val *key, bool sync);
bool (*db_read_seq)(BMCTX *ctx, bool reverse);
char *param_benchmarks;
void (*val_free)(void *ptr);
void (*env_setup)(void);
void * (*db_open)(BMCTX *ctx);
bool (*db_close)(BMCTX *ctx);
bool (*db_put)(BMCTX *ctx, const IWKV_val *key, const IWKV_val *val, bool sync);
bool (*db_get)(BMCTX *ctx, const IWKV_val *key, IWKV_val *val, bool *found);
bool (*db_cursor_to_key)(BMCTX *ctx, const IWKV_val *key, IWKV_val *val, bool *found);
bool (*db_del)(BMCTX *ctx, const IWKV_val *key, bool sync);
bool (*db_read_seq)(BMCTX *ctx, bool reverse);
uint64_t (*db_size_bytes)(BMCTX *ctx);
} bm = {0};
} bm = { 0 };
struct _BMCTX {
bool success;
bool freshdb;
bool logdbsize;
char *name;
int num;
int value_size;
bool success;
bool freshdb;
bool logdbsize;
char *name;
int num;
int value_size;
uint64_t start_ms;
uint64_t end_ms;
void *db;
void *extra;
void *db;
void *extra;
bench_method *method;
int rnd_data_pos;
};
@@ -162,24 +162,24 @@ static bool _bm_init(int argc, char *argv[]) {
}
bm.argc = argc;
bm.argv = argv;
bm.param_num = 2000000; // 2M records
bm.param_num = 2000000; // 2M records
bm.param_num_reads = -1; // Same as param_num
bm.param_value_size = 400;
bm.param_benchmarks = "fillrandom2,"
"readrandom,"
"deleterandom,"
"fillseq2,"
"readrandom,"
"deleteseq,"
"fillseq,"
"overwrite,"
"readrandom,"
"readseq,"
"readreverse,"
"readhot,"
"readmissing,"
"deleteseq,"
"fill100K";
bm.param_benchmarks = "fillrandom2,"
"readrandom,"
"deleterandom,"
"fillseq2,"
"readrandom,"
"deleteseq,"
"fillseq,"
"overwrite,"
"readrandom,"
"readseq,"
"readreverse,"
"readhot,"
"readmissing,"
"deleteseq,"
"fill100K";
#ifndef NDEBUG
fprintf(stderr, "WARNING: Assertions are enabled, benchmarks can be slow\n");
#endif
@@ -319,10 +319,8 @@ static void _bm_run(BMCTX *ctx) {
ctx->end_ms = llv;
}
#define FILLKEY() snprintf(key.data, sizeof(kbuf), bm.ksz == 16 ? "%016d" : bm.ksz == 192 ? "%0192d" : "%01024d", k)
static bool _do_write(BMCTX *ctx, bool seq, bool sync, bool rvlen) {
char kbuf[1025];
IWKV_val key, val;
@@ -339,7 +337,7 @@ static bool _do_write(BMCTX *ctx, bool seq, bool sync, bool rvlen) {
FILLKEY();
key.size = strlen(key.data);
val.data = (void *) _bmctx_rndbuf_nextptr(ctx, value_size);
val.data = (void*) _bmctx_rndbuf_nextptr(ctx, value_size);
val.size = value_size;
if (!bm.db_put(ctx, &key, &val, sync)) {
return false;
@@ -457,84 +455,118 @@ static bool _do_seek_random(BMCTX *ctx) {
}
static bool _bm_fillseq(BMCTX *ctx) {
if (!ctx->freshdb) return false;
if (!ctx->freshdb) {
return false;
}
return _do_write(ctx, true, false, false);
}
static bool _bm_fillseq2(BMCTX *ctx) {
if (!ctx->freshdb) return false;
if (!ctx->freshdb) {
return false;
}
return _do_write(ctx, true, false, true);
}
static bool _bm_fillrandom(BMCTX *ctx) {
if (!ctx->freshdb) return false;
if (!ctx->freshdb) {
return false;
}
return _do_write(ctx, false, false, false);
}
static bool _bm_fillrandom2(BMCTX *ctx) {
if (!ctx->freshdb) return false;
if (!ctx->freshdb) {
return false;
}
return _do_write(ctx, false, false, true);
}
static bool _bm_overwrite(BMCTX *ctx) {
if (ctx->freshdb) return false;
if (ctx->freshdb) {
return false;
}
return _do_write(ctx, false, false, false);
}
static bool _bm_fillsync(BMCTX *ctx) {
if (!ctx->freshdb) return false;
if (!ctx->freshdb) {
return false;
}
ctx->num /= 100;
if (ctx->num < 1) ctx->num = 1;
if (ctx->num < 1) {
ctx->num = 1;
}
fprintf(stderr, "\tfillsync num records: %d\n", ctx->num);
return _do_write(ctx, false, true, false);
}
static bool _bm_fill100K(BMCTX *ctx) {
if (!ctx->freshdb) return false;
if (!ctx->freshdb) {
return false;
}
ctx->num /= 100;
if (ctx->num < 1) ctx->num = 1;
if (ctx->num < 1) {
ctx->num = 1;
}
fprintf(stderr, "\tfill100K num records: %d\n", ctx->num);
ctx->value_size = 100 * 1000;
return _do_write(ctx, false, false, false);
}
static bool _bm_deleteseq(BMCTX *ctx) {
if (ctx->freshdb) return false;
if (ctx->freshdb) {
return false;
}
return _do_delete(ctx, false, true);
}
static bool _bm_deleterandom(BMCTX *ctx) {
if (ctx->freshdb) return false;
if (ctx->freshdb) {
return false;
}
return _do_delete(ctx, false, false);
}
static bool _bm_readseq(BMCTX *ctx) {
if (ctx->freshdb) return false;
if (ctx->freshdb) {
return false;
}
return _do_read_seq(ctx);
}
static bool _bm_readreverse(BMCTX *ctx) {
if (ctx->freshdb) return false;
if (ctx->freshdb) {
return false;
}
return _do_read_reverse(ctx);
}
static bool _bm_readrandom(BMCTX *ctx) {
if (ctx->freshdb) return false;
if (ctx->freshdb) {
return false;
}
return _do_read_random(ctx);
}
static bool _bm_readmissing(BMCTX *ctx) {
if (ctx->freshdb) return false;
if (ctx->freshdb) {
return false;
}
return _do_read_missing(ctx);
}
static bool _bm_readhot(BMCTX *ctx) {
if (ctx->freshdb) return false;
if (ctx->freshdb) {
return false;
}
return _do_read_hot(ctx);
}
static bool _bm_seekrandom(BMCTX *ctx) {
if (ctx->freshdb) return false;
if (ctx->freshdb) {
return false;
}
return _do_seek_random(ctx);
}
@@ -612,7 +644,7 @@ static bool bm_bench_run(int argc, char *argv[]) {
char bname[100];
bool bmres = true;
while (bmres) {
if (*ptr == ',' || *ptr == '\0' || c >= 99) {
if ((*ptr == ',') || (*ptr == '\0') || (c >= 99)) {
bname[c] = '\0';
BMCTX *ctx = _bmctx_create(bname);
c = 0;
@@ -630,7 +662,7 @@ static bool bm_bench_run(int argc, char *argv[]) {
}
_bmctx_dispose(ctx);
}
if (*ptr == '\0' || !bmres) {
if ((*ptr == '\0') || !bmres) {
break;
}
} else if (!isspace(*ptr)) {
+10 -8
View File
@@ -33,19 +33,19 @@ static void *db_open(BMCTX *ctx) {
return 0; // db is not closed properly
}
bool wal_enabled = false;
for (int i = 0; i < bm.argc; ++i) {
for (int i = 0; i < bm.argc; ++i) {
if (!strcmp(bm.argv[i], "-w")) {
wal_enabled = true;
}
}
IWKV_OPTS opts = {
.wal = {
.enabled = wal_enabled,
.wal = {
.enabled = wal_enabled,
.check_crc_on_checkpoint = false,
.savepoint_timeout_sec = 10, // 10 sec
.checkpoint_timeout_sec = 300, // 5 min
.wal_buffer_sz = 8 * 1024 * 1024, // 8M
.checkpoint_buffer_sz = 500ULL * 1024 * 1024 // 500MB
.savepoint_timeout_sec = 10, // 10 sec
.checkpoint_timeout_sec = 300, // 5 min
.wal_buffer_sz = 8 * 1024 * 1024, // 8M
.checkpoint_buffer_sz = 500ULL * 1024 * 1024 // 500MB
}
};
opts.path = bm.param_db ? bm.param_db : DEFAULT_DB;
@@ -167,7 +167,9 @@ static bool db_cursor_to_key(BMCTX *ctx, const IWKV_val *key, IWKV_val *val, boo
}
int main(int argc, char *argv[]) {
if (argc < 1) return -1;
if (argc < 1) {
return -1;
}
g_program = argv[0];
bm.env_setup = env_setup;
bm.db_size_bytes = db_size_bytes;
+5 -4
View File
@@ -27,7 +27,7 @@ static void *db_open(BMCTX *ctx) {
return 0; // db is not closed properly
}
bool wal_enabled = false;
for (int i = 0; i < bm.argc; ++i) {
for (int i = 0; i < bm.argc; ++i) {
if (!strcmp(bm.argv[i], "-w")) {
wal_enabled = true;
}
@@ -151,7 +151,7 @@ static bool db_cursor_to_key(BMCTX *ctx, const IWKV_val *key, IWKV_val *val, boo
if (rc) {
*found = true;
}
if (!rc && kcdbecode(bmdb->db) != KCENOREC) {
if (!rc && (kcdbecode(bmdb->db) != KCENOREC)) {
fprintf(stderr, "db_cursor_to_key: %s\n", kcdbemsg(bmdb->db));
kccurdel(cur);
return false;
@@ -161,9 +161,10 @@ static bool db_cursor_to_key(BMCTX *ctx, const IWKV_val *key, IWKV_val *val, boo
return true;
}
int main(int argc, char **argv) {
if (argc < 1) return -1;
if (argc < 1) {
return -1;
}
g_program = argv[0];
bm.env_setup = env_setup;
bm.db_size_bytes = db_size_bytes;
+3 -1
View File
@@ -180,7 +180,9 @@ static bool db_cursor_to_key(BMCTX *ctx, const IWKV_val *key, IWKV_val *val, boo
}
int main(int argc, char **argv) {
if (argc < 1) return -1;
if (argc < 1) {
return -1;
}
g_program = argv[0];
bm.env_setup = env_setup;
bm.db_size_bytes = db_size_bytes;
+8 -5
View File
@@ -8,7 +8,7 @@ static_assert(sizeof(size_t) == 8, "sizeof(size_t) == 8 bytes");
#define E(expr_, ret_) \
if ((rc = (expr_)) != MDB_SUCCESS) { \
fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, mdb_strerror(rc)); \
return ret_;\
return ret_; \
}
#define B(expr_) E(expr_, 0)
@@ -17,7 +17,7 @@ static_assert(sizeof(size_t) == 8, "sizeof(size_t) == 8 bytes");
typedef struct BM_LEVELDB {
MDB_env *env;
MDB_dbi dbi;
MDB_dbi dbi;
} BM_LMDB;
static void env_setup() {
@@ -45,7 +45,7 @@ static void *db_open(BMCTX *ctx) {
const char *path = bm.param_db ? bm.param_db : DEFAULT_DB;
if (ctx->freshdb) { // completely remove db folder
rc = unlink(path);
if (rc && errno != ENOENT) {
if (rc && (errno != ENOENT)) {
E(errno, 0);
}
}
@@ -173,7 +173,8 @@ static bool db_cursor_to_key(BMCTX *ctx, const IWKV_val *key, IWKV_val *val, boo
rc = 0;
} else if (!rc) {
*found = true;
val->data = malloc(mval.mv_size);;
val->data = malloc(mval.mv_size);
;
memcpy(val->data, mval.mv_data, mval.mv_size);
}
mdb_cursor_close(cur);
@@ -183,7 +184,9 @@ static bool db_cursor_to_key(BMCTX *ctx, const IWKV_val *key, IWKV_val *val, boo
}
int main(int argc, char **argv) {
if (argc < 1) return -1;
if (argc < 1) {
return -1;
}
g_program = argv[0];
bm.env_setup = env_setup;
bm.db_size_bytes = db_size_bytes;
+3 -1
View File
@@ -132,7 +132,9 @@ static bool db_cursor_to_key(BMCTX *ctx, const IWKV_val *key, IWKV_val *val, boo
}
int main(int argc, char **argv) {
if (argc < 1) return -1;
if (argc < 1) {
return -1;
}
g_program = argv[0];
bm.env_setup = env_setup;
bm.db_size_bytes = db_size_bytes;
+6 -4
View File
@@ -6,8 +6,8 @@
struct BMWT {
WT_CONNECTION *conn;
WT_SESSION *session;
WT_CURSOR *cursor;
WT_SESSION *session;
WT_CURSOR *cursor;
} bmwt;
typedef struct BMWT BMWT;
@@ -48,7 +48,7 @@ static void *db_open(BMCTX *ctx) {
return 0; // db is not closed properly
}
bool wal_enabled = false;
for (int i = 0; i < bm.argc; ++i) {
for (int i = 0; i < bm.argc; ++i) {
if (!strcmp(bm.argv[i], "-w")) {
wal_enabled = true;
}
@@ -219,7 +219,9 @@ static bool db_cursor_to_key(BMCTX *ctx, const IWKV_val *key, IWKV_val *val, boo
}
int main(int argc, char **argv) {
if (argc < 1) return -1;
if (argc < 1) {
return -1;
}
g_program = argv[0];
bm.env_setup = env_setup;
bm.db_size_bytes = db_size_bytes;
+3 -5
View File
@@ -38,7 +38,7 @@ void iwkvd_kvblk(FILE *f, KVBLK *kb, int maxvlen) {
iwrc iwkvd_sblk(FILE *f, IWLCTX *lx, SBLK *sb, int flags) {
assert(sb && sb->addr);
uint32_t lkl = 0;
char lkbuf[PREFIX_KEY_LEN_V1 + 1] = {0};
char lkbuf[PREFIX_KEY_LEN_V1 + 1] = { 0 };
uint8_t *mm, *vbuf, *kbuf;
uint32_t klen, vlen;
IWFS_FSM *fsm = &sb->db->iwkv->fsm;
@@ -59,7 +59,7 @@ iwrc iwkvd_sblk(FILE *f, IWLCTX *lx, SBLK *sb, int flags) {
} else {
memcpy(&lkl, mm + sb->addr + SOFF_LKL_U1, 1);
lkl = IW_ITOHL(lkl);
if (lx->db->iwkv->fmt_version > 1) {
if (lx->db->iwkv->fmt_version > 1) {
memcpy(lkbuf, mm + sb->addr + SOFF_LK_V2, lkl);
} else {
memcpy(lkbuf, mm + sb->addr + SOFF_LK_V1, lkl);
@@ -106,7 +106,7 @@ void iwkvd_db(FILE *f, IWDB db, int flags, int plvl) {
assert(db);
SBLK *sb, *tail;
IWLCTX lx = {
.db = db,
.db = db,
.nlvl = -1
};
iwrc rc = _sblk_at(&lx, db->addr, 0, &sb);
@@ -149,5 +149,3 @@ void iwkvd_db(FILE *f, IWDB db, int flags, int plvl) {
}
fflush(f);
}
+12 -12
View File
@@ -16,7 +16,7 @@
struct user_s {
uint32_t id;
char *name;
char *name;
};
struct chat_root_s {
@@ -27,18 +27,18 @@ struct chat_root_s {
static struct chat_root_s rooms[] = {
{
.name = "Meeting room",
.users = {
{ .id = 1, .name = "Joy Lynn" },
.users ={
{ .id = 1, .name = "Joy Lynn" },
{ .id = 2, .name = "Aubrey Sparks" },
{ .id = 3, .name = "Vinnie Kaye"},
{ .id = 3, .name = "Vinnie Kaye" },
{ 0 }
}
},
{
.name = "Webinar room",
.users = {
{ .id = 4, .name = "Arda Payne" },
{ .id = 2, .name = "Joy Lynn" },
.users ={
{ .id = 4, .name = "Arda Payne" },
{ .id = 2, .name = "Joy Lynn" },
{ 0 }
}
}
@@ -46,7 +46,7 @@ static struct chat_root_s rooms[] = {
static iwrc run(void) {
IWKV_OPTS opts = {
.path = "compoundkeys.db",
.path = "compoundkeys.db",
.oflags = IWKV_TRUNC
};
IWKV iwkv;
@@ -75,8 +75,8 @@ static iwrc run(void) {
IWKV_val val;
RCC(rc, finish, iwkv_get(db, &key, &val));
fprintf(stdout, "\n>>>> Found: '%.*s' in room '%s' by id: %d\n",
(int) val.size, (char *) val.data,
(char *) key.data, (int) key.compound);
(int) val.size, (char*) val.data,
(char*) key.data, (int) key.compound);
iwkv_val_dispose(&val);
}
@@ -94,10 +94,10 @@ static iwrc run(void) {
break;
}
fprintf(stdout, "%.*s: %d %.*s\n",
(int) key.size, (char *) key.data,
(int) key.size, (char*) key.data,
(int) key.compound,
(int) val.size,
(char *) val.data);
(char*) val.data);
iwkv_kv_dispose(&key, &val);
} while ((rc = iwkv_cursor_to(cur, IWKV_CURSOR_PREV)) == 0);
rc = 0;
+29 -29
View File
@@ -13,31 +13,31 @@ static struct data_s {
uint8_t points;
} _points[] = {
{ "Aston Villa", 25 },
{ "Manchester City", 57 },
{ "Arsenal", 40 },
{ "Everton", 37 },
{ "West Ham United", 27 },
{ "Tottenham Hotspur", 41 },
{ "Wolverhampton Wanderers", 43 },
{ "Norwich City", 21 },
{ "Leicester City", 53 },
{ "Manchester United", 45 },
{ "Newcastle United", 35 },
{ "Brighton & Hove Albion", 29 },
{ "AFC Bournemouth", 27 },
{ "Crystal Palace", 39 },
{ "Sheffield United", 43 },
{ "Burnley", 39 },
{ "Southampton", 34 },
{ "Watford", 27 },
{ "Chelsea", 48 },
{ "Liverpool", 82 },
{ "Aston Villa", 25 },
{ "Manchester City", 57 },
{ "Arsenal", 40 },
{ "Everton", 37 },
{ "West Ham United", 27 },
{ "Tottenham Hotspur", 41 },
{ "Wolverhampton Wanderers", 43 },
{ "Norwich City", 21 },
{ "Leicester City", 53 },
{ "Manchester United", 45 },
{ "Newcastle United", 35 },
{ "Brighton & Hove Albion", 29 },
{ "AFC Bournemouth", 27 },
{ "Crystal Palace", 39 },
{ "Sheffield United", 43 },
{ "Burnley", 39 },
{ "Southampton", 34 },
{ "Watford", 27 },
{ "Chelsea", 48 },
{ "Liverpool", 82 },
};
static iwrc run(void) {
IWKV_OPTS opts = {
.path = "cursor1.db",
.path = "cursor1.db",
.oflags = IWKV_TRUNC // Cleanup database before open
};
IWKV iwkv;
@@ -51,7 +51,7 @@ static iwrc run(void) {
for (int i = 0; i < sizeof(_points) / sizeof(_points[0]); ++i) {
struct data_s *n = &_points[i];
IWKV_val key = { .data = (void *) n->club, .size = strlen(n->club) };
IWKV_val key = { .data = (void*) n->club, .size = strlen(n->club) };
IWKV_val val = { .data = &n->points, .size = sizeof(n->points) };
RCC(rc, finish, iwkv_put(db, &key, &val, 0));
}
@@ -62,8 +62,8 @@ static iwrc run(void) {
IWKV_val key, val;
RCC(rc, finish, iwkv_cursor_get(cur, &key, &val));
fprintf(stdout, "%.*s: %u\n",
(int) key.size, (char *) key.data,
*(uint8_t *) val.data);
(int) key.size, (char*) key.data,
*(uint8_t*) val.data);
iwkv_kv_dispose(&key, &val);
}
rc = 0;
@@ -75,8 +75,8 @@ static iwrc run(void) {
IWKV_val key, val;
RCC(rc, finish, iwkv_cursor_get(cur, &key, &val));
fprintf(stdout, "%.*s: %u\n",
(int) key.size, (char *) key.data,
*(uint8_t *) val.data);
(int) key.size, (char*) key.data,
*(uint8_t*) val.data);
iwkv_kv_dispose(&key, &val);
}
rc = 0;
@@ -85,13 +85,13 @@ static iwrc run(void) {
// Select all keys greater or equal than: Manchester United
{
fprintf(stdout, "\n>>>> Records GE: %s\n", _points[9].club);
IWKV_val key = { .data = (void *) _points[9].club, .size = strlen(_points[9].club) }, val;
IWKV_val key = { .data = (void*) _points[9].club, .size = strlen(_points[9].club) }, val;
RCC(rc, finish, iwkv_cursor_open(db, &cur, IWKV_CURSOR_GE, &key));
do {
RCC(rc, finish, iwkv_cursor_get(cur, &key, &val));
fprintf(stdout, "%.*s: %u\n",
(int) key.size, (char *) key.data,
*(uint8_t *) val.data);
(int) key.size, (char*) key.data,
*(uint8_t*) val.data);
iwkv_kv_dispose(&key, &val);
} while ((rc = iwkv_cursor_to(cur, IWKV_CURSOR_NEXT)) == 0);
rc = 0;
+5 -5
View File
@@ -4,7 +4,7 @@
int main() {
IWKV_OPTS opts = {
.path = "example1.db",
.path = "example1.db",
.oflags = IWKV_TRUNC // Cleanup database before open
};
IWKV iwkv;
@@ -30,8 +30,8 @@ int main() {
val.size = strlen(val.data);
fprintf(stdout, "put: %.*s => %.*s\n",
(int) key.size, (char *) key.data,
(int) val.size, (char *) val.data);
(int) key.size, (char*) key.data,
(int) val.size, (char*) val.data);
rc = iwkv_put(mydb, &key, &val, 0);
if (rc) {
@@ -48,8 +48,8 @@ int main() {
}
fprintf(stdout, "get: %.*s => %.*s\n",
(int) key.size, (char *) key.data,
(int) val.size, (char *) val.data);
(int) key.size, (char*) key.data,
(int) val.size, (char*) val.data);
iwkv_val_dispose(&val);
iwkv_close(&iwkv);
+103 -76
View File
@@ -7,20 +7,24 @@
#include "win32/mman/mman.h"
#else
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif
#include <sys/mman.h>
#endif
extern atomic_uint_fast64_t g_trigger;
#define BKP_STARTED 0x1 /**< Backup started */
#define BKP_WAL_CLEANUP 0x2 /**< Do checkpoint and truncate WAL file */
#define BKP_MAIN_COPY 0x3 /**< Copy main database file */
#define BKP_WAL_COPY1 0x4 /**< Copy most of WAL file content */
#define BKP_WAL_COPY2 0x5 /**< Copy rest of WAL file in exclusive locked mode */
#define BKP_STARTED 0x1 /**< Backup started */
#define BKP_WAL_CLEANUP 0x2 /**< Do checkpoint and truncate WAL file */
#define BKP_MAIN_COPY 0x3 /**< Copy main database file */
#define BKP_WAL_COPY1 0x4 /**< Copy most of WAL file content */
#define BKP_WAL_COPY2 0x5 /**< Copy rest of WAL file in exclusive locked mode */
typedef struct IWAL {
IWDLSNR lsnr;
IWDLSNR lsnr;
atomic_bool applying; /**< WAL applying */
atomic_bool open; /**< Is WAL in use */
atomic_bool force_cp; /**< Next checkpoint scheduled */
@@ -28,32 +32,32 @@ typedef struct IWAL {
bool force_sp; /**< Next savepoint scheduled */
bool check_cp_crc; /**< Check CRC32 sum of data blocks during checkpoint. Default: false */
iwkv_openflags oflags; /**< File open flags */
atomic_int bkp_stage; /**< Online backup stage */
size_t wal_buffer_sz; /**< WAL file intermediate buffer size. */
size_t checkpoint_buffer_sz; /**< Checkpoint buffer size in bytes. */
atomic_int bkp_stage; /**< Online backup stage */
size_t wal_buffer_sz; /**< WAL file intermediate buffer size. */
size_t checkpoint_buffer_sz; /**< Checkpoint buffer size in bytes. */
uint32_t bufpos; /**< Current position in buffer */
uint32_t bufsz; /**< Size of buffer */
HANDLE fh; /**< File handle */
HANDLE fh; /**< File handle */
uint8_t *buf; /**< File buffer */
char *path; /**< WAL file path */
char *path; /**< WAL file path */
pthread_mutex_t *mtxp; /**< Global WAL mutex */
pthread_cond_t *cpt_condp; /**< Checkpoint thread cond variable */
pthread_t *cptp; /**< Checkpoint thread */
iwrc(*wal_lock_interceptor)(bool, void *);
pthread_cond_t *cpt_condp; /**< Checkpoint thread cond variable */
pthread_t *cptp; /**< Checkpoint thread */
iwrc (*wal_lock_interceptor)(bool, void*);
/**< Optional function called
- before acquiring
- after releasing
exclusive database lock by WAL checkpoint thread.
In the case of `before lock` first argument will be set to true */
void *wal_lock_interceptor_opaque;/**< Opaque data for `wal_lock_interceptor` */
uint32_t savepoint_timeout_sec; /**< Savepoint timeout seconds */
uint32_t checkpoint_timeout_sec; /**< Checkpoint timeout seconds */
atomic_size_t mbytes; /**< Estimated size of modifed private mmaped memory bytes */
off_t rollforward_offset; /**< Rollforward offset during online backup */
uint64_t checkpoint_ts; /**< Last checkpoint timestamp milliseconds */
pthread_mutex_t mtx; /**< Global WAL mutex */
pthread_cond_t cpt_cond; /**< Checkpoint thread cond variable */
pthread_t cpt; /**< Checkpoint thread */
void *wal_lock_interceptor_opaque; /**< Opaque data for `wal_lock_interceptor` */
uint32_t savepoint_timeout_sec; /**< Savepoint timeout seconds */
uint32_t checkpoint_timeout_sec; /**< Checkpoint timeout seconds */
atomic_size_t mbytes; /**< Estimated size of modifed private mmaped memory bytes */
off_t rollforward_offset; /**< Rollforward offset during online backup */
uint64_t checkpoint_ts; /**< Last checkpoint timestamp milliseconds */
pthread_mutex_t mtx; /**< Global WAL mutex */
pthread_cond_t cpt_cond; /**< Checkpoint thread cond variable */
pthread_t cpt; /**< Checkpoint thread */
IWKV iwkv;
} IWAL;
@@ -139,7 +143,7 @@ static iwrc _flush_wl(IWAL *wal, bool sync) {
if (wal->bufpos) {
uint32_t crc = wal->check_cp_crc ? iwu_crc32(wal->buf, wal->bufpos, 0) : 0;
WBSEP sep = {
.id = WOP_SEP,
.id = WOP_SEP,
.crc = crc,
.len = wal->bufpos
};
@@ -199,7 +203,7 @@ IW_INLINE iwrc _write_op(IWAL *wal, const void *op, off_t oplen, const uint8_t *
}
iwrc iwal_sync(IWKV iwkv) {
IWAL *wal = (IWAL *) iwkv->dlsnr;
IWAL *wal = (IWAL*) iwkv->dlsnr;
iwrc rc = _lock(wal);
RCRET(rc);
rc = _flush_wl(wal, true);
@@ -212,7 +216,7 @@ static iwrc _onopen(struct IWDLSNR *self, const char *path, int mode) {
}
static iwrc _onclosing(struct IWDLSNR *self) {
IWAL *wal = (IWAL *) self;
IWAL *wal = (IWAL*) self;
#ifdef IW_TESTS
uint64_t tv = g_trigger;
if (tv & IWKVD_WAL_NO_CHECKPOINT_ON_CLOSE) {
@@ -226,29 +230,29 @@ static iwrc _onclosing(struct IWDLSNR *self) {
}
static iwrc _onset(struct IWDLSNR *self, off_t off, uint8_t val, off_t len, int flags) {
IWAL *wal = (IWAL *) self;
IWAL *wal = (IWAL*) self;
if (wal->applying) {
return 0;
}
WBSET wb = {
.id = WOP_SET,
.id = WOP_SET,
.val = val,
.off = off,
.len = len
};
wal->mbytes += len;
return _write_op((IWAL *) self, &wb, sizeof(wb), 0, 0);
return _write_op((IWAL*) self, &wb, sizeof(wb), 0, 0);
}
static iwrc _oncopy(struct IWDLSNR *self, off_t off, off_t len, off_t noff, int flags) {
IWAL *wal = (IWAL *) self;
IWAL *wal = (IWAL*) self;
if (wal->applying) {
return 0;
}
WBCOPY wb = {
.id = WOP_COPY,
.off = off,
.len = len,
.id = WOP_COPY,
.off = off,
.len = len,
.noff = noff
};
wal->mbytes += len;
@@ -256,14 +260,14 @@ static iwrc _oncopy(struct IWDLSNR *self, off_t off, off_t len, off_t noff, int
}
static iwrc _onwrite(struct IWDLSNR *self, off_t off, const void *buf, off_t len, int flags) {
assert(len <= (size_t)(-1));
IWAL *wal = (IWAL *) self;
assert(len <= (size_t) (-1));
IWAL *wal = (IWAL*) self;
if (wal->applying) {
return 0;
}
WBWRITE wb = {
.id = WOP_WRITE,
.crc = wal->check_cp_crc ? iwu_crc32(buf, len, 0) : 0,
.id = WOP_WRITE,
.crc = wal->check_cp_crc ? iwu_crc32(buf,len, 0) : 0,
.len = len,
.off = off
};
@@ -272,14 +276,14 @@ static iwrc _onwrite(struct IWDLSNR *self, off_t off, const void *buf, off_t len
}
static iwrc _onresize(struct IWDLSNR *self, off_t osize, off_t nsize, int flags, bool *handled) {
IWAL *wal = (IWAL *) self;
IWAL *wal = (IWAL*) self;
if (wal->applying) {
*handled = false;
return 0;
}
*handled = true;
WBRESIZE wb = {
.id = WOP_RESIZE,
.id = WOP_RESIZE,
.osize = osize,
.nsize = nsize
};
@@ -294,7 +298,7 @@ finish:
}
static iwrc _onsynced(struct IWDLSNR *self, int flags) {
IWAL *wal = (IWAL *) self;
IWAL *wal = (IWAL*) self;
if (wal->applying) {
return 0;
}
@@ -314,7 +318,7 @@ static void _last_fix_and_reset_points(IWAL *wal, uint8_t *wmm, off_t fsz, off_t
uint8_t opid;
off_t avail = fsz - (rp - wmm);
memcpy(&opid, rp, 1);
if (i == 0 && opid != WOP_SEP) {
if ((i == 0) && (opid != WOP_SEP)) {
return;
}
switch (opid) {
@@ -397,7 +401,16 @@ static iwrc _rollforward_exl(IWAL *wal, IWFS_EXT *extf, int recover_mode) {
#ifndef _WIN32
off_t pfsz = IW_ROUNDUP(fsz, iwp_page_size());
uint8_t *wmm = mmap(0, (size_t) pfsz, PROT_READ, MAP_PRIVATE, wal->fh, 0);
madvise(wmm, (size_t) fsz, MADV_SEQUENTIAL);
#if defined(MADV_SEQUENTIAL) || defined(MADV_DONTFORK)
int adv = 0;
#ifdef MADV_SEQUENTIAL
adv |= MADV_SEQUENTIAL;
#endif
#ifdef MADV_DONTFORK
adv |= MADV_DONTFORK;
#endif
madvise(wmm, (size_t) fsz, adv);
#endif
#else
off_t pfsz = fsz;
uint8_t *wmm = mmap(0, 0, PROT_READ, MAP_PRIVATE, wal->fh, 0);
@@ -422,7 +435,7 @@ static iwrc _rollforward_exl(IWAL *wal, IWFS_EXT *extf, int recover_mode) {
rc = IWKV_ERROR_CORRUPTED_WAL_FILE; \
iwlog_ecode_error2(rc, msg_); \
goto finish; \
} while(0);
} while (0);
if (recover_mode) {
off_t rpos; // reset point
@@ -430,7 +443,7 @@ static iwrc _rollforward_exl(IWAL *wal, IWFS_EXT *extf, int recover_mode) {
if (!fpos) {
goto finish;
}
if (rpos > 0 && recover_mode == 1) {
if ((rpos > 0) && (recover_mode == 1)) {
// Recover from last known reset point
if (fpos < rpos) {
goto finish;
@@ -456,17 +469,21 @@ static iwrc _rollforward_exl(IWAL *wal, IWFS_EXT *extf, int recover_mode) {
uint8_t opid;
off_t avail = fsz - (rp - wmm);
memcpy(&opid, rp, 1);
if (i == 0 && opid != WOP_SEP) {
if ((i == 0) && (opid != WOP_SEP)) {
rc = IWKV_ERROR_CORRUPTED_WAL_FILE;
goto finish;
}
switch (opid) {
case WOP_SEP: {
WBSEP wb;
if (avail < sizeof(wb)) _WAL_CORRUPTED("Premature end of WAL (WBSEP)");
if (avail < sizeof(wb)) {
_WAL_CORRUPTED("Premature end of WAL (WBSEP)");
}
memcpy(&wb, rp, sizeof(wb));
rp += sizeof(wb);
if (wb.len > avail) _WAL_CORRUPTED("Premature end of WAL (WBSEP)");
if (wb.len > avail) {
_WAL_CORRUPTED("Premature end of WAL (WBSEP)");
}
if (ccrc && wb.crc) {
uint32_t crc = iwu_crc32(rp, wb.len, 0);
if (crc != wb.crc) {
@@ -477,7 +494,9 @@ static iwrc _rollforward_exl(IWAL *wal, IWFS_EXT *extf, int recover_mode) {
}
case WOP_SET: {
WBSET wb;
if (avail < sizeof(wb)) _WAL_CORRUPTED("Premature end of WAL (WBSET)");
if (avail < sizeof(wb)) {
_WAL_CORRUPTED("Premature end of WAL (WBSET)");
}
memcpy(&wb, rp, sizeof(wb));
rp += sizeof(wb);
rc = extf->probe_mmap_unsafe(extf, 0, &mm, &sp);
@@ -487,7 +506,9 @@ static iwrc _rollforward_exl(IWAL *wal, IWFS_EXT *extf, int recover_mode) {
}
case WOP_COPY: {
WBCOPY wb;
if (avail < sizeof(wb)) _WAL_CORRUPTED("Premature end of WAL (WBCOPY)");
if (avail < sizeof(wb)) {
_WAL_CORRUPTED("Premature end of WAL (WBCOPY)");
}
memcpy(&wb, rp, sizeof(wb));
rp += sizeof(wb);
rc = extf->probe_mmap_unsafe(extf, 0, &mm, &sp);
@@ -497,10 +518,14 @@ static iwrc _rollforward_exl(IWAL *wal, IWFS_EXT *extf, int recover_mode) {
}
case WOP_WRITE: {
WBWRITE wb;
if (avail < sizeof(wb)) _WAL_CORRUPTED("Premature end of WAL (WBWRITE)");
if (avail < sizeof(wb)) {
_WAL_CORRUPTED("Premature end of WAL (WBWRITE)");
}
memcpy(&wb, rp, sizeof(wb));
rp += sizeof(wb);
if (avail < wb.len) _WAL_CORRUPTED("Premature end of WAL (WBWRITE)");
if (avail < wb.len) {
_WAL_CORRUPTED("Premature end of WAL (WBWRITE)");
}
if (ccrc && wb.crc) {
uint32_t crc = iwu_crc32(rp, wb.len, 0);
if (crc != wb.crc) {
@@ -515,7 +540,9 @@ static iwrc _rollforward_exl(IWAL *wal, IWFS_EXT *extf, int recover_mode) {
}
case WOP_RESIZE: {
WBRESIZE wb;
if (avail < sizeof(wb)) _WAL_CORRUPTED("Premature end of WAL (WBRESIZE)");
if (avail < sizeof(wb)) {
_WAL_CORRUPTED("Premature end of WAL (WBRESIZE)");
}
memcpy(&wb, rp, sizeof(wb));
rp += sizeof(wb);
rc = extf->truncate_unsafe(extf, wb.nsize);
@@ -554,7 +581,7 @@ finish:
IWRC(extf->add_mmap_unsafe(extf, 0, SIZE_T_MAX, IWFS_MMAP_PRIVATE), rc);
if (!rc) {
int stage = wal->bkp_stage;
if (stage == 0 || stage == BKP_WAL_CLEANUP) {
if ((stage == 0) || (stage == BKP_WAL_CLEANUP)) {
rc = _truncate_wl(wal);
} else {
// Don't truncate WAL during online backup.
@@ -660,7 +687,7 @@ iwrc iwal_test_checkpoint(IWKV iwkv) {
if (!iwkv->dlsnr) {
return IWKV_ERROR_WAL_MODE_REQUIRED;
}
IWAL *wal = (IWAL *) iwkv->dlsnr;
IWAL *wal = (IWAL*) iwkv->dlsnr;
iwrc rc = _excl_lock(wal);
RCRET(rc);
rc = _checkpoint_exl(wal, 0, false);
@@ -673,7 +700,7 @@ iwrc iwal_test_checkpoint(IWKV iwkv) {
//--------------------------------------- Public API
WUR iwrc iwal_poke_checkpoint(IWKV iwkv, bool force) {
IWAL *wal = (IWAL *) iwkv->dlsnr;
IWAL *wal = (IWAL*) iwkv->dlsnr;
if (!wal || !(force || _need_checkpoint(wal))) {
return 0;
}
@@ -698,7 +725,7 @@ WUR iwrc iwal_poke_checkpoint(IWKV iwkv, bool force) {
}
iwrc iwal_poke_savepoint(IWKV iwkv) {
IWAL *wal = (IWAL *) iwkv->dlsnr;
IWAL *wal = (IWAL*) iwkv->dlsnr;
if (!wal) {
return 0;
}
@@ -740,7 +767,7 @@ iwrc _savepoint_exl(IWAL *wal, uint64_t *tsp, bool sync) {
}
bool iwal_synched(IWKV iwkv) {
IWAL *wal = (IWAL *) iwkv->dlsnr;
IWAL *wal = (IWAL*) iwkv->dlsnr;
if (!wal) {
return false;
}
@@ -748,7 +775,7 @@ bool iwal_synched(IWKV iwkv) {
}
iwrc iwal_savepoint_exl(IWKV iwkv, bool sync) {
IWAL *wal = (IWAL *) iwkv->dlsnr;
IWAL *wal = (IWAL*) iwkv->dlsnr;
if (!wal) {
return 0;
}
@@ -756,7 +783,7 @@ iwrc iwal_savepoint_exl(IWKV iwkv, bool sync) {
}
void iwal_shutdown(IWKV iwkv) {
IWAL *wal = (IWAL *) iwkv->dlsnr;
IWAL *wal = (IWAL*) iwkv->dlsnr;
if (!wal) {
return;
}
@@ -775,7 +802,7 @@ void iwal_shutdown(IWKV iwkv) {
}
}
static void *_cpt_worker_fn(void *op) {
static void* _cpt_worker_fn(void *op) {
int rci;
iwrc rc = 0;
IWAL *wal = op;
@@ -811,7 +838,7 @@ static void *_cpt_worker_fn(void *op) {
tp.tv_sec += 1; // one sec tick
tick_ts = tp.tv_sec * 1000 + (uint64_t) round(tp.tv_nsec / 1.0e6);
rci = pthread_cond_timedwait(wal->cpt_condp, wal->mtxp, &tp);
if (rci && rci != ETIMEDOUT) {
if (rci && (rci != ETIMEDOUT)) {
rc = iwrc_set_errno(IW_ERROR_THREADING_ERRNO, rci);
_unlock(wal);
break;
@@ -865,7 +892,7 @@ iwrc iwal_online_backup(IWKV iwkv, uint64_t *ts, const char *target_file) {
if (!target_file) {
return IW_ERROR_INVALID_ARGS;
}
IWAL *wal = (IWAL *) iwkv->dlsnr;
IWAL *wal = (IWAL*) iwkv->dlsnr;
if (!wal) {
return IWKV_ERROR_WAL_MODE_REQUIRED;
}
@@ -903,7 +930,7 @@ iwrc iwal_online_backup(IWKV iwkv, uint64_t *ts, const char *target_file) {
RCGO(rc, finish);
// Copy main database file
IWFS_FSM_STATE fstate = {0};
IWFS_FSM_STATE fstate = { 0 };
rc = iwkv->fsm.state(&iwkv->fsm, &fstate);
RCGO(rc, finish);
do {
@@ -981,8 +1008,8 @@ finish:
}
iwrc _init_cpt(IWAL *wal) {
if (wal->savepoint_timeout_sec == UINT32_MAX
&& wal->checkpoint_timeout_sec == UINT32_MAX) {
if ( (wal->savepoint_timeout_sec == UINT32_MAX)
&& (wal->checkpoint_timeout_sec == UINT32_MAX)) {
// do not start checkpoint thread
return 0;
}
@@ -1060,23 +1087,23 @@ iwrc iwal_create(IWKV iwkv, const IWKV_OPTS *opts, IWFS_FSM_OPTS *fsmopts, bool
dlsnr->onwrite = _onwrite;
dlsnr->onresize = _onresize;
dlsnr->onsynced = _onsynced;
iwkv->dlsnr = (IWDLSNR *) wal;
iwkv->dlsnr = (IWDLSNR*) wal;
wal->wal_buffer_sz =
opts->wal.wal_buffer_sz > 0 ?
opts->wal.wal_buffer_sz :
wal->wal_buffer_sz
= opts->wal.wal_buffer_sz > 0
? opts->wal.wal_buffer_sz :
#if defined __ANDROID__ || defined TARGET_OS_IPHONE
2 * 1024 * 1024; // 2M
2 * 1024 * 1024; // 2M
#else
8 * 1024 * 1024; // 8M
8 * 1024 * 1024; // 8M
#endif
if (wal->wal_buffer_sz < 4096) {
wal->wal_buffer_sz = 4096;
}
wal->checkpoint_buffer_sz
= opts->wal.checkpoint_buffer_sz > 0 ?
opts->wal.checkpoint_buffer_sz :
= opts->wal.checkpoint_buffer_sz > 0
? opts->wal.checkpoint_buffer_sz :
#if defined __ANDROID__ || defined TARGET_OS_IPHONE
64ULL * 1024 * 1024; // 64M
#else
@@ -1087,8 +1114,8 @@ iwrc iwal_create(IWKV iwkv, const IWKV_OPTS *opts, IWFS_FSM_OPTS *fsmopts, bool
}
wal->savepoint_timeout_sec
= opts->wal.savepoint_timeout_sec > 0 ?
opts->wal.savepoint_timeout_sec : 10; // 10 sec
= opts->wal.savepoint_timeout_sec > 0
? opts->wal.savepoint_timeout_sec : 10; // 10 sec
wal->checkpoint_timeout_sec
= opts->wal.checkpoint_timeout_sec > 0 ?
@@ -1118,7 +1145,7 @@ iwrc iwal_create(IWKV iwkv, const IWKV_OPTS *opts, IWFS_FSM_OPTS *fsmopts, bool
// Now open WAL file
#ifndef _WIN32
HANDLE fh = open(wal->path, O_CREAT | O_RDWR, IWFS_DEFAULT_FILEMODE);
HANDLE fh = open(wal->path, O_CREAT | O_RDWR | O_CLOEXEC, IWFS_DEFAULT_FILEMODE);
if (INVALIDHANDLE(fh)) {
rc = iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
goto finish;
+17 -17
View File
@@ -7,7 +7,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -48,8 +48,8 @@ typedef enum {
#pragma pack(push, 1)
typedef struct WBSEP {
uint8_t id;
uint8_t pad[3];
uint8_t id;
uint8_t pad[3];
uint32_t crc;
uint32_t len;
} WBSEP;
@@ -60,39 +60,39 @@ typedef struct WBRESET {
} WBRESET;
typedef struct WBSET {
uint8_t id;
uint8_t pad[3];
uint8_t id;
uint8_t pad[3];
uint32_t val;
off_t off;
off_t len;
off_t off;
off_t len;
} WBSET;
typedef struct WBCOPY {
uint8_t id;
uint8_t pad[3];
off_t off;
off_t len;
off_t noff;
off_t off;
off_t len;
off_t noff;
} WBCOPY;
typedef struct WBWRITE {
uint8_t id;
uint8_t pad[3];
uint8_t id;
uint8_t pad[3];
uint32_t crc;
uint32_t len;
off_t off;
off_t off;
} WBWRITE;
typedef struct WBRESIZE {
uint8_t id;
uint8_t pad[3];
off_t osize;
off_t nsize;
off_t osize;
off_t nsize;
} WBRESIZE;
typedef struct WBFIXPOINT {
uint8_t id;
uint8_t pad[3];
uint8_t id;
uint8_t pad[3];
uint64_t ts;
} WBFIXPOINT;
#pragma pack(pop)
+246 -196
View File
File diff suppressed because it is too large Load Diff
+55 -40
View File
@@ -7,7 +7,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -62,20 +62,31 @@ IW_EXTERN_C_START
*/
typedef enum {
_IWKV_ERROR_START = (IW_ERROR_START + 5000UL),
IWKV_ERROR_NOTFOUND, /**< Key not found (IWKV_ERROR_NOTFOUND) */
IWKV_ERROR_KEY_EXISTS, /**< Key already exists (IWKV_ERROR_KEY_EXISTS) */
IWKV_ERROR_MAXKVSZ, /**< Size of Key+value must be not greater than 0xfffffff bytes (IWKV_ERROR_MAXKVSZ) */
IWKV_ERROR_CORRUPTED, /**< Database file invalid or corrupted (IWKV_ERROR_CORRUPTED) */
IWKV_ERROR_DUP_VALUE_SIZE, /**< Value size is not compatible for insertion into sorted values array (IWKV_ERROR_DUP_VALUE_SIZE) */
IWKV_ERROR_KEY_NUM_VALUE_SIZE, /**< Given key is not compatible to storage as number (IWKV_ERROR_KEY_NUM_VALUE_SIZE) */
IWKV_ERROR_INCOMPATIBLE_DB_MODE, /**< Incorpatible database open mode (IWKV_ERROR_INCOMPATIBLE_DB_MODE) */
IWKV_ERROR_INCOMPATIBLE_DB_FORMAT, /**< Incompatible database format version, please migrate database data (IWKV_ERROR_INCOMPATIBLE_DB_FORMAT) */
IWKV_ERROR_CORRUPTED_WAL_FILE, /**< Corrupted WAL file (IWKV_ERROR_CORRUPTED_WAL_FILE) */
IWKV_ERROR_VALUE_CANNOT_BE_INCREMENTED, /**< Stored value cannot be incremented/descremented (IWKV_ERROR_VALUE_CANNOT_BE_INCREMENTED) */
IWKV_ERROR_WAL_MODE_REQUIRED, /**< Operation requires WAL enabled database. (IWKV_ERROR_WAL_MODE_REQUIRED) */
IWKV_ERROR_BACKUP_IN_PROGRESS, /**< Backup operation in progress. (IWKV_ERROR_BACKUP_IN_PROGRESS) */
IWKV_ERROR_NOTFOUND, /**< Key not found (IWKV_ERROR_NOTFOUND) */
IWKV_ERROR_KEY_EXISTS, /**< Key already exists (IWKV_ERROR_KEY_EXISTS) */
IWKV_ERROR_MAXKVSZ,
/**< Size of Key+value must be not greater than 0xfffffff bytes
(IWKV_ERROR_MAXKVSZ) */
IWKV_ERROR_CORRUPTED, /**< Database file invalid or corrupted (IWKV_ERROR_CORRUPTED) */
IWKV_ERROR_DUP_VALUE_SIZE,
/**< Value size is not compatible for insertion into sorted values array
(IWKV_ERROR_DUP_VALUE_SIZE) */
IWKV_ERROR_KEY_NUM_VALUE_SIZE,
/**< Given key is not compatible to storage as number
(IWKV_ERROR_KEY_NUM_VALUE_SIZE) */
IWKV_ERROR_INCOMPATIBLE_DB_MODE, /**< Incorpatible database open mode (IWKV_ERROR_INCOMPATIBLE_DB_MODE) */
IWKV_ERROR_INCOMPATIBLE_DB_FORMAT,
/**< Incompatible database format version, please migrate database data
(IWKV_ERROR_INCOMPATIBLE_DB_FORMAT) */
IWKV_ERROR_CORRUPTED_WAL_FILE, /**< Corrupted WAL file (IWKV_ERROR_CORRUPTED_WAL_FILE) */
IWKV_ERROR_VALUE_CANNOT_BE_INCREMENTED,
/**< Stored value cannot be incremented/descremented
(IWKV_ERROR_VALUE_CANNOT_BE_INCREMENTED) */
IWKV_ERROR_WAL_MODE_REQUIRED,
/**< Operation requires WAL enabled database. (IWKV_ERROR_WAL_MODE_REQUIRED)
*/
IWKV_ERROR_BACKUP_IN_PROGRESS, /**< Backup operation in progress. (IWKV_ERROR_BACKUP_IN_PROGRESS) */
_IWKV_ERROR_END,
// Internal only
_IWKV_RC_KVBLOCK_FULL,
_IWKV_RC_REQUIRE_NLEVEL,
@@ -87,56 +98,56 @@ typedef uint8_t iwkv_openflags;
/** Open storage file in read-only mode */
#define IWKV_RDONLY ((iwkv_openflags) 0x02U)
/** Truncate storage file on open */
#define IWKV_TRUNC ((iwkv_openflags) 0x04U)
#define IWKV_TRUNC ((iwkv_openflags) 0x04U)
#define IWKV_NO_TRIM_ON_CLOSE ((iwkv_openflags) 0x08U)
/** Database initialization modes */
typedef uint8_t iwdb_flags_t;
/** Floating point number keys represented as string (char*) value. */
#define IWDB_REALNUM_KEYS ((iwdb_flags_t) 0x10U)
#define IWDB_REALNUM_KEYS ((iwdb_flags_t) 0x10U)
/** Variable-length number keys */
#define IWDB_VNUM64_KEYS ((iwdb_flags_t) 0x20U)
#define IWDB_VNUM64_KEYS ((iwdb_flags_t) 0x20U)
/**
* Enable compound database keys. Keys stored in the following format: `<key value prefix><numeric key suffix>`
* Allows associate one `key value` with many references represented as VNUM64 (eg.: Non unique table indexes).
* @see IWKV_val.compound
*/
#define IWDB_COMPOUND_KEYS ((iwdb_flags_t) 0x40U)
#define IWDB_COMPOUND_KEYS ((iwdb_flags_t) 0x40U)
/** Record store modes used in `iwkv_put()` and `iwkv_cursor_set()` functions. */
typedef uint8_t iwkv_opflags;
/** Do not overwrite value for an existing key.
`IWKV_ERROR_KEY_EXISTS` will be returned in such cases. */
#define IWKV_NO_OVERWRITE ((iwkv_opflags) 0x01U)
#define IWKV_NO_OVERWRITE ((iwkv_opflags) 0x01U)
/** Flush changes on disk after operation */
#define IWKV_SYNC ((iwkv_opflags) 0x04U)
#define IWKV_SYNC ((iwkv_opflags) 0x04U)
/** Increment/decrement stored UINT32|UINT64 value by given INT32|INT64 number
`IWKV_ERROR_KEY_EXISTS` does not makes sense if this flag set. */
#define IWKV_VAL_INCREMENT ((iwkv_opflags) 0x10U)
#define IWKV_VAL_INCREMENT ((iwkv_opflags) 0x10U)
struct _IWKV;
typedef struct _IWKV *IWKV;
typedef struct _IWKV*IWKV;
struct _IWDB;
typedef struct _IWDB *IWDB;
typedef struct _IWDB*IWDB;
/**
* @brief Write ahead log (WAL) options.
*/
typedef struct IWKV_WAL_OPTS {
bool enabled; /**< WAL enabled */
bool check_crc_on_checkpoint; /**< Check CRC32 sum of data blocks during checkpoint. Default: false */
bool enabled; /**< WAL enabled */
bool check_crc_on_checkpoint; /**< Check CRC32 sum of data blocks during checkpoint. Default: false */
uint32_t savepoint_timeout_sec; /**< Savepoint timeout seconds. Default: 10 sec */
uint32_t checkpoint_timeout_sec; /**< Checkpoint timeout seconds. Default: 300 sec (5 min); */
size_t wal_buffer_sz; /**< WAL file intermediate buffer size. Default: 8Mb */
size_t wal_buffer_sz; /**< WAL file intermediate buffer size. Default: 8Mb */
uint64_t checkpoint_buffer_sz; /**< Checkpoint buffer size in bytes. Default: 1Gb */
iwrc(*wal_lock_interceptor)(bool, void *);
iwrc (*wal_lock_interceptor)(bool, void*);
/**< Optional function called
- before acquiring
- after releasing
@@ -150,7 +161,7 @@ typedef struct IWKV_WAL_OPTS {
*/
typedef struct IWKV_OPTS {
const char *path; /**< Path to database file */
uint32_t random_seed; /**< Random seed used for iwu random generator */
uint32_t random_seed; /**< Random seed used for iwu random generator */
/**
* Database storage format version.
* Leave it as zero for the latest supported format.
@@ -166,7 +177,7 @@ typedef struct IWKV_OPTS {
* @brief Data container for key/value.
*/
typedef struct IWKV_val {
void *data; /**< Data buffer */
void *data; /**< Data buffer */
size_t size; /**< Data buffer size */
/** Extra key part used for key comparison.
* If set to non zero and database is created with `IWDB_COMPOUND_KEYS` mode
@@ -180,7 +191,7 @@ typedef struct IWKV_val {
* @brief Cursor opaque handler.
*/
struct _IWKV_cursor;
typedef struct _IWKV_cursor *IWKV_cursor;
typedef struct _IWKV_cursor*IWKV_cursor;
/**
* @brief Database cursor operations and position flags.
@@ -191,7 +202,7 @@ typedef enum IWKV_cursor_op {
IWKV_CURSOR_NEXT, /**< Move cursor to the next record */
IWKV_CURSOR_PREV, /**< Move cursor to the previous record */
IWKV_CURSOR_EQ, /**< Set cursor to the specified key value */
IWKV_CURSOR_GE /**< Set cursor to the key which greater or equal key specified */
IWKV_CURSOR_GE, /**< Set cursor to the key which greater or equal key specified */
} IWKV_cursor_op;
/**
@@ -308,14 +319,15 @@ IW_EXPORT iwrc iwkv_put(IWDB db, const IWKV_val *key, const IWKV_val *val, iwkv_
* @param oldval Old value which will be replaced by `val` may be `NULL`
* @param op Arbitrary opaqued data passed to this handler
*/
typedef iwrc(*IWKV_PUT_HANDLER)(const IWKV_val *key, const IWKV_val *val, IWKV_val *oldval, void *op);
typedef iwrc (*IWKV_PUT_HANDLER)(const IWKV_val *key, const IWKV_val *val, IWKV_val *oldval, void *op);
/**
* @brief Store record in database.
* @see iwkv_put()
*/
IW_EXPORT iwrc iwkv_puth(IWDB db, const IWKV_val *key, const IWKV_val *val,
iwkv_opflags opflags, IWKV_PUT_HANDLER ph, void *phop);
IW_EXPORT iwrc iwkv_puth(
IWDB db, const IWKV_val *key, const IWKV_val *val,
iwkv_opflags opflags, IWKV_PUT_HANDLER ph, void *phop);
/**
* @brief Get value for given `key`.
@@ -396,10 +408,12 @@ IW_EXPORT void iwkv_kv_dispose(IWKV_val *key, IWKV_val *val);
* @param op Cursor open mode/initial positions flags
* @param key Optional key argument, required to point cursor to the given key.
*/
IW_EXPORT WUR iwrc iwkv_cursor_open(IWDB db,
IWKV_cursor *cur,
IWKV_cursor_op op,
const IWKV_val *key);
IW_EXPORT WUR iwrc iwkv_cursor_open(
IWDB db,
IWKV_cursor *cur,
IWKV_cursor_op op,
const IWKV_val *key);
/**
* @brief Move cursor to the next position.
*
@@ -486,8 +500,9 @@ IW_EXPORT iwrc iwkv_cursor_is_matched_key(IWKV_cursor cur, const IWKV_val *key,
*/
IW_EXPORT iwrc iwkv_cursor_set(IWKV_cursor cur, IWKV_val *val, iwkv_opflags opflags);
IW_EXPORT iwrc iwkv_cursor_seth(IWKV_cursor cur, IWKV_val *val, iwkv_opflags opflags,
IWKV_PUT_HANDLER ph, void *phop);
IW_EXPORT iwrc iwkv_cursor_seth(
IWKV_cursor cur, IWKV_val *val, iwkv_opflags opflags,
IWKV_PUT_HANDLER ph, void *phop);
/**
* @brief Remove record value at current cursor position.
+121 -122
View File
@@ -96,7 +96,7 @@
// Max non KV size [blen:u1,idxsz:u2,[ps1:vn,pl1:vn,...,ps63,pl63]
#define KVBLK_MAX_NKV_SZ (KVBLK_HDRSZ + KVBLK_MAX_IDX_SZ)
#define ADDR2BLK(addr_) ((blkn_t) (((uint64_t)(addr_)) >> IWKV_FSM_BPOW))
#define ADDR2BLK(addr_) ((blkn_t) (((uint64_t) (addr_)) >> IWKV_FSM_BPOW))
#define BLK2ADDR(blk_) (((uint64_t) (blk_)) << IWKV_FSM_BPOW)
@@ -108,60 +108,60 @@ typedef uint32_t dbid_t;
/* Key/Value pair stored in `KVBLK` */
typedef struct KV {
size_t keysz;
size_t valsz;
size_t keysz;
size_t valsz;
uint8_t *key;
uint8_t *val;
} KV;
/* Ket/Value (KV) index: Offset and length. */
typedef struct KVP {
off_t off; /**< KV block offset relative to `end` of KVBLK */
off_t off; /**< KV block offset relative to `end` of KVBLK */
uint32_t len; /**< Length of kv pair block */
uint8_t ridx; /**< Position of the actually persisted slot in `KVBLK` */
uint8_t ridx; /**< Position of the actually persisted slot in `KVBLK` */
} KVP;
typedef uint8_t kvblk_flags_t;
#define KVBLK_DEFAULT ((kvblk_flags_t) 0x00U)
#define KVBLK_DEFAULT ((kvblk_flags_t) 0x00U)
/** KVBLK data is durty and should be flushed to mm */
#define KVBLK_DURTY ((kvblk_flags_t) 0x01U)
#define KVBLK_DURTY ((kvblk_flags_t) 0x01U)
typedef uint8_t kvblk_rmkv_opts_t;
#define RMKV_SYNC ((kvblk_rmkv_opts_t) 0x01U)
#define RMKV_NO_RESIZE ((kvblk_rmkv_opts_t) 0x02U)
#define RMKV_SYNC ((kvblk_rmkv_opts_t) 0x01U)
#define RMKV_NO_RESIZE ((kvblk_rmkv_opts_t) 0x02U)
typedef uint8_t sblk_flags_t;
/** The lowest `SBLK` key is fully contained in `SBLK`. Persistent flag. */
#define SBLK_FULL_LKEY ((sblk_flags_t) 0x01U)
#define SBLK_FULL_LKEY ((sblk_flags_t) 0x01U)
/** This block is the start database block. */
#define SBLK_DB ((sblk_flags_t) 0x08U)
#define SBLK_DB ((sblk_flags_t) 0x08U)
/** Block data changed, block marked as durty and needs to be persisted */
#define SBLK_DURTY ((sblk_flags_t) 0x10U)
#define SBLK_DURTY ((sblk_flags_t) 0x10U)
/** Put this `SBLK` into dbcache */
#define SBLK_CACHE_PUT ((sblk_flags_t) 0x20U)
#define SBLK_CACHE_UPDATE ((sblk_flags_t) 0x40U)
#define SBLK_CACHE_REMOVE ((sblk_flags_t) 0x80U)
#define SBLK_CACHE_PUT ((sblk_flags_t) 0x20U)
#define SBLK_CACHE_UPDATE ((sblk_flags_t) 0x40U)
#define SBLK_CACHE_REMOVE ((sblk_flags_t) 0x80U)
typedef uint8_t iwlctx_op_t;
/** Put key value operation */
#define IWLCTX_PUT ((iwlctx_op_t) 0x01U)
#define IWLCTX_PUT ((iwlctx_op_t) 0x01U)
/** Delete key operation */
#define IWLCTX_DEL ((iwlctx_op_t) 0x01U)
#define IWLCTX_DEL ((iwlctx_op_t) 0x01U)
/* KVBLK: [szpow:u1,idxsz:u2,[ps0:vn,pl0:vn,..., ps32,pl32]____[[KV],...]] */
typedef struct KVBLK {
IWDB db;
off_t addr; /**< Block address */
off_t maxoff; /**< Max pair offset */
IWDB db;
off_t addr; /**< Block address */
off_t maxoff; /**< Max pair offset */
uint16_t idxsz; /**< Size of KV pairs index in bytes */
int8_t zidx; /**< Index of first empty pair slot (zero index), or -1 */
uint8_t szpow; /**< Block size as power of 2 */
int8_t zidx; /**< Index of first empty pair slot (zero index), or -1 */
uint8_t szpow; /**< Block size as power of 2 */
kvblk_flags_t flags; /**< Flags */
KVP pidx[KVBLK_IDXNUM]; /**< KV pairs index */
} KVBLK;
#define SBLK_PERSISTENT_FLAGS (SBLK_FULL_LKEY)
#define SBLK_CACHE_FLAGS (SBLK_CACHE_UPDATE | SBLK_CACHE_PUT | SBLK_CACHE_REMOVE)
#define SBLK_CACHE_FLAGS (SBLK_CACHE_UPDATE | SBLK_CACHE_PUT | SBLK_CACHE_REMOVE)
// Number of top levels to cache (~ (1<<DBCACHE_LEVELS) cached elements)
#define DBCACHE_LEVELS 10U
@@ -174,8 +174,8 @@ typedef struct KVBLK {
/** Cached SBLK node */
typedef struct DBCNODE {
blkn_t sblkn; /**< SBLK block number or used to store key size (to keep DBCNODE compact) */
blkn_t kblkn; /**< KVBLK block number */
blkn_t sblkn; /**< SBLK block number or used to store key size (to keep DBCNODE compact) */
blkn_t kblkn; /**< KVBLK block number */
uint8_t lkl; /**< Lower key length */
uint8_t fullkey; /**< SBLK is full key */
uint8_t k0idx; /**< KVBLK Zero KVP index */
@@ -184,7 +184,7 @@ typedef struct DBCNODE {
} DBCNODE;
#define DBCNODE_VNUM_SZ 24
#define DBCNODE_STR_SZ 128
#define DBCNODE_STR_SZ 128
static_assert(DBCNODE_VNUM_SZ >= offsetof(DBCNODE, lk) + IW_VNUMBUFSZ,
"DBCNODE_VNUM_SZ >= offsetof(DBCNODE, lk) + IW_VNUMBUFSZ");
@@ -193,11 +193,11 @@ static_assert(DBCNODE_STR_SZ >= offsetof(DBCNODE, lk) + SBLK_LKLEN,
/** Tallest SBLK nodes cache */
typedef struct DBCACHE {
size_t asize; /**< Size of allocated cache buffer */
size_t num; /**< Actual number of nodes */
size_t nsize; /**< Cached node size */
uint8_t lvl; /**< Lowes cached level */
bool open; /**< Is cache open */
size_t asize; /**< Size of allocated cache buffer */
size_t num; /**< Actual number of nodes */
size_t nsize; /**< Cached node size */
uint8_t lvl; /**< Lowes cached level */
bool open; /**< Is cache open */
DBCNODE *nodes; /**< Sorted nodes array */
} DBCACHE;
@@ -206,46 +206,45 @@ struct _IWKV_cursor;
/* Database: [magic:u4,dbflg:u1,dbid:u4,next_db_blk:u4,p0:u4,n[24]:u4,c[24]:u4]:209 */
struct _IWDB {
// SBH
IWDB db; /**< Database ref */
IWDB db; /**< Database ref */
off_t addr; /**< Database block address */
sblk_flags_t flags; /**< Flags */
// !SBH
IWKV iwkv;
DBCACHE cache; /**< SBLK nodes cache */
pthread_rwlock_t rwl; /**< Database API RW lock */
pthread_spinlock_t cursors_slk; /**< Cursors set guard lock */
off_t next_db_addr; /**< Next IWDB addr */
struct _IWKV_cursor *cursors; /**< Active (currently in-use) database cursors */
struct _IWDB *next; /**< Next IWDB meta */
struct _IWDB *prev; /**< Prev IWDB meta */
dbid_t id; /**< Database ID */
volatile int32_t wk_count; /**< Number of active database workers */
blkn_t meta_blk; /**< Database meta block number */
blkn_t meta_blkn; /**< Database meta length (number of blocks) */
iwdb_flags_t dbflg; /**< Database specific flags */
atomic_bool open; /**< True if DB is in OPEN state */
IWKV iwkv;
DBCACHE cache; /**< SBLK nodes cache */
pthread_rwlock_t rwl; /**< Database API RW lock */
pthread_spinlock_t cursors_slk; /**< Cursors set guard lock */
off_t next_db_addr; /**< Next IWDB addr */
struct _IWKV_cursor *cursors; /**< Active (currently in-use) database cursors */
struct _IWDB *next; /**< Next IWDB meta */
struct _IWDB *prev; /**< Prev IWDB meta */
dbid_t id; /**< Database ID */
volatile int32_t wk_count; /**< Number of active database workers */
blkn_t meta_blk; /**< Database meta block number */
blkn_t meta_blkn; /**< Database meta length (number of blocks) */
iwdb_flags_t dbflg; /**< Database specific flags */
atomic_bool open; /**< True if DB is in OPEN state */
volatile bool wk_pending_exclusive; /**< If true someone wants to acquire exclusive lock on IWDB */
uint32_t lcnt[SLEVELS]; /**< SBLK count per level */
uint32_t lcnt[SLEVELS]; /**< SBLK count per level */
};
/* Skiplist block: [u1:flags,lvl:u1,lkl:u1,pnum:u1,p0:u4,kblk:u4,[pi0:u1,... pi32],n0-n23:u4,lk:u116]:u256 // SBLK */
typedef struct SBLK {
// SBH
IWDB db; /**< Database ref */
IWDB db; /**< Database ref */
off_t addr; /**< Block address */
sblk_flags_t flags; /**< Flags */
uint8_t lvl; /**< Skip list node level */
uint8_t bpos; /**< Position of SBLK in a page block starting with 1 (zero means SBLK deleted) */
blkn_t p0; /**< Prev node, if IWDB it is the last node */
blkn_t n[SLEVELS]; /**< Next nodes */
uint8_t lvl; /**< Skip list node level */
uint8_t bpos; /**< Position of SBLK in a page block starting with 1 (zero means SBLK deleted) */
blkn_t p0; /**< Prev node, if IWDB it is the last node */
blkn_t n[SLEVELS]; /**< Next nodes */
// !SBH
KVBLK *kvblk; /**< Associated KVBLK */
blkn_t kvblkn; /**< Associated KVBLK block number */
int8_t pnum; /**< Number of active kv indexes in `SBLK::pi` */
uint8_t lkl; /**< Lower key length within a buffer */
uint8_t pi[KVBLK_IDXNUM]; /**< Sorted KV slots, value is an index of kv slot in `KVBLK` */
uint8_t lk[PREFIX_KEY_LEN_V1]; /**< Lower key buffer */
KVBLK *kvblk; /**< Associated KVBLK */
blkn_t kvblkn; /**< Associated KVBLK block number */
int8_t pnum; /**< Number of active kv indexes in `SBLK::pi` */
uint8_t lkl; /**< Lower key length within a buffer */
uint8_t pi[KVBLK_IDXNUM]; /**< Sorted KV slots, value is an index of kv slot in `KVBLK` */
uint8_t lk[PREFIX_KEY_LEN_V1]; /**< Lower key buffer */
} SBLK;
// -V:KHASH_MAP_INIT_INT:522
@@ -253,28 +252,28 @@ KHASH_MAP_INIT_INT(DBS, IWDB)
/** IWKV instance */
struct _IWKV {
IWFS_FSM fsm; /**< FSM pool */
pthread_rwlock_t rwl; /**< API RW lock */
iwrc fatalrc; /**< Fatal error occuried, no farther operations can be performed */
IWDB first_db; /**< First database in chain */
IWDB last_db; /**< Last database in chain */
IWDLSNR *dlsnr; /**< WAL data events listener */
khash_t(DBS) *dbs; /**< Database id -> IWDB mapping */
iwkv_openflags oflags; /**< Open flags */
pthread_cond_t wk_cond; /**< Workers cond variable */
pthread_mutex_t wk_mtx; /**< Workers cond mutext */
int32_t fmt_version; /**< Database format version */
int32_t pklen; /**< Prefix key length in use */
volatile int32_t wk_count; /**< Number of active workers */
volatile bool wk_pending_exclusive; /**< If true someone wants to acquire exclusive lock on IWKV */
atomic_bool open; /**< True if kvstore is in OPEN state */
IWFS_FSM fsm; /**< FSM pool */
pthread_rwlock_t rwl; /**< API RW lock */
iwrc fatalrc; /**< Fatal error occuried, no farther operations can be performed */
IWDB first_db; /**< First database in chain */
IWDB last_db; /**< Last database in chain */
IWDLSNR *dlsnr; /**< WAL data events listener */
khash_t(DBS) * dbs; /**< Database id -> IWDB mapping */
iwkv_openflags oflags; /**< Open flags */
pthread_cond_t wk_cond; /**< Workers cond variable */
pthread_mutex_t wk_mtx; /**< Workers cond mutext */
int32_t fmt_version; /**< Database format version */
int32_t pklen; /**< Prefix key length in use */
volatile int32_t wk_count; /**< Number of active workers */
volatile bool wk_pending_exclusive; /**< If true someone wants to acquire exclusive lock on IWKV */
atomic_bool open; /**< True if kvstore is in OPEN state */
};
/** Database lookup context */
typedef struct IWLCTX {
IWDB db;
const IWKV_val *key; /**< Search key */
IWKV_val *val; /**< Update value */
IWKV_val *val; /**< Update value */
SBLK *lower; /**< Next to upper bound block */
SBLK *upper; /**< Upper bound block */
SBLK *nb; /**< New block */
@@ -285,34 +284,34 @@ typedef struct IWLCTX {
#endif
iwkv_opflags opflags; /**< Operation flags */
sblk_flags_t sbflags; /**< `SBLK` flags applied to all new/looked blocks in this context */
iwlctx_op_t op; /**< Context operation */
uint8_t saan; /**< Position of next free `SBLK` element in the `saa` area */
uint8_t kaan; /**< Position of next free `KVBLK` element in the `kaa` area */
int8_t nlvl; /**< Level of new inserted/deleted `SBLK` node. -1 if no new node inserted/deleted */
int8_t cache_reload; /**< If true dbcache should be refreshed after operation */
iwlctx_op_t op; /**< Context operation */
uint8_t saan; /**< Position of next free `SBLK` element in the `saa` area */
uint8_t kaan; /**< Position of next free `KVBLK` element in the `kaa` area */
int8_t nlvl; /**< Level of new inserted/deleted `SBLK` node. -1 if no new node inserted/deleted */
int8_t cache_reload; /**< If true dbcache should be refreshed after operation */
IWKV_PUT_HANDLER ph; /**< Optional put handler */
void *phop; /**< Put handler opaque data */
SBLK *plower[SLEVELS]; /**< Pinned lower nodes per level */
SBLK *pupper[SLEVELS]; /**< Pinned upper nodes per level */
void *phop; /**< Put handler opaque data */
SBLK *plower[SLEVELS]; /**< Pinned lower nodes per level */
SBLK *pupper[SLEVELS]; /**< Pinned upper nodes per level */
IWKV_val ekey;
SBLK dblk; /**< First database block */
SBLK saa[AANUM]; /**< `SBLK` allocation area */
KVBLK kaa[AANUM]; /**< `KVBLK` allocation area */
uint8_t nbuf[IW_VNUMBUFSZ];
uint8_t incbuf[8]; /**< Buffer used to store incremented/decremented values `IWKV_VAL_INCREMENT` opflag */
SBLK dblk; /**< First database block */
SBLK saa[AANUM]; /**< `SBLK` allocation area */
KVBLK kaa[AANUM]; /**< `KVBLK` allocation area */
uint8_t nbuf[IW_VNUMBUFSZ];
uint8_t incbuf[8]; /**< Buffer used to store incremented/decremented values `IWKV_VAL_INCREMENT` opflag */
} IWLCTX;
/** Cursor context */
struct _IWKV_cursor {
uint8_t cnpos; /**< Position in the current `SBLK` node */
bool closed; /**< Cursor closed */
int8_t skip_next; /**< When to skip next IWKV_CURSOR_NEXT|IWKV_CURSOR_PREV cursor move
bool closed; /**< Cursor closed */
int8_t skip_next; /**< When to skip next IWKV_CURSOR_NEXT|IWKV_CURSOR_PREV cursor move
due to the side effect of `iwkv_cursor_del()` call.
If `skip_next > 0` `IWKV_CURSOR_NEXT` will be skipped
If `skip_next < 0` `IWKV_CURSOR_PREV` will be skipped */
SBLK *cn; /**< Current `SBLK` node */
struct _IWKV_cursor *next; /**< Next cursor in active db cursors chain */
off_t dbaddr; /**< Database address used as `cn` */
off_t dbaddr; /**< Database address used as `cn` */
IWLCTX lx; /**< Lookup context */
};
@@ -328,7 +327,7 @@ struct _IWKV_cursor {
(rci_) = pthread_rwlock_rdlock(&(iwkv_)->rwl); \
if (rci_) return iwrc_set_errno(IW_ERROR_THREADING_ERRNO, rci_)
IW_INLINE iwrc _api_rlock(IWKV iwkv) {
IW_INLINE iwrc _api_rlock(IWKV iwkv) {
int rci;
API_RLOCK(iwkv, rci);
return 0;
@@ -339,7 +338,7 @@ IW_INLINE iwrc _api_rlock(IWKV iwkv) {
(rci_) = pthread_rwlock_wrlock(&(iwkv_)->rwl); \
if (rci_) return iwrc_set_errno(IW_ERROR_THREADING_ERRNO, rci_)
IW_INLINE iwrc _api_wlock(IWKV iwkv) {
IW_INLINE iwrc _api_wlock(IWKV iwkv) {
int rci;
API_WLOCK(iwkv, rci);
return 0;
@@ -357,9 +356,9 @@ IW_INLINE iwrc _api_wlock(IWKV iwkv) {
pthread_rwlock_unlock(&(db_)->iwkv->rwl); \
return iwrc_set_errno(IW_ERROR_THREADING_ERRNO, rci_); \
} \
} while(0)
} while (0)
IW_INLINE iwrc _api_db_rlock(IWDB db) {
IW_INLINE iwrc _api_db_rlock(IWDB db) {
int rci;
API_DB_RLOCK(db, rci);
return 0;
@@ -373,9 +372,9 @@ IW_INLINE iwrc _api_db_rlock(IWDB db) {
pthread_rwlock_unlock(&(db_)->iwkv->rwl); \
return iwrc_set_errno(IW_ERROR_THREADING_ERRNO, rci_); \
} \
} while(0)
} while (0)
IW_INLINE iwrc _api_db_wlock(IWDB db) {
IW_INLINE iwrc _api_db_wlock(IWDB db) {
int rci;
API_DB_WLOCK(db, rci);
return 0;
@@ -386,7 +385,7 @@ IW_INLINE iwrc _api_db_wlock(IWDB db) {
(rci_) = pthread_rwlock_unlock(&(db_)->rwl); \
if (rci_) IWRC(iwrc_set_errno(IW_ERROR_THREADING_ERRNO, rci_), rc_); \
API_UNLOCK((db_)->iwkv, rci_, rc_); \
} while(0)
} while (0)
#define AAPOS_INC(aan_) \
do { \
@@ -395,45 +394,45 @@ IW_INLINE iwrc _api_db_wlock(IWDB db) {
} else { \
(aan_) = 0; \
} \
} while(0)
} while (0)
// SBLK
// [flags:u1,lvl:u1,lkl:u1,pnum:u1,p0:u4,kblk:u4,pi:u1[32],n:u4[24],bpos:u1,lk:u115]:u256
#define SOFF_FLAGS_U1 0
#define SOFF_LVL_U1 (SOFF_FLAGS_U1 + 1)
#define SOFF_LKL_U1 (SOFF_LVL_U1 + 1)
#define SOFF_PNUM_U1 (SOFF_LKL_U1 + 1)
#define SOFF_P0_U4 (SOFF_PNUM_U1 + 1)
#define SOFF_KBLK_U4 (SOFF_P0_U4 + 4)
#define SOFF_PI0_U1 (SOFF_KBLK_U4 + 4)
#define SOFF_N0_U4 (SOFF_PI0_U1 + 1 * KVBLK_IDXNUM)
#define SOFF_BPOS_U1_V2 (SOFF_N0_U4 + 4 * SLEVELS)
#define SOFF_LK_V2 (SOFF_BPOS_U1_V2 + 1)
#define SOFF_LK_V1 (SOFF_N0_U4 + 4 * SLEVELS)
#define SOFF_END (SOFF_LK_V2 + SBLK_LKLEN)
#define SOFF_FLAGS_U1 0
#define SOFF_LVL_U1 (SOFF_FLAGS_U1 + 1)
#define SOFF_LKL_U1 (SOFF_LVL_U1 + 1)
#define SOFF_PNUM_U1 (SOFF_LKL_U1 + 1)
#define SOFF_P0_U4 (SOFF_PNUM_U1 + 1)
#define SOFF_KBLK_U4 (SOFF_P0_U4 + 4)
#define SOFF_PI0_U1 (SOFF_KBLK_U4 + 4)
#define SOFF_N0_U4 (SOFF_PI0_U1 + 1 * KVBLK_IDXNUM)
#define SOFF_BPOS_U1_V2 (SOFF_N0_U4 + 4 * SLEVELS)
#define SOFF_LK_V2 (SOFF_BPOS_U1_V2 + 1)
#define SOFF_LK_V1 (SOFF_N0_U4 + 4 * SLEVELS)
#define SOFF_END (SOFF_LK_V2 + SBLK_LKLEN)
static_assert(SOFF_END == 256, "SOFF_END == 256");
static_assert(SBLK_SZ >= SOFF_END, "SBLK_SZ >= SOFF_END");
// DB
// [magic:u4,dbflg:u1,dbid:u4,next_db_blk:u4,p0:u4,n[24]:u4,c[24]:u4,meta_blk:u4,meta_blkn:u4]:217
#define DOFF_MAGIC_U4 0
#define DOFF_DBFLG_U1 (DOFF_MAGIC_U4 + 4)
#define DOFF_DBID_U4 (DOFF_DBFLG_U1 + 1)
#define DOFF_NEXTDB_U4 (DOFF_DBID_U4 + 4)
#define DOFF_P0_U4 (DOFF_NEXTDB_U4 + 4)
#define DOFF_N0_U4 (DOFF_P0_U4 + 4)
#define DOFF_C0_U4 (DOFF_N0_U4 + 4 * SLEVELS)
#define DOFF_METABLK_U4 (DOFF_C0_U4 + 4 * SLEVELS)
#define DOFF_METABLKN_U4 (DOFF_METABLK_U4 + 4)
#define DOFF_END (DOFF_METABLKN_U4 + 4)
#define DOFF_MAGIC_U4 0
#define DOFF_DBFLG_U1 (DOFF_MAGIC_U4 + 4)
#define DOFF_DBID_U4 (DOFF_DBFLG_U1 + 1)
#define DOFF_NEXTDB_U4 (DOFF_DBID_U4 + 4)
#define DOFF_P0_U4 (DOFF_NEXTDB_U4 + 4)
#define DOFF_N0_U4 (DOFF_P0_U4 + 4)
#define DOFF_C0_U4 (DOFF_N0_U4 + 4 * SLEVELS)
#define DOFF_METABLK_U4 (DOFF_C0_U4 + 4 * SLEVELS)
#define DOFF_METABLKN_U4 (DOFF_METABLK_U4 + 4)
#define DOFF_END (DOFF_METABLKN_U4 + 4)
static_assert(DOFF_END == 217, "DOFF_END == 217");
static_assert(DB_SZ >= DOFF_END, "DB_SZ >= DOFF_END");
// KVBLK
// [szpow:u1,idxsz:u2,[ps1:vn,pl1:vn,...,ps32,pl32]____[[_KV],...]] // KVBLK
#define KBLK_SZPOW_OFF 0
#define KBLK_SZPOW_OFF 0
iwrc iwkv_exclusive_lock(IWKV iwkv);
+41 -42
View File
@@ -34,7 +34,6 @@ int clean_suite() {
return 0;
}
// Test5 staff
struct Test5DUP1 {
bool _mv;
@@ -68,13 +67,13 @@ static void iwkv_test3_impl(int fmt_version) {
CU_ASSERT_PTR_NOT_NULL(f);
iwrc rc;
IWKV_val key = {0};
IWKV_val val = {0};
IWKV_val key = { 0 };
IWKV_val val = { 0 };
IWKV iwkv;
IWDB db1;
IWKV_OPTS opts = {
.path = "iwkv_test1_3.db",
.oflags = IWKV_TRUNC,
.path = "iwkv_test1_3.db",
.oflags = IWKV_TRUNC,
.fmt_version = fmt_version
};
@@ -137,13 +136,13 @@ static void iwkv_test2_impl(int fmt_version) {
CU_ASSERT_PTR_NOT_NULL(f);
iwrc rc;
IWKV_val key = {0};
IWKV_val val = {0};
IWKV_val key = { 0 };
IWKV_val val = { 0 };
IWKV iwkv;
IWDB db1;
IWKV_OPTS opts = {
.path = "iwkv_test1_2.db",
.oflags = IWKV_TRUNC,
.path = "iwkv_test1_2.db",
.oflags = IWKV_TRUNC,
.fmt_version = fmt_version
};
@@ -263,17 +262,17 @@ static void iwkv_test1_impl(int fmt_version) {
size_t vsize;
IWKV_OPTS opts = {
.path = "iwkv_test1.db",
.oflags = IWKV_TRUNC,
.path = "iwkv_test1.db",
.oflags = IWKV_TRUNC,
.fmt_version = fmt_version
};
// Test open/close
IWKV iwkv;
IWDB db1, db2, db3;
iwrc rc;
IWKV_val key = {.data = "foo"};
IWKV_val key = { .data = "foo" };
key.size = strlen(key.data);
IWKV_val val = {.data = "bar"};
IWKV_val val = { .data = "bar" };
val.size = strlen(val.data);
rc = iwkv_open(&opts, &iwkv);
@@ -500,8 +499,8 @@ static void iwkv_test1_impl(int fmt_version) {
rc = iwkv_cursor_to(cur1, IWKV_CURSOR_PREV);
CU_ASSERT_EQUAL_FATAL(rc, 0);
int i = 0;
do {
int i = 0;
do {
IWKV_val key;
IWKV_val val;
iwrc rc2 = iwkv_cursor_get(cur1, &key, &val);
@@ -691,8 +690,8 @@ static void iwkv_test1_v2() {
static void iwkv_test8_impl(int fmt_version) {
IWKV_OPTS opts = {
.path = "iwkv_test1_8.db",
.oflags = IWKV_TRUNC,
.path = "iwkv_test1_8.db",
.oflags = IWKV_TRUNC,
.fmt_version = fmt_version
};
IWKV iwkv;
@@ -783,8 +782,8 @@ static void iwkv_test8_v2() {
static void iwkv_test7_impl(int fmt_version) {
IWKV_OPTS opts = {
.path = "iwkv_test1_7.db",
.oflags = IWKV_TRUNC,
.path = "iwkv_test1_7.db",
.oflags = IWKV_TRUNC,
.fmt_version = fmt_version
};
IWKV iwkv;
@@ -829,18 +828,18 @@ static void iwkv_test7_impl(int fmt_version) {
}
static void iwkv_test7_v1() {
iwkv_test7_impl(1) ;
iwkv_test7_impl(1);
}
static void iwkv_test7_v2() {
iwkv_test7_impl(2) ;
iwkv_test7_impl(2);
}
static void iwkv_test6_impl(int fmt_version) {
IWKV_OPTS opts = {
.path = "iwkv_test1_6.db",
.oflags = IWKV_TRUNC,
.fmt_version = fmt_version
.path = "iwkv_test1_6.db",
.oflags = IWKV_TRUNC,
.fmt_version = fmt_version
};
const int vbsiz = 1000 * 1000;
// Test open/close
@@ -897,7 +896,9 @@ int main() {
CU_pSuite pSuite = NULL;
/* Initialize the CUnit test registry */
if (CUE_SUCCESS != CU_initialize_registry()) return CU_get_error();
if (CUE_SUCCESS != CU_initialize_registry()) {
return CU_get_error();
}
/* Add a suite to the registry */
pSuite = CU_add_suite("iwkv_test1", init_suite, clean_suite);
@@ -908,25 +909,23 @@ int main() {
}
/* Add the tests to the suite */
if (
(NULL == CU_add_test(pSuite, "iwkv_test1_v1", iwkv_test1_v1)) ||
(NULL == CU_add_test(pSuite, "iwkv_test1_v2", iwkv_test1_v2)) ||
(NULL == CU_add_test(pSuite, "iwkv_test2_v1", iwkv_test2_v1)) ||
(NULL == CU_add_test(pSuite, "iwkv_test2_v2", iwkv_test2_v2)) ||
(NULL == CU_add_test(pSuite, "iwkv_test3_v1", iwkv_test3_v1)) ||
(NULL == CU_add_test(pSuite, "iwkv_test3_v2", iwkv_test3_v2)) ||
if ( (NULL == CU_add_test(pSuite, "iwkv_test1_v1", iwkv_test1_v1))
|| (NULL == CU_add_test(pSuite, "iwkv_test1_v2", iwkv_test1_v2))
|| (NULL == CU_add_test(pSuite, "iwkv_test2_v1", iwkv_test2_v1))
|| (NULL == CU_add_test(pSuite, "iwkv_test2_v2", iwkv_test2_v2))
|| (NULL == CU_add_test(pSuite, "iwkv_test3_v1", iwkv_test3_v1))
|| (NULL == CU_add_test(pSuite, "iwkv_test3_v2", iwkv_test3_v2)) ||
//- (NULL == CU_add_test(pSuite, "iwkv_test4", iwkv_test4)) ||
//- (NULL == CU_add_test(pSuite, "iwkv_test5", iwkv_test5)) ||
//- (NULL == CU_add_test(pSuite, "iwkv_test4", iwkv_test4)) ||
//- (NULL == CU_add_test(pSuite, "iwkv_test5", iwkv_test5)) ||
(NULL == CU_add_test(pSuite, "iwkv_test6_v1", iwkv_test6_v1)) ||
(NULL == CU_add_test(pSuite, "iwkv_test6_v2", iwkv_test6_v2)) ||
(NULL == CU_add_test(pSuite, "iwkv_test7_v1", iwkv_test7_v1)) ||
(NULL == CU_add_test(pSuite, "iwkv_test7_v2", iwkv_test7_v2)) ||
(NULL == CU_add_test(pSuite, "iwkv_test8_v1", iwkv_test8_v1)) ||
(NULL == CU_add_test(pSuite, "iwkv_test8_v2", iwkv_test8_v2)) ||
(NULL == CU_add_test(pSuite, "iwkv_test9", iwkv_test9))
) {
(NULL == CU_add_test(pSuite, "iwkv_test6_v1", iwkv_test6_v1))
|| (NULL == CU_add_test(pSuite, "iwkv_test6_v2", iwkv_test6_v2))
|| (NULL == CU_add_test(pSuite, "iwkv_test7_v1", iwkv_test7_v1))
|| (NULL == CU_add_test(pSuite, "iwkv_test7_v2", iwkv_test7_v2))
|| (NULL == CU_add_test(pSuite, "iwkv_test8_v1", iwkv_test8_v1))
|| (NULL == CU_add_test(pSuite, "iwkv_test8_v2", iwkv_test8_v2))
|| (NULL == CU_add_test(pSuite, "iwkv_test9", iwkv_test9))) {
CU_cleanup_registry();
return CU_get_error();
}
+8 -9
View File
@@ -18,13 +18,12 @@ int clean_suite(void) {
return 0;
}
static void iwkv_test10_1_impl(int fmt_version) {
IWKV iwkv;
IWKV_OPTS opts = {
.path = fmt_version > 1 ? "iwkv_test10_1_v2.db" : "iwkv_test10_1_v1.db",
.oflags = IWKV_TRUNC,
.wal = {
.path = fmt_version > 1 ? "iwkv_test10_1_v2.db" : "iwkv_test10_1_v1.db",
.oflags = IWKV_TRUNC,
.wal = {
.enabled = true
}
};
@@ -119,7 +118,9 @@ int main() {
CU_pSuite pSuite = NULL;
/* Initialize the CUnit test registry */
if (CUE_SUCCESS != CU_initialize_registry()) return CU_get_error();
if (CUE_SUCCESS != CU_initialize_registry()) {
return CU_get_error();
}
/* Add a suite to the registry */
pSuite = CU_add_suite("iwkv_test8", init_suite, clean_suite);
@@ -130,10 +131,8 @@ int main() {
}
/* Add the tests to the suite */
if (
(NULL == CU_add_test(pSuite, "iwkv_test10_1_v1", iwkv_test10_1_v1)) ||
(NULL == CU_add_test(pSuite, "iwkv_test10_1_v2", iwkv_test10_1_v2))
) {
if ( (NULL == CU_add_test(pSuite, "iwkv_test10_1_v1", iwkv_test10_1_v1))
|| (NULL == CU_add_test(pSuite, "iwkv_test10_1_v2", iwkv_test10_1_v2))) {
CU_cleanup_registry();
return CU_get_error();
}
+6 -6
View File
@@ -4,10 +4,9 @@
#include "iwcfg.h"
#include <CUnit/Basic.h>
#define RND_DATA_SZ (10*1048576)
#define RND_DATA_SZ (10 * 1048576)
char RND_DATA[RND_DATA_SZ];
int init_suite(void) {
iwrc rc = iwkv_init();
return rc;
@@ -19,7 +18,7 @@ int clean_suite(void) {
static void iwkv_test2_1(void) {
IWKV_OPTS opts = {
.path = "iwkv_test2_1.db",
.path = "iwkv_test2_1.db",
.oflags = IWKV_TRUNC
};
const uint64_t numrec = 1000000; // 1M
@@ -60,7 +59,9 @@ int main() {
CU_pSuite pSuite = NULL;
/* Initialize the CUnit test registry */
if (CUE_SUCCESS != CU_initialize_registry()) return CU_get_error();
if (CUE_SUCCESS != CU_initialize_registry()) {
return CU_get_error();
}
/* Add a suite to the registry */
pSuite = CU_add_suite("iwkv_test2", init_suite, clean_suite);
@@ -71,8 +72,7 @@ int main() {
}
/* Add the tests to the suite */
if ((NULL == CU_add_test(pSuite, "iwkv_test2_1", iwkv_test2_1))
) {
if ((NULL == CU_add_test(pSuite, "iwkv_test2_1", iwkv_test2_1))) {
CU_cleanup_registry();
return CU_get_error();
}
+19 -19
View File
@@ -16,17 +16,17 @@ typedef struct VN {
typedef struct CTX {
VN *vn;
int vnsz;
pthread_cond_t cond;
pthread_cond_t cond;
pthread_mutex_t mtx;
int readynum;
int readynum;
const int thrnum;
IWDB db;
IWDB db;
} CTX;
typedef struct TASK {
CTX *ctx;
int start;
int cnt;
CTX *ctx;
int start;
int cnt;
pthread_t thr;
} TASK;
@@ -82,10 +82,10 @@ static void iwkv_test3_impl(int thrnum, int recth, bool wal) {
TASK *tasks = calloc(thrnum, sizeof(*tasks));
VN *arr = calloc(nrecs, sizeof(*arr));
CTX ctx = {
.vn = arr,
.vnsz = nrecs,
.mtx = PTHREAD_MUTEX_INITIALIZER,
.cond = PTHREAD_COND_INITIALIZER,
.vn = arr,
.vnsz = nrecs,
.mtx = PTHREAD_MUTEX_INITIALIZER,
.cond = PTHREAD_COND_INITIALIZER,
.thrnum = thrnum
};
for (int i = 0; i < nrecs; ++i) {
@@ -107,10 +107,10 @@ static void iwkv_test3_impl(int thrnum, int recth, bool wal) {
}
IWKV_OPTS opts = {
.path = "iwkv_test3_1.db",
.oflags = IWKV_TRUNC,
.wal = {
.enabled = wal,
.path = "iwkv_test3_1.db",
.oflags = IWKV_TRUNC,
.wal = {
.enabled = wal,
.checkpoint_buffer_sz = 1024 * 1024
}
};
@@ -174,7 +174,9 @@ int main() {
CU_pSuite pSuite = NULL;
/* Initialize the CUnit test registry */
if (CUE_SUCCESS != CU_initialize_registry()) return CU_get_error();
if (CUE_SUCCESS != CU_initialize_registry()) {
return CU_get_error();
}
/* Add a suite to the registry */
pSuite = CU_add_suite("iwkv_test3", init_suite, clean_suite);
@@ -185,10 +187,8 @@ int main() {
}
/* Add the tests to the suite */
if (
(NULL == CU_add_test(pSuite, "iwkv_test3_1", iwkv_test3_1)) ||
(NULL == CU_add_test(pSuite, "iwkv_test3_2", iwkv_test3_2))
) {
if ( (NULL == CU_add_test(pSuite, "iwkv_test3_1", iwkv_test3_1))
|| (NULL == CU_add_test(pSuite, "iwkv_test3_2", iwkv_test3_2))) {
CU_cleanup_registry();
return CU_get_error();
}
+44 -44
View File
@@ -7,7 +7,7 @@
uint32_t g_seed;
uint32_t g_rnd_data_pos;
#define RND_DATA_SZ (10*1048576)
#define RND_DATA_SZ (10 * 1048576)
char RND_DATA[RND_DATA_SZ];
static void *rndbuf_next(uint32_t len) {
@@ -17,7 +17,7 @@ static void *rndbuf_next(uint32_t len) {
}
const char *ret = RND_DATA + g_rnd_data_pos;
g_rnd_data_pos += len;
return (void *) ret;
return (void*) ret;
}
int init_suite(void) {
@@ -45,15 +45,15 @@ static void iwkv_test4_4(void) {
char *path = "iwkv_test4_4.db";
IWKV iwkv;
IWDB db1;
IWKV_val key = {0};
IWKV_val val = {0};
IWKV_val key = { 0 };
IWKV_val val = { 0 };
IWKV_OPTS opts = {
.path = path,
.oflags = IWKV_TRUNC,
.random_seed = g_seed,
.wal = {
.enabled = true,
.savepoint_timeout_sec = 2,
.path = path,
.oflags = IWKV_TRUNC,
.random_seed = g_seed,
.wal = {
.enabled = true,
.savepoint_timeout_sec = 2,
.checkpoint_timeout_sec = 300
}
};
@@ -83,17 +83,17 @@ static void iwkv_test4_3_impl(int fmt_version) {
char *path = "iwkv_test4_3.db";
IWKV iwkv;
IWDB db1;
IWKV_val key = {0};
IWKV_val val = {0};
IWKV_val key = { 0 };
IWKV_val val = { 0 };
IWKV_OPTS opts = {
.path = path,
.oflags = IWKV_TRUNC | IWKV_NO_TRIM_ON_CLOSE,
.random_seed = g_seed,
.fmt_version = fmt_version,
.wal = {
.enabled = true,
.path = path,
.oflags = IWKV_TRUNC | IWKV_NO_TRIM_ON_CLOSE,
.random_seed = g_seed,
.fmt_version = fmt_version,
.wal = {
.enabled = true,
.check_crc_on_checkpoint = true,
.savepoint_timeout_sec = UINT32_MAX
.savepoint_timeout_sec = UINT32_MAX
}
};
iwrc rc = iwkv_open(&opts, &iwkv);
@@ -183,18 +183,18 @@ static void iwkv_test2_impl(char *path, const char *walpath, uint32_t num, uint3
if (walpath) {
unlink(walpath);
}
IWKV_val key = {0};
IWKV_val val = {0};
IWKV_val key = { 0 };
IWKV_val val = { 0 };
IWKV_OPTS opts = {
.path = path,
.oflags = IWKV_TRUNC,
.random_seed = g_seed,
.wal = {
.enabled = (walpath != NULL),
.path = path,
.oflags = IWKV_TRUNC,
.random_seed = g_seed,
.wal = {
.enabled = (walpath != NULL),
.check_crc_on_checkpoint = true,
.savepoint_timeout_sec = UINT32_MAX,
.wal_buffer_sz = 64 * 1024,
.checkpoint_buffer_sz = 32 * 1024 * 1024
.savepoint_timeout_sec = UINT32_MAX,
.wal_buffer_sz = 64 * 1024,
.checkpoint_buffer_sz = 32 * 1024 * 1024
}
};
rc = iwkv_open(&opts, &iwkv);
@@ -237,20 +237,20 @@ static void iwkv_test4_2(void) {
fclose(iw2);
}
static void iwkv_test1_impl(char *path, const char *walpath) {
static void iwkv_test1_impl(char *path, const char *walpath) {
iwrc rc;
IWKV iwkv;
IWDB db1, db2;
if (walpath) {
unlink(walpath);
}
IWKV_val key = {0};
IWKV_val val = {0};
IWKV_val key = { 0 };
IWKV_val val = { 0 };
IWKV_OPTS opts = {
.path = path,
.oflags = IWKV_TRUNC,
.wal = {
.enabled = (walpath != NULL),
.path = path,
.oflags = IWKV_TRUNC,
.wal = {
.enabled = (walpath != NULL),
.savepoint_timeout_sec = UINT32_MAX
}
};
@@ -313,7 +313,9 @@ int main() {
CU_pSuite pSuite = NULL;
/* Initialize the CUnit test registry */
if (CUE_SUCCESS != CU_initialize_registry()) return CU_get_error();
if (CUE_SUCCESS != CU_initialize_registry()) {
return CU_get_error();
}
/* Add a suite to the registry */
pSuite = CU_add_suite("iwkv_test4", init_suite, clean_suite);
@@ -323,13 +325,11 @@ int main() {
return CU_get_error();
}
/* Add the tests to the suite */
if (
(NULL == CU_add_test(pSuite, "iwkv_test4_1", iwkv_test4_1)) ||
(NULL == CU_add_test(pSuite, "iwkv_test4_2", iwkv_test4_2)) ||
(NULL == CU_add_test(pSuite, "iwkv_test4_3_v1", iwkv_test4_3_v1)) ||
(NULL == CU_add_test(pSuite, "iwkv_test4_3_v2", iwkv_test4_3_v2)) ||
(NULL == CU_add_test(pSuite, "iwkv_test4_4", iwkv_test4_4))
) {
if ( (NULL == CU_add_test(pSuite, "iwkv_test4_1", iwkv_test4_1))
|| (NULL == CU_add_test(pSuite, "iwkv_test4_2", iwkv_test4_2))
|| (NULL == CU_add_test(pSuite, "iwkv_test4_3_v1", iwkv_test4_3_v1))
|| (NULL == CU_add_test(pSuite, "iwkv_test4_3_v2", iwkv_test4_3_v2))
|| (NULL == CU_add_test(pSuite, "iwkv_test4_4", iwkv_test4_4))) {
CU_cleanup_registry();
return CU_get_error();
}
+19 -21
View File
@@ -27,11 +27,11 @@ static void iwkv_test5_2() {
iwrc rc;
IWKV iwkv;
IWDB db;
IWKV_val key = {0};
IWKV_val val = {0};
IWKV_val key = { 0 };
IWKV_val val = { 0 };
IWKV_cursor cur1;
IWKV_OPTS opts = {
.path = "iwkv_test5_2.db",
.path = "iwkv_test5_2.db",
.oflags = IWKV_TRUNC
};
@@ -107,13 +107,13 @@ static void iwkv_test5_2() {
static void iwkv_test5_1(void) {
iwrc rc;
IWKV_val key = {0};
IWKV_val val = {0};
IWKV_val key = { 0 };
IWKV_val val = { 0 };
IWKV iwkv;
IWDB db;
IWKV_cursor cur1, cur2;
IWKV_OPTS opts = {
.path = "iwkv_test5_1.db",
.path = "iwkv_test5_1.db",
.oflags = IWKV_TRUNC
};
rc = iwkv_open(&opts, &iwkv);
@@ -211,16 +211,16 @@ static void iwkv_test5_1(void) {
rc = iwkv_cursor_get(cur1, &key, &val);
CU_ASSERT_EQUAL_FATAL(rc, 0);
CU_ASSERT_FALSE(strncmp((char *)key.data, "025kkk", strlen("025kkk")));
CU_ASSERT_FALSE(strncmp((char *)val.data, "025val", strlen("025val")));
CU_ASSERT_FALSE(strncmp((char*) key.data, "025kkk", strlen("025kkk")));
CU_ASSERT_FALSE(strncmp((char*) val.data, "025val", strlen("025val")));
iwkv_kv_dispose(&key, &val);
rc = iwkv_cursor_to(cur1, IWKV_CURSOR_NEXT);
CU_ASSERT_EQUAL_FATAL(rc, 0);
rc = iwkv_cursor_get(cur1, &key, &val);
CU_ASSERT_EQUAL_FATAL(rc, 0);
CU_ASSERT_FALSE(strncmp((char *)key.data, "023kkk", strlen("023kkk")));
CU_ASSERT_FALSE(strncmp((char *)val.data, "023val", strlen("023val")));
CU_ASSERT_FALSE(strncmp((char*) key.data, "023kkk", strlen("023kkk")));
CU_ASSERT_FALSE(strncmp((char*) val.data, "023val", strlen("023val")));
iwkv_kv_dispose(&key, &val);
rc = iwkv_cursor_to(cur1, IWKV_CURSOR_PREV);
@@ -229,16 +229,16 @@ static void iwkv_test5_1(void) {
CU_ASSERT_EQUAL_FATAL(rc, 0);
rc = iwkv_cursor_get(cur1, &key, &val);
CU_ASSERT_EQUAL_FATAL(rc, 0);
CU_ASSERT_FALSE(strncmp((char *)key.data, "026kkk", strlen("026kkk")));
CU_ASSERT_FALSE(strncmp((char *)val.data, "026val", strlen("026val")));
CU_ASSERT_FALSE(strncmp((char*) key.data, "026kkk", strlen("026kkk")));
CU_ASSERT_FALSE(strncmp((char*) val.data, "026val", strlen("026val")));
iwkv_kv_dispose(&key, &val);
rc = iwkv_cursor_to(cur1, IWKV_CURSOR_PREV);
CU_ASSERT_EQUAL_FATAL(rc, 0);
rc = iwkv_cursor_get(cur1, &key, &val);
CU_ASSERT_EQUAL_FATAL(rc, 0);
CU_ASSERT_FALSE(strncmp((char *)key.data, "027kkk", strlen("027kkk")));
CU_ASSERT_FALSE(strncmp((char *)val.data, "027val", strlen("027val")));
CU_ASSERT_FALSE(strncmp((char*) key.data, "027kkk", strlen("027kkk")));
CU_ASSERT_FALSE(strncmp((char*) val.data, "027val", strlen("027val")));
iwkv_kv_dispose(&key, &val);
CU_ASSERT_EQUAL(cur1->cnpos, 17);
@@ -251,12 +251,13 @@ static void iwkv_test5_1(void) {
CU_ASSERT_EQUAL_FATAL(rc, 0);
}
int main() {
CU_pSuite pSuite = NULL;
/* Initialize the CUnit test registry */
if (CUE_SUCCESS != CU_initialize_registry()) return CU_get_error();
if (CUE_SUCCESS != CU_initialize_registry()) {
return CU_get_error();
}
/* Add a suite to the registry */
pSuite = CU_add_suite("iwkv_test5", init_suite, clean_suite);
@@ -267,11 +268,8 @@ int main() {
}
/* Add the tests to the suite */
if (
(NULL == CU_add_test(pSuite, "iwkv_test5_1", iwkv_test5_1)) ||
(NULL == CU_add_test(pSuite, "iwkv_test5_2", iwkv_test5_2))
) {
if ( (NULL == CU_add_test(pSuite, "iwkv_test5_1", iwkv_test5_1))
|| (NULL == CU_add_test(pSuite, "iwkv_test5_2", iwkv_test5_2))) {
CU_cleanup_registry();
return CU_get_error();
}
+15 -15
View File
@@ -16,15 +16,15 @@ int clean_suite(void) {
static void iwkv_test6_1_impl(int fmt_version) {
iwrc rc;
IWKV_val key = {0};
IWKV_val val = {0};
IWKV_val key = { 0 };
IWKV_val val = { 0 };
IWKV iwkv;
IWDB db;
IWKV_cursor cur;
IWKV_OPTS opts = {
.path = "iwkv_test6_1.db",
.oflags = IWKV_TRUNC,
.path = "iwkv_test6_1.db",
.oflags = IWKV_TRUNC,
.fmt_version = fmt_version
};
rc = iwkv_open(&opts, &iwkv);
@@ -84,13 +84,13 @@ static void iwkv_test6_2_impl(int fmt_version) {
iwrc rc;
IWKV iwkv;
IWDB db;
IWKV_val key = {0};
IWKV_val val = {0};
IWKV_val key = { 0 };
IWKV_val val = { 0 };
char kbuf[PREFIX_KEY_LEN_V1];
IWKV_OPTS opts = {
.path = "iwkv_test6_2.db",
.oflags = IWKV_TRUNC,
.path = "iwkv_test6_2.db",
.oflags = IWKV_TRUNC,
.fmt_version = fmt_version
};
rc = iwkv_open(&opts, &iwkv);
@@ -128,7 +128,9 @@ int main() {
CU_pSuite pSuite = NULL;
/* Initialize the CUnit test registry */
if (CUE_SUCCESS != CU_initialize_registry()) return CU_get_error();
if (CUE_SUCCESS != CU_initialize_registry()) {
return CU_get_error();
}
/* Add a suite to the registry */
pSuite = CU_add_suite("iwkv_test6", init_suite, clean_suite);
@@ -139,12 +141,10 @@ int main() {
}
/* Add the tests to the suite */
if (
(NULL == CU_add_test(pSuite, "iwkv_test6_1_v1", iwkv_test6_1_v1)) ||
(NULL == CU_add_test(pSuite, "iwkv_test6_1_v2", iwkv_test6_1_v2)) ||
(NULL == CU_add_test(pSuite, "iwkv_test6_2_v1", iwkv_test6_2_v1)) ||
(NULL == CU_add_test(pSuite, "iwkv_test6_2_v2", iwkv_test6_2_v2))
) {
if ( (NULL == CU_add_test(pSuite, "iwkv_test6_1_v1", iwkv_test6_1_v1))
|| (NULL == CU_add_test(pSuite, "iwkv_test6_1_v2", iwkv_test6_1_v2))
|| (NULL == CU_add_test(pSuite, "iwkv_test6_2_v1", iwkv_test6_2_v1))
|| (NULL == CU_add_test(pSuite, "iwkv_test6_2_v2", iwkv_test6_2_v2))) {
CU_cleanup_registry();
return CU_get_error();
}
+11 -10
View File
@@ -27,11 +27,11 @@ static void iwkv_test7_1_impl(int direction) {
iwrc rc;
IWKV iwkv;
IWDB db;
IWKV_val key = {0};
IWKV_val val = {0};
IWKV_val key = { 0 };
IWKV_val val = { 0 };
IWKV_OPTS opts = {
.path = direction > 0 ? "iwkv_test7_2_fwd.db" : "iwkv_test7_2_back.db",
.oflags = IWKV_TRUNC,
.path = direction > 0 ? "iwkv_test7_2_fwd.db" : "iwkv_test7_2_back.db",
.oflags = IWKV_TRUNC,
.random_seed = g_seed
};
rc = iwkv_open(&opts, &iwkv);
@@ -71,20 +71,22 @@ static void iwkv_test7_1_impl(int direction) {
static void iwkv_test7_1() {
iwkv_test7_1_impl(1);
iwkv_test7_1_impl(-1);
IWP_FILE_STAT fwd_s = {0};
IWP_FILE_STAT back_s = {0};
IWP_FILE_STAT fwd_s = { 0 };
IWP_FILE_STAT back_s = { 0 };
iwrc rc = iwp_fstat("iwkv_test7_2_fwd.db", &fwd_s);
CU_ASSERT_EQUAL_FATAL(rc, 0);
rc = iwp_fstat("iwkv_test7_2_back.db", &back_s);
CU_ASSERT_EQUAL_FATAL(rc, 0);
CU_ASSERT_TRUE((double)fwd_s.size / back_s.size < 1.1);
CU_ASSERT_TRUE((double) fwd_s.size / back_s.size < 1.1);
}
int main() {
CU_pSuite pSuite = NULL;
/* Initialize the CUnit test registry */
if (CUE_SUCCESS != CU_initialize_registry()) return CU_get_error();
if (CUE_SUCCESS != CU_initialize_registry()) {
return CU_get_error();
}
/* Add a suite to the registry */
pSuite = CU_add_suite("iwkv_test7", init_suite, clean_suite);
@@ -96,8 +98,7 @@ int main() {
/* Add the tests to the suite */
if (
(NULL == CU_add_test(pSuite, "iwkv_test7_1", iwkv_test7_1))
) {
(NULL == CU_add_test(pSuite, "iwkv_test7_1", iwkv_test7_1))) {
CU_cleanup_registry();
return CU_get_error();
}
+23 -21
View File
@@ -32,12 +32,12 @@ int clean_suite(void) {
static void iwkv_test8_1() {
IWKV iwkv;
IWDB db;
IWKV_val key = {0};
IWKV_val val = {0};
IWKV_val key = { 0 };
IWKV_val val = { 0 };
IWKV_OPTS opts = {
.path = "iwkv_test8_1.db",
.oflags = IWKV_TRUNC,
.wal = {
.path = "iwkv_test8_1.db",
.oflags = IWKV_TRUNC,
.wal = {
.enabled = true
}
};
@@ -66,7 +66,9 @@ static void iwkv_test8_1() {
rc = iwkv_open(&opts, &iwkv);
CU_ASSERT_EQUAL_FATAL(rc, 0);
rc = iwkv_online_backup(iwkv, &ts, "iwkv_test8_1_bkp.db");
if (rc) iwlog_ecode_error3(rc);
if (rc) {
iwlog_ecode_error3(rc);
}
CU_ASSERT_EQUAL_FATAL(rc, 0);
rc = iwkv_close(&iwkv);
CU_ASSERT_EQUAL_FATAL(rc, 0);
@@ -97,16 +99,16 @@ static void iwkv_test8_1() {
typedef struct T82 {
pthread_t t;
pthread_barrier_t barrier;
pthread_cond_t cond;
pthread_mutex_t mtx;
pthread_cond_t cond;
pthread_mutex_t mtx;
IWKV iwkv;
IWKV iwkvcheck;
} T82;
static void *t82(void *ctx_) {
T82 *ctx = ctx_;
IWKV_val key = {0};
IWKV_val val = {0};
IWKV_val key = { 0 };
IWKV_val val = { 0 };
iwrc rc = iwkv_open(&(IWKV_OPTS) {
.path = "iwkv_test8_2_check.db",
@@ -122,7 +124,7 @@ static void *t82(void *ctx_) {
CU_ASSERT_EQUAL_FATAL(rc, 0);
int i = 0;
for (; i < 500000; ++i) {
for ( ; i < 500000; ++i) {
snprintf(kbuf, KBUFSZ, "%dkey", i);
key.data = kbuf;
key.size = strlen(key.data);
@@ -143,7 +145,7 @@ static void *t82(void *ctx_) {
pthread_barrier_wait(&ctx->barrier);
int c = i + 10000;
for (; i < c; ++i) {
for ( ; i < c; ++i) {
if (i == c - 9800) { // Force checkpoint during online-backup
rc = iwal_test_checkpoint(ctx->iwkv);
@@ -174,14 +176,14 @@ static void *t82(void *ctx_) {
static void iwkv_test8_2() {
IWKV_OPTS opts = {
.path = "iwkv_test8_2.db",
.oflags = IWKV_TRUNC,
.wal = {
.path = "iwkv_test8_2.db",
.oflags = IWKV_TRUNC,
.wal = {
.enabled = true
}
};
T82 ctx = {0};
T82 ctx = { 0 };
iwrc rc = iwkv_open(&opts, &ctx.iwkv);
CU_ASSERT_EQUAL_FATAL(rc, 0);
@@ -267,7 +269,9 @@ int main() {
CU_pSuite pSuite = NULL;
/* Initialize the CUnit test registry */
if (CUE_SUCCESS != CU_initialize_registry()) return CU_get_error();
if (CUE_SUCCESS != CU_initialize_registry()) {
return CU_get_error();
}
/* Add a suite to the registry */
pSuite = CU_add_suite("iwkv_test8", init_suite, clean_suite);
@@ -278,10 +282,8 @@ int main() {
}
/* Add the tests to the suite */
if (
(NULL == CU_add_test(pSuite, "iwkv_test8_1", iwkv_test8_1)) ||
(NULL == CU_add_test(pSuite, "iwkv_test8_2", iwkv_test8_2))
) {
if ( (NULL == CU_add_test(pSuite, "iwkv_test8_1", iwkv_test8_1))
|| (NULL == CU_add_test(pSuite, "iwkv_test8_2", iwkv_test8_2))) {
CU_cleanup_registry();
return CU_get_error();
}
+7 -8
View File
@@ -15,7 +15,7 @@ int clean_suite() {
static void iwkv_test9_1() {
IWKV_OPTS opts = {
.path = "iwkv_test9_1.db",
.path = "iwkv_test9_1.db",
.oflags = IWKV_TRUNC
};
IWKV kv = NULL;
@@ -30,7 +30,7 @@ static void iwkv_test9_1() {
IWKV_val ikey, ival;
ikey.data = ip1;
ikey.size = 4;
ival.data = (void *)"";
ival.data = (void*) "";
ival.size = 0;
iwkv_opflags opflags = IWKV_NO_OVERWRITE;
iwrc rc = iwkv_put(db, &ikey, &ival, opflags);
@@ -42,22 +42,22 @@ static void iwkv_test9_1() {
IWKV_val ikey, ival;
ikey.data = ip2;
ikey.size = 4;
ival.data = (void *)"";
ival.data = (void*) "";
ival.size = 0;
iwkv_opflags opflags = IWKV_NO_OVERWRITE;
iwrc rc = iwkv_put(db, &ikey, &ival, opflags);
CU_ASSERT_EQUAL(rc, 0);
}
iwkv_close(&kv);
}
int main() {
CU_pSuite pSuite = NULL;
/* Initialize the CUnit test registry */
if (CUE_SUCCESS != CU_initialize_registry()) return CU_get_error();
if (CUE_SUCCESS != CU_initialize_registry()) {
return CU_get_error();
}
/* Add a suite to the registry */
pSuite = CU_add_suite("iwkv_test9", init_suite, clean_suite);
@@ -69,8 +69,7 @@ int main() {
/* Add the tests to the suite */
if (
(NULL == CU_add_test(pSuite, "iwkv_test9_1", iwkv_test9_1))
) {
(NULL == CU_add_test(pSuite, "iwkv_test9_1", iwkv_test9_1))) {
CU_cleanup_registry();
return CU_get_error();
}
+2 -3
View File
@@ -3,8 +3,7 @@
void iwkvd_trigger_xor(uint64_t val);
static int cmp_files(FILE *f1, FILE *f2) {
static int cmp_files(FILE *f1, FILE *f2) {
CU_ASSERT_TRUE_FATAL(f1 && f2);
fseek(f1, 0, SEEK_SET);
fseek(f2, 0, SEEK_SET);
@@ -13,7 +12,7 @@ static int cmp_files(FILE *f1, FILE *f2) {
int pos = 0, line = 1;
while (c1 != EOF && c2 != EOF) {
pos++;
if (c1 == '\n' && c2 == '\n') {
if ((c1 == '\n') && (c2 == '\n')) {
line++;
pos = 0;
} else if (c1 != c2) {
+91 -73
View File
@@ -4,7 +4,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -25,7 +25,6 @@
* SOFTWARE.
*************************************************************************************************/
#include "iwcfg.h"
#include "iwp.h"
#include "iwlog.h"
@@ -40,7 +39,7 @@
#include <time.h>
#include <limits.h>
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__ANDROID__)
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__ANDROID__) || !_GNU_SOURCE
#include <libgen.h>
#elif defined(_WIN32)
#include <libiberty/libiberty.h>
@@ -54,25 +53,25 @@
#include <android/log.h>
#endif // __ANDROID__
static iwrc _default_logfn(FILE *out, locale_t locale, iwlog_lvl lvl, iwrc ecode, int errno_code, int werror_code,
const char *file, int line, uint64_t ts, void *opts, const char *fmt,
va_list argp);
static iwrc _default_logfn(
FILE *out, locale_t locale, iwlog_lvl lvl, iwrc ecode, int errno_code, int werror_code,
const char *file, int line, uint64_t ts, void *opts, const char *fmt,
va_list argp, bool no_va);
static const char *_ecode_explained(locale_t locale, uint32_t ecode);
static const char *_default_ecodefn(locale_t locale, uint32_t ecode);
static const char* _ecode_explained(locale_t locale, uint32_t ecode);
static const char* _default_ecodefn(locale_t locale, uint32_t ecode);
static IWLOG_FN _current_logfn;
static pthread_mutex_t _mtx = PTHREAD_MUTEX_INITIALIZER;
static IWLOG_FN _current_logfn = _default_logfn;
static void *_current_logfn_options = 0;
#define _IWLOG_MAX_ECODE_FUN 256
static IWLOG_ECODE_FN _ecode_functions[_IWLOG_MAX_ECODE_FUN] = {0};
static IWLOG_ECODE_FN _ecode_functions[_IWLOG_MAX_ECODE_FUN] = { 0 };
iwrc iwlog(iwlog_lvl lvl, iwrc ecode, const char *file, int line, const char *fmt, ...) {
va_list argp;
iwrc rc;
va_start(argp, fmt);
rc = iwlog_va(stderr, lvl, ecode, file, line, fmt, argp);
rc = iwlog_va(stderr, lvl, ecode, file, line, fmt, argp, false);
va_end(argp);
return rc;
}
@@ -80,11 +79,25 @@ iwrc iwlog(iwlog_lvl lvl, iwrc ecode, const char *file, int line, const char *fm
void iwlog2(iwlog_lvl lvl, iwrc ecode, const char *file, int line, const char *fmt, ...) {
va_list argp;
va_start(argp, fmt);
iwlog_va(stderr, lvl, ecode, file, line, fmt, argp);
iwlog_va(stderr, lvl, ecode, file, line, fmt, argp, false);
va_end(argp);
}
iwrc iwlog_va(FILE *out, iwlog_lvl lvl, iwrc ecode, const char *file, int line, const char *fmt, va_list argp) {
void iwlog3(iwlog_lvl lvl, iwrc ecode, const char *file, int line, const char *data) {
va_list argp = { 0 };
iwlog_va(stderr, lvl, ecode, file, line, data, argp, true);
}
iwrc iwlog_va(
FILE *out,
iwlog_lvl lvl,
iwrc ecode,
const char *file,
int line,
const char *fmt,
va_list argp,
bool no_va
) {
assert(_current_logfn);
#ifdef _WIN32
@@ -99,12 +112,10 @@ iwrc iwlog_va(FILE *out, iwlog_lvl lvl, iwrc ecode, const char *file, int line,
iwrc rc = iwp_current_time_ms(&ts, false);
RCRET(rc);
pthread_mutex_lock(&_mtx);
IWLOG_FN logfn = _current_logfn;
void *opts = _current_logfn_options;
pthread_mutex_unlock(&_mtx);
rc = logfn(out, locale, lvl, ecode, errno_code, werror_code, file, line, ts, opts, fmt, argp);
rc = logfn(out, locale, lvl, ecode, errno_code, werror_code, file, line, ts, opts, fmt, argp, no_va);
if (rc) {
fprintf(stderr, "Logging function returned with error: %" PRIu64 IW_LINE_SEP, rc);
}
@@ -112,7 +123,7 @@ iwrc iwlog_va(FILE *out, iwlog_lvl lvl, iwrc ecode, const char *file, int line,
}
#define _IWLOG_ERRNO_RC_MASK 0x01U
#define _IWLOG_WERR_EC_MASK 0x02U
#define _IWLOG_WERR_EC_MASK 0x02U
iwrc iwrc_set_errno(iwrc rc, int errno_code) {
if (!errno_code) {
@@ -132,7 +143,7 @@ uint32_t iwrc_strip_errno(iwrc *rc) {
return 0;
}
*rc = rcv & 0x00000000ffffffffULL;
return (uint32_t)(rcv >> 32) & 0x3fffffffU;
return (uint32_t) (rcv >> 32) & 0x3fffffffU;
}
#ifdef _WIN32
@@ -155,39 +166,29 @@ uint32_t iwrc_strip_werror(iwrc *rc) {
return 0;
}
*rc = rcv & 0x00000000ffffffffULL;
return (uint32_t)(rcv >> 32) & 0x3fffffffU;
return (uint32_t) (rcv >> 32) & 0x3fffffffU;
}
#endif
void iwrc_strip_code(iwrc *rc) {
*rc = *rc & 0x00000000ffffffffULL;
}
void iwlog_set_logfn(IWLOG_FN fp) {
pthread_mutex_lock(&_mtx);
void iwlog_set_logfn(IWLOG_FN fp, void *opts) {
if (!fp) {
_current_logfn = _default_logfn;
} else {
_current_logfn = fp;
}
pthread_mutex_unlock(&_mtx);
_current_logfn_options = opts;
}
IWLOG_FN iwlog_get_logfn(void) {
IWLOG_FN res;
pthread_mutex_lock(&_mtx);
res = _current_logfn;
pthread_mutex_unlock(&_mtx);
return res;
return _current_logfn;
}
void iwlog_set_logfn_opts(void *opts) {
pthread_mutex_lock(&_mtx);
_current_logfn_options = opts;
pthread_mutex_unlock(&_mtx);
}
const char *iwlog_ecode_explained(iwrc ecode) {
const char* iwlog_ecode_explained(iwrc ecode) {
iwrc_strip_errno(&ecode);
const char *res;
pthread_mutex_lock(&_mtx);
@@ -225,7 +226,7 @@ iwrc iwlog_init(void) {
// Assumed:
// 1. `_mtx` is locked.
static const char *_ecode_explained(locale_t locale, uint32_t ecode) {
static const char* _ecode_explained(locale_t locale, uint32_t ecode) {
const char *ret = 0;
for (int i = 0; i < _IWLOG_MAX_ECODE_FUN; ++i) {
if (_ecode_functions[i] == 0) {
@@ -240,7 +241,7 @@ static const char *_ecode_explained(locale_t locale, uint32_t ecode) {
return ret;
}
static const char *_default_ecodefn(locale_t locale, uint32_t ecode) {
static const char* _default_ecodefn(locale_t locale, uint32_t ecode) {
switch (ecode) {
case IW_ERROR_FAIL:
return "Unspecified error. (IW_ERROR_FAIL)";
@@ -282,6 +283,12 @@ static const char *_default_ecodefn(locale_t locale, uint32_t ecode) {
return "Overflow. (IW_ERROR_OVERFLOW)";
case IW_ERROR_INVALID_VALUE:
return " Invalid value. (IW_ERROR_INVALID_VALUE)";
case IW_ERROR_UNEXPECTED_RESPONSE:
return "Unexpected response. (IW_ERROR_UNEXPECTED_RESPONSE)";
case IW_ERROR_NOT_ALLOWED:
return "Action is not allowed. (IW_ERROR_NOT_ALLOWED)";
case IW_ERROR_UNSUPPORTED:
return "Unsupported opration. (IW_ERROR_UNSUPPORTED)";
case IW_OK:
default:
return 0;
@@ -289,23 +296,25 @@ static const char *_default_ecodefn(locale_t locale, uint32_t ecode) {
return 0;
}
static iwrc _default_logfn(FILE *out,
locale_t locale,
iwlog_lvl lvl,
iwrc ecode,
int errno_code,
int werror_code,
const char *file,
int line,
uint64_t ts,
void *opts,
const char *fmt,
va_list argp) {
static iwrc _default_logfn(
FILE *out,
locale_t locale,
iwlog_lvl lvl,
iwrc ecode,
int errno_code,
int werror_code,
const char *file,
int line,
uint64_t ts,
void *opts,
const char *fmt,
va_list argp,
bool no_va
) {
#define TBUF_SZ 96
#define EBUF_SZ 128
#define EBUF_SZ 256
iwrc rc = 0;
IWLOG_DEFAULT_OPTS myopts = {0};
#ifndef IW_ANDROID_LOG
time_t ts_sec = ((long double) ts / 1000);
@@ -322,19 +331,26 @@ static iwrc _default_logfn(FILE *out,
char *fnameptr = fnamebuf;
char *fname = 0;
if (errno_code) {
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__ANDROID__)
int rci = strerror_r(errno_code, ebuf, EBUF_SZ);
if (!rci) {
errno_msg = ebuf;
if (opts) {
out = ((IWLOG_DEFAULT_OPTS*) opts)->out;
if (!out) {
goto finish;
}
#elif defined(_WIN32)
}
if (errno_code) {
#if defined(_WIN32)
int rci = strerror_s(ebuf, EBUF_SZ, errno_code);
if (!rci) {
errno_msg = ebuf;
}
#else
#elif defined(__GLIBC__) && defined(_GNU_SOURCE)
errno_msg = strerror_r(errno_code, ebuf, EBUF_SZ); // NOLINT
#else
int rci = strerror_r(errno_code, ebuf, EBUF_SZ);
if (!rci) {
errno_msg = ebuf;
}
#endif
}
@@ -354,12 +370,6 @@ static iwrc _default_logfn(FILE *out,
}
#endif
if (opts) {
myopts = *(IWLOG_DEFAULT_OPTS *) opts;
if (myopts.out) {
out = myopts.out;
}
}
#ifndef IW_ANDROID_LOG
// cppcheck-suppress portability
@@ -370,7 +380,7 @@ static iwrc _default_logfn(FILE *out,
tbuf[0] = '\0';
} else if (TBUF_SZ - sz > 4) { // .000 suffix
tbuf[sz] = '.';
sz2 = snprintf((char *) tbuf + sz + 1, 4, "%03d", (int)(ts % 1000));
sz2 = snprintf((char*) tbuf + sz + 1, 4, "%03d", (int) (ts % 1000));
if (sz2 > 3) {
tbuf[sz] = '\0';
}
@@ -419,7 +429,7 @@ static iwrc _default_logfn(FILE *out,
if (ecode) {
ecode_msg = _ecode_explained(locale, ecode);
}
if (file && line > 0) {
if (file && (line > 0)) {
size_t len = strlen(file);
if (len < sizeof(fnamebuf)) {
memcpy(fnameptr, file, len);
@@ -428,7 +438,7 @@ static iwrc _default_logfn(FILE *out,
fnameptr = strdup(file);
RCA(fnameptr, finish);
}
#ifdef IW_HAVE_BASENAME_R
#if defined(IW_HAVE_BASENAME_R) && defined(__FreeBSD__)
fname = basename_r(file, fnameptr);
#else
fname = basename(fnameptr); // NOLINT
@@ -443,7 +453,7 @@ static iwrc _default_logfn(FILE *out,
#ifndef IW_ANDROID_LOG
if (ecode || errno_code || werror_code) {
if (fname && line > 0) {
if (fname && (line > 0)) {
fprintf(out, "%s %s %s:%d %" PRIu64 "|%d|%d|%s|%s|%s: ", tbuf, cat, fname, line, ecode, errno_code,
werror_code, (ecode_msg ? ecode_msg : ""), (errno_msg ? errno_msg : ""),
(werror_msg ? werror_msg : "")); // -V547
@@ -452,22 +462,26 @@ static iwrc _default_logfn(FILE *out,
(ecode_msg ? ecode_msg : ""), (errno_msg ? errno_msg : ""), (werror_msg ? werror_msg : "")); // -V547
}
} else {
if (fname && line > 0) {
if (fname && (line > 0)) {
fprintf(out, "%s %s %s:%d: ", tbuf, cat, fname, line);
} else {
fprintf(out, "%s %s: ", tbuf, cat);
}
}
if (fmt) {
vfprintf(out, fmt, argp);
if (no_va) {
fwrite(fmt, strlen(fmt), 1, out);
} else {
vfprintf(out, fmt, argp);
}
}
fprintf(out, IW_LINE_SEP);
fwrite(IW_LINE_SEP, sizeof(IW_LINE_SEP) - 1, 1, out);
fflush(out);
#else
if (ecode || errno_code || werror_code) {
if (fname && line > 0) {
if (fname && (line > 0)) {
__android_log_print(alp, "IWLOG", "%s:%d %" PRIu64 "|%d|%d|%s|%s|%s: ", fname, line, ecode, errno_code,
werror_code, (ecode_msg ? ecode_msg : ""), (errno_msg ? errno_msg : ""),
(werror_msg ? werror_msg : ""));
@@ -476,12 +490,16 @@ static iwrc _default_logfn(FILE *out,
(ecode_msg ? ecode_msg : ""), (errno_msg ? errno_msg : ""), (werror_msg ? werror_msg : ""));
}
} else {
if (fname && line > 0) {
if (fname && (line > 0)) {
__android_log_print(alp, "IWLOG", "%s:%d: ", fname, line);
}
}
if (fmt) {
__android_log_vprint(alp, "IWLOG", fmt, argp);
if (no_va) {
__android_log_write(alp, "IWLOG", fmt);
} else {
__android_log_vprint(alp, "IWLOG", fmt, argp);
}
}
#endif
+83 -79
View File
@@ -7,7 +7,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -77,26 +77,30 @@ IW_EXTERN_C_START
* @brief Common used error codes.
*/
typedef enum {
IW_OK = 0, /**< No error. */
IW_OK = 0, /**< No error. */
IW_ERROR_FAIL = IW_ERROR_START, /**< Unspecified error. */
IW_ERROR_ERRNO, /**< Error with expected errno status set. */
IW_ERROR_IO_ERRNO, /**< IO error with expected errno status set. */
IW_ERROR_NOT_EXISTS, /**< Resource is not exists. */
IW_ERROR_READONLY, /**< Resource is readonly. */
IW_ERROR_ALREADY_OPENED, /**< Resource is already opened. */
IW_ERROR_THREADING, /**< Threading error. */
IW_ERROR_THREADING_ERRNO, /**< Threading error with errno status set. */
IW_ERROR_ASSERTION, /**< Generic assertion error. */
IW_ERROR_INVALID_HANDLE, /**< Invalid HANDLE value. */
IW_ERROR_OUT_OF_BOUNDS, /**< Invalid bounds specified. */
IW_ERROR_NOT_IMPLEMENTED, /**< Method is not implemented. */
IW_ERROR_ALLOC, /**< Memory allocation failed. */
IW_ERROR_INVALID_STATE, /**< Illegal state error. */
IW_ERROR_NOT_ALIGNED, /**< Argument is not aligned properly. */
IW_ERROR_FALSE, /**< Request rejection/false response. */
IW_ERROR_INVALID_ARGS, /**< Invalid function arguments. */
IW_ERROR_OVERFLOW, /**< Overflow. */
IW_ERROR_INVALID_VALUE /**< Invalid value. */
IW_ERROR_IO_ERRNO, /**< IO error with expected errno status set. */
IW_ERROR_AGAIN,
IW_ERROR_NOT_EXISTS, /**< Resource is not exists. */
IW_ERROR_READONLY, /**< Resource is readonly. */
IW_ERROR_ALREADY_OPENED, /**< Resource is already opened. */
IW_ERROR_THREADING, /**< Threading error. */
IW_ERROR_THREADING_ERRNO, /**< Threading error with errno status set. */
IW_ERROR_ASSERTION, /**< Generic assertion error. */
IW_ERROR_INVALID_HANDLE, /**< Invalid HANDLE value. */
IW_ERROR_OUT_OF_BOUNDS, /**< Invalid bounds specified. */
IW_ERROR_NOT_IMPLEMENTED, /**< Method is not implemented. */
IW_ERROR_ALLOC, /**< Memory allocation failed. */
IW_ERROR_INVALID_STATE, /**< Illegal state error. */
IW_ERROR_NOT_ALIGNED, /**< Argument is not aligned properly. */
IW_ERROR_FALSE, /**< Request rejection/false response. */
IW_ERROR_INVALID_ARGS, /**< Invalid function arguments. */
IW_ERROR_OVERFLOW, /**< Overflow. */
IW_ERROR_INVALID_VALUE, /**< Invalid value. */
IW_ERROR_UNEXPECTED_RESPONSE, /**< Unexpected response (IW_ERROR_UNEXPECTED_RESPONSE) */
IW_ERROR_NOT_ALLOWED, /**< Action is not allowed. (IW_ERROR_NOT_ALLOWED) */
IW_ERROR_UNSUPPORTED, /**< Unsupported opration. (IW_ERROR_UNSUPPORTED) */
} iw_ecode;
/**
@@ -105,9 +109,9 @@ typedef enum {
*/
typedef enum {
IWLOG_ERROR = 0,
IWLOG_WARN = 1,
IWLOG_INFO = 2,
IWLOG_DEBUG = 3
IWLOG_WARN = 1,
IWLOG_INFO = 2,
IWLOG_DEBUG = 3,
} iwlog_lvl;
/**
@@ -133,10 +137,11 @@ typedef struct {
*
* @see iwlog_set_logfn(IWLOG_FN)
*/
typedef iwrc(*IWLOG_FN)(FILE *out, locale_t locale, iwlog_lvl lvl, iwrc ecode,
int errno_code, int werror_code, const char *file,
int line, uint64_t ts, void *opts, const char *fmt,
va_list argp);
typedef iwrc (*IWLOG_FN)(
FILE *out, locale_t locale, iwlog_lvl lvl, iwrc ecode,
int errno_code, int werror_code, const char *file,
int line, uint64_t ts, void *opts, const char *fmt,
va_list argp, bool no_va);
/**
* @brief Return the locale aware error code explanation message.
@@ -146,7 +151,7 @@ typedef iwrc(*IWLOG_FN)(FILE *out, locale_t locale, iwlog_lvl lvl, iwrc ecode,
* @return Message string describes a given error code or `NULL` if
* no message found.
*/
typedef const char *(*IWLOG_ECODE_FN)(locale_t locale, uint32_t ecode);
typedef const char* (*IWLOG_ECODE_FN)(locale_t locale, uint32_t ecode);
/**
* @brief Attach the specified @a errno_code code into @a rc code
@@ -197,28 +202,20 @@ IW_EXPORT void iwrc_strip_code(iwrc *rc);
* @param fp Logging function pointer.
* @return Not zero if error occured.
*/
IW_EXPORT void iwlog_set_logfn(IWLOG_FN fp);
IW_EXPORT void iwlog_set_logfn(IWLOG_FN fp, void *opts);
/**
* @brief Get a default logging function.
*
*/
IW_EXPORT IWLOG_FN iwlog_get_logfn(void);
/**
* @brief Set opaque options structure for the
* current logging function implementation.
* @param opts
* @see `IWLOG_DEFAULT_OPTS`
* @see `IWLOG_FN`
*/
IW_EXPORT void iwlog_set_logfn_opts(void *opts);
/**
* @brief Returns string representation of a given error code.
* @param ecode Error code
* @return
*/
IW_EXPORT const char *iwlog_ecode_explained(iwrc ecode);
IW_EXPORT const char* iwlog_ecode_explained(iwrc ecode);
/**
* @brief Register error code explanation function.
@@ -237,104 +234,111 @@ IW_EXPORT iwrc iwlog_register_ecodefn(IWLOG_ECODE_FN fp);
* @param fmt Printf like message format.
* @return
*/
IW_EXPORT iwrc iwlog(iwlog_lvl lvl, iwrc ecode, const char *file, int line,
const char *fmt, ...);
IW_EXPORT iwrc iwlog(
iwlog_lvl lvl, iwrc ecode, const char *file, int line,
const char *fmt, ...) __attribute__((format(__printf__, 5, 6)));
IW_EXPORT void iwlog2(iwlog_lvl lvl, iwrc ecode, const char *file, int line,
const char *fmt, ...);
IW_EXPORT void iwlog2(
iwlog_lvl lvl, iwrc ecode, const char *file, int line,
const char *fmt, ...) __attribute__((format(__printf__, 5, 6)));
IW_EXPORT iwrc iwlog_va(FILE *out, iwlog_lvl lvl, iwrc ecode, const char *file, int line,
const char *fmt, va_list argp);
IW_EXPORT void iwlog3(
iwlog_lvl lvl, iwrc ecode, const char *file, int line,
const char *data);
IW_EXPORT iwrc iwlog_va(
FILE *out, iwlog_lvl lvl, iwrc ecode, const char *file, int line,
const char *fmt, va_list argp, bool no_va);
#ifdef _DEBUG
#define iwlog_debug(IW_fmt, ...) \
iwlog2(IWLOG_DEBUG, 0, __FILE__, __LINE__, (IW_fmt), ##__VA_ARGS__)
iwlog2(IWLOG_DEBUG, 0, __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__)
#else
#define iwlog_debug(IW_fmt, ...)
#endif
#define iwlog_info(IW_fmt, ...) \
iwlog2(IWLOG_INFO, 0, __FILE__, __LINE__, (IW_fmt), ##__VA_ARGS__)
iwlog2(IWLOG_INFO, 0, __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__)
#define iwlog_warn(IW_fmt, ...) \
iwlog2(IWLOG_WARN, 0, __FILE__, __LINE__, (IW_fmt), ##__VA_ARGS__)
iwlog2(IWLOG_WARN, 0, __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__)
#define iwlog_error(IW_fmt, ...) \
iwlog2(IWLOG_ERROR, 0, __FILE__, __LINE__, (IW_fmt), ##__VA_ARGS__)
iwlog2(IWLOG_ERROR, 0, __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__)
#ifdef _DEBUG
#define iwlog_debug2(IW_fmt) \
iwlog2(IWLOG_DEBUG, 0, __FILE__, __LINE__, (IW_fmt))
iwlog3(IWLOG_DEBUG, 0, __FILE__, __LINE__, (IW_fmt))
#else
#define iwlog_debug2(IW_fmt)
#endif
#define iwlog_info2(IW_fmt) iwlog2(IWLOG_INFO, 0, __FILE__, __LINE__, (IW_fmt))
#define iwlog_warn2(IW_fmt) iwlog2(IWLOG_WARN, 0, __FILE__, __LINE__, (IW_fmt))
#define iwlog_info2(IW_fmt) iwlog3(IWLOG_INFO, 0, __FILE__, __LINE__, (IW_fmt))
#define iwlog_warn2(IW_fmt) iwlog3(IWLOG_WARN, 0, __FILE__, __LINE__, (IW_fmt))
#define iwlog_error2(IW_fmt) \
iwlog2(IWLOG_ERROR, 0, __FILE__, __LINE__, (IW_fmt))
iwlog3(IWLOG_ERROR, 0, __FILE__, __LINE__, (IW_fmt))
#ifdef _DEBUG
#define iwlog_ecode_debug(IW_ecode, IW_fmt, ...) \
iwlog2(IWLOG_DEBUG, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ##__VA_ARGS__)
iwlog2(IWLOG_DEBUG, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__)
#else
#define iwlog_ecode_debug(IW_ecode, IW_fmt, ...)
#endif
#define iwlog_ecode_info(IW_ecode, IW_fmt, ...) \
iwlog2(IWLOG_INFO, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ##__VA_ARGS__)
iwlog2(IWLOG_INFO, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__)
#define iwlog_ecode_warn(IW_ecode, IW_fmt, ...) \
iwlog2(IWLOG_WARN, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ##__VA_ARGS__)
iwlog2(IWLOG_WARN, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__)
#define iwlog_ecode_error(IW_ecode, IW_fmt, ...) \
iwlog2(IWLOG_ERROR, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ##__VA_ARGS__)
iwlog2(IWLOG_ERROR, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__)
#ifdef _DEBUG
#define iwlog_ecode_debug2(IW_ecode, IW_fmt) \
iwlog2(IWLOG_DEBUG, (IW_ecode), __FILE__, __LINE__, (IW_fmt))
iwlog3(IWLOG_DEBUG, (IW_ecode), __FILE__, __LINE__, (IW_fmt))
#else
#define iwlog_ecode_debug2(IW_ecode, IW_fmt)
#endif
#define iwlog_ecode_info2(IW_ecode, IW_fmt) \
iwlog2(IWLOG_INFO, (IW_ecode), __FILE__, __LINE__, (IW_fmt))
iwlog3(IWLOG_INFO, (IW_ecode), __FILE__, __LINE__, (IW_fmt))
#define iwlog_ecode_warn2(IW_ecode, IW_fmt) \
iwlog2(IWLOG_WARN, (IW_ecode), __FILE__, __LINE__, (IW_fmt))
iwlog3(IWLOG_WARN, (IW_ecode), __FILE__, __LINE__, (IW_fmt))
#define iwlog_ecode_error2(IW_ecode, IW_fmt) \
iwlog2(IWLOG_ERROR, (IW_ecode), __FILE__, __LINE__, (IW_fmt))
iwlog3(IWLOG_ERROR, (IW_ecode), __FILE__, __LINE__, (IW_fmt))
#ifdef _DEBUG
#define iwlog_ecode_debug3(IW_ecode) \
iwlog2(IWLOG_DEBUG, (IW_ecode), __FILE__, __LINE__, "")
iwlog3(IWLOG_DEBUG, (IW_ecode), __FILE__, __LINE__, "")
#else
#define iwlog_ecode_debug3(IW_ecode)
#endif
#define iwlog_ecode_info3(IW_ecode) iwlog2(IWLOG_INFO, (IW_ecode), __FILE__, __LINE__, ""))
#define iwlog_ecode_info3(IW_ecode) iwlog3(IWLOG_INFO, (IW_ecode), __FILE__, __LINE__, ""))
#define iwlog_ecode_warn3(IW_ecode) \
iwlog2(IWLOG_WARN, (IW_ecode), __FILE__, __LINE__, "")
iwlog3(IWLOG_WARN, (IW_ecode), __FILE__, __LINE__, "")
#define iwlog_ecode_error3(IW_ecode) \
iwlog2(IWLOG_ERROR, (IW_ecode), __FILE__, __LINE__, "")
iwlog3(IWLOG_ERROR, (IW_ecode), __FILE__, __LINE__, "")
#define IWRC(IW_act, IW_rc) \
{ \
iwrc __iwrc = (IW_act); \
if (__iwrc) { \
if (!(IW_rc)) \
(IW_rc) = __iwrc; \
else \
iwlog2(IWLOG_ERROR, __iwrc, __FILE__, __LINE__, ""); \
} \
}
#define IWRC2(IW_act, IW_lvl) \
#define IWRC(IW_act, IW_rc) \
{ \
iwrc __iwrc = (IW_act); \
if (__iwrc) { \
iwlog2(IWLOG_##IW_lvl, __iwrc, __FILE__, __LINE__, ""); \
if (!(IW_rc)) \
(IW_rc) = __iwrc; \
else \
iwlog3(IWLOG_ERROR, __iwrc, __FILE__, __LINE__, ""); \
} \
}
#define IWRC2(IW_act, IW_lvl) \
{ \
iwrc __iwrc = (IW_act); \
if (__iwrc) { \
iwlog3(IWLOG_ ## IW_lvl, __iwrc, __FILE__, __LINE__, ""); \
} \
}
#define IWRC3(IW_act, IW_rc, IW_lvl) \
{ \
iwrc __iwrc = (IW_act); \
if (__iwrc) { \
if (!(IW_rc)) \
(IW_rc) = __iwrc; \
(IW_rc) = __iwrc; \
else \
iwlog2(IWLOG_##IW_lvl, __iwrc, __FILE__, __LINE__, ""); \
iwlog3(IWLOG_ ## IW_lvl, __iwrc, __FILE__, __LINE__, ""); \
} \
}
+9 -7
View File
@@ -4,7 +4,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -54,7 +54,7 @@ void iwlog_test1() {
}
void iwlog_test2() {
IWLOG_DEFAULT_OPTS opts = {0};
IWLOG_DEFAULT_OPTS opts = { 0 };
int rv = 0;
size_t sz;
char fname[] = "iwlog_test1_XXXXXX";
@@ -66,7 +66,7 @@ void iwlog_test2() {
fprintf(stderr, "Redirecting log to: %s" IW_LINE_SEP, fname);
opts.out = out;
iwlog_set_logfn_opts(&opts);
iwlog_set_logfn(0, &opts);
iwlog_info2("7fa79c75beac413d83f35ffb6bf571b9");
iwlog_error("7e94f7214af64513b30ab4df3f62714a%s", "C");
@@ -95,7 +95,8 @@ void iwlog_test2() {
"status set. (IW_ERROR_ERRNO)|"));
CU_ASSERT_PTR_NOT_NULL(strstr(buf, "ERRNO Message"));
CU_ASSERT_PTR_NOT_NULL(strstr(buf, "ERROR iwlog_test1.c:"));
CU_ASSERT_PTR_NOT_NULL(strstr(buf, "70004|0|0|Resource is readonly. (IW_ERROR_READONLY)|"));
CU_ASSERT_PTR_NOT_NULL(strstr(buf, "70005|0|0|Resource is readonly. (IW_ERROR_READONLY)|"));
CU_ASSERT_PTR_NOT_NULL(strstr(buf, "c94645c3b107433497ef295b1c00dcff12"));
fclose(out);
@@ -106,8 +107,9 @@ int main() {
CU_pSuite pSuite = NULL;
/* Initialize the CUnit test registry */
if (CUE_SUCCESS != CU_initialize_registry())
if (CUE_SUCCESS != CU_initialize_registry()) {
return CU_get_error();
}
/* Add a suite to the registry */
pSuite = CU_add_suite("iwlog_test1", init_suite, clean_suite);
@@ -118,8 +120,8 @@ int main() {
}
/* Add the tests to the suite */
if ((NULL == CU_add_test(pSuite, "iwlog_test1", iwlog_test1)) ||
(NULL == CU_add_test(pSuite, "iwlog_test2", iwlog_test2))) {
if ( (NULL == CU_add_test(pSuite, "iwlog_test1", iwlog_test1))
|| (NULL == CU_add_test(pSuite, "iwlog_test2", iwlog_test2))) {
CU_cleanup_registry();
return CU_get_error();
}
+36 -16
View File
@@ -4,7 +4,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -57,16 +57,32 @@ static unsigned int x86_simd(void) {
__cpuid(cpuid, 1);
eax = cpuid[0], ebx = cpuid[1], ecx = cpuid[2], edx = cpuid[3];
# else
__asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(1));
__asm volatile ("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (1));
# endif
if (edx >> 25 & 1) flag |= IWCPU_SSE;
if (edx >> 26 & 1) flag |= IWCPU_SSE2;
if (ecx >> 0 & 1) flag |= IWCPU_SSE3;
if (ecx >> 19 & 1) flag |= IWCPU_SSE4_1;
if (ecx >> 20 & 1) flag |= IWCPU_SSE4_2;
if (ecx >> 28 & 1) flag |= IWCPU_AVX;
if (ebx >> 5 & 1) flag |= IWCPU_AVX2;
if (ebx >> 16 & 1) flag |= IWCPU_AVX512F;
if (edx >> 25 & 1) {
flag |= IWCPU_SSE;
}
if (edx >> 26 & 1) {
flag |= IWCPU_SSE2;
}
if (ecx >> 0 & 1) {
flag |= IWCPU_SSE3;
}
if (ecx >> 19 & 1) {
flag |= IWCPU_SSE4_1;
}
if (ecx >> 20 & 1) {
flag |= IWCPU_SSE4_2;
}
if (ecx >> 28 & 1) {
flag |= IWCPU_AVX;
}
if (ebx >> 5 & 1) {
flag |= IWCPU_AVX2;
}
if (ebx >> 16 & 1) {
flag |= IWCPU_AVX512F;
}
return flag;
#else
return 0;
@@ -82,7 +98,7 @@ iwrc iwp_copy_bytes(HANDLE fh, off_t off, size_t siz, off_t noff) {
iwrc rc = 0;
off_t pos = 0;
uint8_t buf[4096];
if (overlap && noff > off) {
if (overlap && (noff > off)) {
// todo resolve it!!
return IW_ERROR_OVERFLOW;
}
@@ -115,13 +131,17 @@ iwrc iwp_copy_bytes(HANDLE fh, off_t off, size_t siz, off_t noff) {
return rc;
}
char *iwp_allocate_tmpfile_path(const char *prefix) {
char* iwp_allocate_tmpfile_path(const char *prefix) {
size_t plen = prefix ? strlen(prefix) : 0;
char tmpdir[PATH_MAX + 1];
size_t tlen = iwp_tmpdir(tmpdir, sizeof(tmpdir));
if (!tlen) return 0;
if (!tlen) {
return 0;
}
char *res = malloc(tlen + sizeof(IW_PATH_STR) - 1 + plen + IW_UUID_STR_LEN + 1 /*NULL*/);
if (!res) return 0;
if (!res) {
return 0;
}
char *wp = res;
memcpy(wp, tmpdir, tlen);
wp += tlen;
@@ -169,9 +189,9 @@ iwrc iwp_mkdirs(const char *path) {
}
}
#if (defined(_WIN32) || defined(__WIN32__))
if (_mkdir(_path) != 0) {
if (_mkdir(_path) != 0) {
#else
if (mkdir(_path, S_IRWXU) != 0) {
if (mkdir(_path, S_IRWXU) != 0) {
#endif
if (errno != EEXIST) {
return iwrc_set_errno(IW_ERROR_ERRNO, errno);
+31 -23
View File
@@ -7,7 +7,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -40,11 +40,11 @@
#include <sys/time.h>
#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 0
#define CLOCK_REALTIME 0
#endif
#ifndef CLOCK_MONOTONIC
#define CLOCK_MONOTONIC 1
#define CLOCK_MONOTONIC 1
#endif
#define IWCPU_SSE 0x1
@@ -69,20 +69,20 @@ extern unsigned int iwcpuflags;
*/
typedef enum {
_IWP_ERROR_FS_START = (IW_ERROR_START + 2000UL),
_IWP_ERROR_FS_END
_IWP_ERROR_FS_END,
} iwp_ecode;
/** File locking mode acquired by process opened this file. */
typedef uint8_t iwp_lockmode;
/** Do not acquire lock on file. */
#define IWP_NOLOCK ((iwp_lockmode) 0x00U)
#define IWP_NOLOCK ((iwp_lockmode) 0x00U)
/** Acquire read lock on file. */
#define IWP_RLOCK ((iwp_lockmode) 0x01U)
#define IWP_RLOCK ((iwp_lockmode) 0x01U)
/** Acquire write lock on file. */
#define IWP_WLOCK ((iwp_lockmode) 0x02U)
#define IWP_WLOCK ((iwp_lockmode) 0x02U)
/** Do not block current thread if file have been locked by another process.
* In this case error will be raised. */
#define IWP_NBLOCK ((iwp_lockmode) 0x04U)
#define IWP_NBLOCK ((iwp_lockmode) 0x04U)
/**
* @enum iwp_file_type
@@ -92,19 +92,19 @@ typedef enum {
IWP_TYPE_FILE, /**< Ordinary file. */
IWP_TYPE_DIR, /**< Directory. */
IWP_LINK, /**< Symlink. */
IWP_OTHER /**< Other file types, eg soc, block, pipe.. */
IWP_OTHER, /**< Other file types, eg soc, block, pipe.. */
} iwp_file_type;
typedef enum {
IWP_SEEK_SET = 1,
IWP_SEEK_CUR,
IWP_SEEK_END
IWP_SEEK_END,
} iwp_seek_origin;
/**
* Portable version of `int clock_gettime(clockid_t clk_id, struct timespec *tp)`
*/
IW_EXPORT iwrc iwp_clock_get_time(int clock_id, struct timespec* t);
IW_EXPORT iwrc iwp_clock_get_time(int clock_id, struct timespec *t);
/**
* @brief Get current time in milliseconds.
@@ -118,10 +118,10 @@ IW_EXPORT iwrc iwp_current_time_ms(uint64_t *time, bool monotonic);
* @brief File info.
*/
typedef struct IWP_FILE_STAT {
uint64_t size; /**< File size. */
uint64_t atime; /**< Time of last access. */
uint64_t ctime; /**< Time of last status change. */
uint64_t mtime; /**< Time of last modification. */
uint64_t size; /**< File size. */
uint64_t atime; /**< Time of last access. */
uint64_t ctime; /**< Time of last status change. */
uint64_t mtime; /**< Time of last modification. */
iwp_file_type ftype; /**< File type. */
} IWP_FILE_STAT;
@@ -192,14 +192,16 @@ IW_EXPORT iwrc iwp_read(HANDLE fh, void *buf, size_t count, size_t *sp);
IW_EXPORT iwrc iwp_lseek(HANDLE fh, off_t offset, iwp_seek_origin origin, off_t *pos);
/**
* @brief Copy data within a file
* @param off Data offset
* @param siz Data size
* @param noff New data offset
*/
IW_EXPORT iwrc iwp_copy_bytes(HANDLE fh,
off_t off, size_t siz,
off_t noff);
* @brief Copy data within a file
* @param off Data offset
* @param siz Data size
* @param noff New data offset
*/
IW_EXPORT iwrc iwp_copy_bytes(
HANDLE fh,
off_t off, size_t siz,
off_t noff);
/**
* @brief Get system page size.
*/
@@ -284,4 +286,10 @@ IW_EXPORT size_t iwp_tmpdir(char *out, size_t len);
*/
IW_EXPORT char* iwp_allocate_tmpfile_path(const char *prefix);
/**
* Set name of the current thread. On some platforms
* thread name canot be longer than 16 bytes including zero terminator.
*/
IW_EXPORT void iwp_set_current_thread_name(const char *name);
#endif
+72 -78
View File
@@ -4,7 +4,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -37,7 +37,13 @@
#include <unistd.h>
#include <fcntl.h>
#include <ftw.h>
#include <pthread.h>
#if defined(__linux__)
#include <sys/prctl.h>
#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
#include <pthread_np.h>
#endif
#ifdef __APPLE__
#define st_atim st_atimespec
@@ -47,7 +53,6 @@
#define _IW_TIMESPEC2MS(IW_ts) (((IW_ts).tv_sec * 1000ULL) + (uint64_t) round((IW_ts).tv_nsec / 1.0e6))
IW_EXPORT iwrc iwp_clock_get_time(int clock_id, struct timespec *t) {
#if (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED < 101200)
struct timeval now;
@@ -55,7 +60,7 @@ IW_EXPORT iwrc iwp_clock_get_time(int clock_id, struct timespec *t) {
if (rci) {
return iwrc_set_errno(IW_ERROR_ERRNO, errno);
}
t->tv_sec = now.tv_sec;
t->tv_sec = now.tv_sec;
t->tv_nsec = now.tv_usec * 1000ULL;
#else
int rci = clock_gettime(clock_id, t);
@@ -84,7 +89,7 @@ iwrc iwp_current_time_ms(uint64_t *time, bool monotonic) {
static iwrc _iwp_fstat(const char *path, HANDLE fd, IWP_FILE_STAT *fs) {
assert(fs);
iwrc rc = 0;
struct stat st = {0};
struct stat st = { 0 };
memset(fs, 0, sizeof(*fs));
if (path) {
if (stat(path, &st)) {
@@ -127,7 +132,7 @@ iwrc iwp_flock(HANDLE fh, iwp_lockmode lmode) {
if (lmode == IWP_NOLOCK) {
return 0;
}
struct flock lock = {.l_type = (lmode & IWP_WLOCK) ? F_WRLCK : F_RDLCK, .l_whence = SEEK_SET};
struct flock lock = { .l_type = (lmode & IWP_WLOCK) ? F_WRLCK : F_RDLCK, .l_whence = SEEK_SET };
while (fcntl(fh, (lmode & IWP_NBLOCK) ? F_SETLK : F_SETLKW, &lock) == -1) {
if (errno != EINTR) {
return iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
@@ -140,7 +145,7 @@ iwrc iwp_unlock(HANDLE fh) {
if (INVALIDHANDLE(fh)) {
return IW_ERROR_INVALID_HANDLE;
}
struct flock lock = {.l_type = F_UNLCK, .l_whence = SEEK_SET};
struct flock lock = { .l_type = F_UNLCK, .l_whence = SEEK_SET };
while (fcntl(fh, F_SETLKW, &lock) == -1) {
if (errno != EINTR) {
return iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
@@ -160,90 +165,73 @@ iwrc iwp_closefh(HANDLE fh) {
}
iwrc iwp_pread(HANDLE fh, off_t off, void *buf, size_t siz, size_t *sp) {
if (INVALIDHANDLE(fh)) {
return IW_ERROR_INVALID_HANDLE;
}
if (!buf || !sp) {
return IW_ERROR_INVALID_ARGS;
}
ssize_t rs;
ssize_t rci;
again:
rs = pread(fh, buf, siz, off);
if (rs == -1) {
rci = pread(fh, buf, siz, off);
if (rci < 0) {
*sp = 0;
if (errno == EINTR) {
goto again;
} else if (errno == EWOULDBLOCK || errno == IW_ERROR_AGAIN) {
return IW_ERROR_AGAIN;
}
*sp = 0;
return iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
} else {
*sp = rs;
return 0;
}
*sp = rci;
return 0;
}
iwrc iwp_read(HANDLE fh, void *buf, size_t count, size_t *sp) {
if (INVALIDHANDLE(fh)) {
return IW_ERROR_INVALID_HANDLE;
}
if (!buf || !sp) {
return IW_ERROR_INVALID_ARGS;
}
ssize_t rs;
again:
rs = read(fh, buf, count);
if (rs == -1) {
if (rs < 0) {
*sp = 0;
if (errno == EINTR) {
goto again;
} else if (errno == EWOULDBLOCK || errno == EAGAIN) {
return IW_ERROR_AGAIN;
}
*sp = 0;
return iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
} else {
*sp = rs;
return 0;
}
*sp = rs;
return 0;
}
iwrc iwp_pwrite(HANDLE fh, off_t off, const void *buf, size_t siz, size_t *sp) {
if (INVALIDHANDLE(fh)) {
return IW_ERROR_INVALID_HANDLE;
}
if (!buf || !sp) {
return IW_ERROR_INVALID_ARGS;
}
ssize_t ws;
again:
ws = pwrite(fh, buf, siz, off);
if (ws == -1) {
if (ws < 0) {
*sp = 0;
if (errno == EINTR) {
goto again;
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
return IW_ERROR_AGAIN;
}
*sp = 0;
return iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
} else {
*sp = ws;
return 0;
}
*sp = ws;
return 0;
}
iwrc iwp_write(HANDLE fh, const void *buf, size_t size) {
if (INVALIDHANDLE(fh)) {
return IW_ERROR_INVALID_HANDLE;
}
const char *rp = buf;
do {
ssize_t wb = write(fh, rp, size);
switch (wb) {
case -1:
if (errno == EINTR) {
continue;
}
return iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
case 0:
break;
default:
rp += wb;
size -= wb;
break;
if (wb < 0) {
if (errno == EINTR) {
continue;
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
return IW_ERROR_AGAIN;
}
return iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
} else {
rp += wb;
size -= wb;
}
} while (size > 0);
return 0;
@@ -291,19 +279,16 @@ iwrc iwp_ftruncate(HANDLE fh, off_t len) {
}
iwrc iwp_fallocate(HANDLE fh, off_t len) {
#ifndef __APPLE__
int rci = posix_fallocate(fh, 0, len);
return !rci ? 0 : iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
#else
#if defined(__APPLE__)
fstore_t fstore = {
.fst_flags = F_ALLOCATECONTIG,
.fst_flags = F_ALLOCATECONTIG,
.fst_posmode = F_PEOFPOSMODE,
.fst_length = len
.fst_length = len
};
fcntl(fh, F_PREALLOCATE, &fstore);
#endif
int rci = ftruncate(fh, len);
return !rci ? 0 : iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
#endif
}
iwrc iwp_sleep(uint64_t ms) {
@@ -354,7 +339,7 @@ iwrc iwp_exec_path(char *opath) {
uint16_t iwp_num_cpu_cores() {
long res = sysconf(_SC_NPROCESSORS_ONLN);
return (uint16_t)(res > 0 ? res : 1);
return (uint16_t) (res > 0 ? res : 1);
}
iwrc iwp_fsync(HANDLE fh) {
@@ -376,25 +361,34 @@ iwrc iwp_fdatasync(HANDLE fh) {
}
size_t iwp_tmpdir(char *out, size_t len) {
const char *tdir;
#ifdef IW_TMPDIR
tdir = IW_TMPDIR;
#else
tdir = getenv("TMPDIR");
if (!tdir) {
#ifdef P_tmpdir
tdir = P_tmpdir;
#else
tdir = "/tmp";
#endif
}
#endif
size_t tlen = strlen(tdir);
const char *tdir = P_tmpdir;
size_t tlen = strlen(P_tmpdir);
size_t nw = MIN(len, tlen);
memcpy(out, tdir, nw);
return nw;
}
void iwp_set_current_thread_name(const char *name) {
#if (defined(__APPLE__) && defined(__MACH__)) || defined(__linux__)
// On linux and OS X the name may not be longer than 16 bytes, including
// the null terminator. Truncate the name to 15 characters.
char buf[16];
strncpy(buf, name, sizeof(buf) - 1);
buf[sizeof(buf) - 1] = '\0';
name = buf;
#endif
#if defined(__linux__)
prctl(PR_SET_NAME, name);
#elif defined(__NetBSD__)
rv = pthread_setname_np(pthread_self(), "%s", (void*) name);
#elif defined(__APPLE__)
pthread_setname_np(name);
#else
pthread_setname_np(pthread_self(), name);
#endif
}
static iwrc _iwp_init_impl() {
iwp_page_size(); // init statics
return 0;
+24 -24
View File
@@ -6,7 +6,7 @@
#include <io.h>
#ifndef FILE_MAP_EXECUTE
#define FILE_MAP_EXECUTE 0x0020
#define FILE_MAP_EXECUTE 0x0020
#endif /* FILE_MAP_EXECUTE */
static int __map_mman_error(const DWORD err, const int deferr) {
@@ -36,7 +36,7 @@ static DWORD __map_mmap_prot_file(const int prot, const int flags) {
DWORD desiredAccess = 0;
if (prot == PROT_NONE) {
return desiredAccess;
}
}
if ((prot & PROT_WRITE)) {
if (flags & MAP_PRIVATE) {
desiredAccess |= FILE_MAP_COPY;
@@ -55,34 +55,34 @@ static DWORD __map_mmap_prot_file(const int prot, const int flags) {
void *mmap(void *addr, size_t len, int prot, int flags, HANDLE fh, OffsetType off) {
HANDLE fm;
void *map = MAP_FAILED;
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4293)
#endif
const DWORD dwFileOffsetLow = (sizeof(OffsetType) <= sizeof(DWORD)) ?
(DWORD)off : (DWORD)(off & 0xFFFFFFFFL);
const DWORD dwFileOffsetHigh = (sizeof(OffsetType) <= sizeof(DWORD)) ?
(DWORD)0 : (DWORD)((off >> 32) & 0xFFFFFFFFL);
const DWORD dwFileOffsetLow = (sizeof(OffsetType) <= sizeof(DWORD))
? (DWORD) off : (DWORD) (off & 0xFFFFFFFFL);
const DWORD dwFileOffsetHigh = (sizeof(OffsetType) <= sizeof(DWORD))
? (DWORD) 0 : (DWORD) ((off >> 32) & 0xFFFFFFFFL);
const DWORD protect = __map_mmap_prot_page(prot, flags);
const DWORD desiredAccess = __map_mmap_prot_file(prot, flags);
const OffsetType maxSize = off + (OffsetType)len;
const DWORD dwMaxSizeLow = (sizeof(OffsetType) <= sizeof(DWORD)) ?
(DWORD)maxSize : (DWORD)(maxSize & 0xFFFFFFFFL);
const DWORD dwMaxSizeHigh = (sizeof(OffsetType) <= sizeof(DWORD)) ?
(DWORD)0 : (DWORD)((maxSize >> 32) & 0xFFFFFFFFL);
const OffsetType maxSize = off + (OffsetType) len;
const DWORD dwMaxSizeLow = (sizeof(OffsetType) <= sizeof(DWORD))
? (DWORD) maxSize : (DWORD) (maxSize & 0xFFFFFFFFL);
const DWORD dwMaxSizeHigh = (sizeof(OffsetType) <= sizeof(DWORD))
? (DWORD) 0 : (DWORD) ((maxSize >> 32) & 0xFFFFFFFFL);
#ifdef _MSC_VER
#pragma warning(pop)
#endif
errno = 0;
if ((flags & MAP_FIXED) != 0 || prot == PROT_EXEC) {
errno = EINVAL;
if (((flags & MAP_FIXED) != 0) || (prot == PROT_EXEC)) {
errno = EINVAL;
return MAP_FAILED;
}
if (!(flags & MAP_ANONYMOUS) && fh == INVALID_HANDLE_VALUE) {
if (!(flags & MAP_ANONYMOUS) && (fh == INVALID_HANDLE_VALUE)) {
errno = EBADF;
return MAP_FAILED;
}
@@ -104,7 +104,7 @@ int munmap(void *addr, size_t len) {
if (UnmapViewOfFile(addr)) {
return 0;
}
errno = __map_mman_error(GetLastError(), EPERM);
errno = __map_mman_error(GetLastError(), EPERM);
return -1;
}
@@ -112,22 +112,22 @@ int msync(void *addr, size_t len, int flags) {
if (FlushViewOfFile(addr, len)) {
return 0;
}
errno = __map_mman_error(GetLastError(), EPERM);
errno = __map_mman_error(GetLastError(), EPERM);
return -1;
}
int mlock(const void *addr, size_t len) {
if (VirtualLock((LPVOID)addr, len)) {
if (VirtualLock((LPVOID) addr, len)) {
return 0;
}
errno = __map_mman_error(GetLastError(), EPERM);
errno = __map_mman_error(GetLastError(), EPERM);
return -1;
}
int munlock(const void *addr, size_t len) {
if (VirtualUnlock((LPVOID)addr, len)) {
if (VirtualUnlock((LPVOID) addr, len)) {
return 0;
}
errno = __map_mman_error(GetLastError(), EPERM);
errno = __map_mman_error(GetLastError(), EPERM);
return -1;
}
+21 -21
View File
@@ -10,7 +10,7 @@
#include "basedefs.h"
#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later.
#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later.
#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows.
#endif
@@ -39,31 +39,31 @@ typedef uint32_t OffsetType;
extern "C" {
#endif
#define PROT_NONE 0
#define PROT_READ 1
#define PROT_WRITE 2
#define PROT_EXEC 4
#define PROT_NONE 0
#define PROT_READ 1
#define PROT_WRITE 2
#define PROT_EXEC 4
#define MAP_FILE 0
#define MAP_SHARED 1
#define MAP_PRIVATE 2
#define MAP_TYPE 0xf
#define MAP_FIXED 0x10
#define MAP_ANONYMOUS 0x20
#define MAP_ANON MAP_ANONYMOUS
#define MAP_FILE 0
#define MAP_SHARED 1
#define MAP_PRIVATE 2
#define MAP_TYPE 0xf
#define MAP_FIXED 0x10
#define MAP_ANONYMOUS 0x20
#define MAP_ANON MAP_ANONYMOUS
#define MAP_FAILED ((void *)-1)
#define MAP_FAILED ((void*) -1)
/* Flags for msync. */
#define MS_ASYNC 1
#define MS_SYNC 2
#define MS_INVALIDATE 4
#define MS_ASYNC 1
#define MS_SYNC 2
#define MS_INVALIDATE 4
void *mmap(void *addr, size_t len, int prot, int flags, HANDLE fh, OffsetType off);
int munmap(void *addr, size_t len);
int msync(void *addr, size_t len, int flags);
int mlock(const void *addr, size_t len);
int munlock(const void *addr, size_t len);
void *mmap(void *addr, size_t len, int prot, int flags, HANDLE fh, OffsetType off);
int munmap(void *addr, size_t len);
int msync(void *addr, size_t len, int flags);
int mlock(const void *addr, size_t len);
int munlock(const void *addr, size_t len);
#ifdef __cplusplus
}
+26 -16
View File
@@ -3,14 +3,16 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>
#include "iwcfg.h"
#define _NANOSECONDS_PER_TICK 100ULL
#define _NANOSECONDS_PER_SECOND 1000000000ULL
#define _TICKS_PER_SECOND 10000000ULL
#define _TICKS_PER_MILLISECOND 10000ULL
#define _SEC_TO_UNIX_EPOCH 11644473600ULL
#define _TICKS_TO_UNIX_EPOCH (_TICKS_PER_SECOND * _SEC_TO_UNIX_EPOCH)
#define _NANOSECONDS_PER_TICK 100ULL
#define _NANOSECONDS_PER_SECOND 1000000000ULL
#define _TICKS_PER_SECOND 10000000ULL
#define _TICKS_PER_MILLISECOND 10000ULL
#define _SEC_TO_UNIX_EPOCH 11644473600ULL
#define _TICKS_TO_UNIX_EPOCH (_TICKS_PER_SECOND * _SEC_TO_UNIX_EPOCH)
#define _TIMESPEC2MS(IW_ts) ((IW_ts).tv_sec * 1000) + (uint64_t) round((IW_ts).tv_nsec / 1.0e6)
IW_INLINE uint64_t _iwp_filetime2ticks(const FILETIME *ft) {
@@ -33,7 +35,7 @@ IW_INLINE uint64_t _iwp_filetime2millisecons(const FILETIME *ft) {
return ticks / _TICKS_PER_MILLISECOND;
}
iwrc iwp_clock_get_time(int clock_id, struct timespec* spec) {
iwrc iwp_clock_get_time(int clock_id, struct timespec *spec) {
int rci = clock_gettime(clock_id, spec);
if (rci) {
return iwrc_set_errno(IW_ERROR_ERRNO, errno);
@@ -109,7 +111,7 @@ iwrc iwp_sleep(uint64_t ms) {
iwrc iwp_fstat(const char *path, IWP_FILE_STAT *fs) {
memset(fs, 0, sizeof(*fs));
struct stat st = {0};
struct stat st = { 0 };
if (stat(path, &st)) {
return (errno == ENOENT) ? IW_ERROR_NOT_EXISTS : iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
}
@@ -135,7 +137,7 @@ iwrc iwp_fstath(HANDLE fh, IWP_FILE_STAT *fs) {
}
if (!GetFileInformationByHandle(fh, &info)) {
uint32_t err = GetLastError();
if (err == ERROR_FILE_NOT_FOUND) {
if (err == ERROR_FILE_NOT_FOUND) {
return IW_ERROR_NOT_EXISTS;
}
return iwrc_set_werror(IW_ERROR_IO_ERRNO, GetLastError());
@@ -144,7 +146,7 @@ iwrc iwp_fstath(HANDLE fh, IWP_FILE_STAT *fs) {
fs->ctime = _iwp_filetime2millisecons(&info.ftCreationTime);
fs->mtime = _iwp_filetime2millisecons(&info.ftLastWriteTime);
ULARGE_INTEGER ul = {
.LowPart = info.nFileSizeLow,
.LowPart = info.nFileSizeLow,
.HighPart = info.nFileSizeHigh
};
fs->size = ul.QuadPart;
@@ -174,9 +176,13 @@ iwrc iwp_flock(HANDLE fh, iwp_lockmode lmode) {
return 0;
}
DWORD type = 0; /* shared lock with waiting */
OVERLAPPED offset = {0};
if (lmode & IWP_WLOCK) type = LOCKFILE_EXCLUSIVE_LOCK;
if (lmode & IWP_NBLOCK) type |= LOCKFILE_FAIL_IMMEDIATELY;
OVERLAPPED offset = { 0 };
if (lmode & IWP_WLOCK) {
type = LOCKFILE_EXCLUSIVE_LOCK;
}
if (lmode & IWP_NBLOCK) {
type |= LOCKFILE_FAIL_IMMEDIATELY;
}
if (!LockFileEx(fh, type, 0, ULONG_MAX, ULONG_MAX, &offset)) {
return iwrc_set_werror(IW_ERROR_ERRNO, GetLastError());
}
@@ -187,7 +193,7 @@ iwrc iwp_unlock(HANDLE fh) {
if (INVALIDHANDLE(fh)) {
return IW_ERROR_INVALID_HANDLE;
}
OVERLAPPED offset = {0};
OVERLAPPED offset = { 0 };
if (!UnlockFileEx(fh, 0, ULONG_MAX, ULONG_MAX, &offset)) {
return iwrc_set_werror(IW_ERROR_ERRNO, GetLastError());
} else {
@@ -204,7 +210,7 @@ iwrc iwp_pread(HANDLE fh, off_t off, void *buf, size_t siz, size_t *sp) {
}
DWORD rdb;
ULARGE_INTEGER bigint;
OVERLAPPED offset = {0};
OVERLAPPED offset = { 0 };
bigint.QuadPart = off;
offset.Offset = bigint.LowPart;
offset.OffsetHigh = bigint.HighPart;
@@ -251,7 +257,7 @@ iwrc iwp_pwrite(HANDLE fh, off_t off, const void *buf, size_t siz, size_t *sp) {
}
DWORD wrb;
ULARGE_INTEGER bigint;
OVERLAPPED offset = {0};
OVERLAPPED offset = { 0 };
bigint.QuadPart = off;
offset.Offset = bigint.LowPart;
offset.OffsetHigh = bigint.HighPart;
@@ -300,6 +306,10 @@ iwrc iwp_lseek(HANDLE fh, off_t offset, iwp_seek_origin origin, off_t *pos) {
return 0;
}
void iwp_set_current_thread_name(const char *name) {
pthread_setname_np(pthread_self(), name);
}
size_t iwp_tmpdir(char *out, size_t len) {
return GetTempPathA(len, out);
}
+26 -16
View File
@@ -7,6 +7,10 @@
#include <fcntl.h>
#include <pthread.h>
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif
#include "iwcfg.h"
#define _ENSURE_OPEN(db_) \
@@ -14,13 +18,13 @@
struct _IWRDB {
HANDLE fh;
iwrdb_oflags_t oflags;
iwrdb_oflags_t oflags;
pthread_rwlock_t *cwl;
char *path;
char *path;
uint8_t *buf;
size_t bufsz;
off_t bp;
off_t end;
size_t bufsz;
off_t bp;
off_t end;
};
IW_INLINE iwrc _wlock(IWRDB db) {
@@ -91,13 +95,13 @@ static iwrc _append_lw(IWRDB db, const void *data, int len, uint64_t *oref) {
iwrc rc = 0;
*oref = 0;
if (db->bufsz && db->bp + len > db->bufsz) {
if (db->bufsz && (db->bp + len > db->bufsz)) {
rc = _flush_lw(db);
if (rc) {
return rc;
}
}
if (!db->bufsz || db->bp + len > db->bufsz) {
if (!db->bufsz || (db->bp + len > db->bufsz)) {
*oref = db->end + 1;
rc = iwp_write(db->fh, data, len);
RCRET(rc);
@@ -108,7 +112,7 @@ static iwrc _append_lw(IWRDB db, const void *data, int len, uint64_t *oref) {
db->bp += len;
assert(db->bp <= db->bufsz);
}
if (db->bufsz && db->bp == db->bufsz) {
if (db->bufsz && (db->bp == db->bufsz)) {
return _flush_lw(db);
}
return rc;
@@ -121,7 +125,7 @@ iwrc iwrdb_open(const char *path, iwrdb_oflags_t oflags, size_t bufsz, IWRDB *od
*odb = 0;
#ifndef _WIN32
HANDLE fh = open(path, O_CREAT | O_RDWR, IWFS_DEFAULT_FILEMODE);
HANDLE fh = open(path, O_CREAT | O_RDWR | O_CLOEXEC, IWFS_DEFAULT_FILEMODE);
if (INVALIDHANDLE(fh)) {
return iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
}
@@ -200,7 +204,9 @@ iwrc iwrdb_close(IWRDB *rdb) {
iwrc iwrdb_append(IWRDB db, const void *data, int len, uint64_t *oref) {
_ENSURE_OPEN(db);
iwrc rc = _wlock(db);
if (rc) return rc;
if (rc) {
return rc;
}
rc = _append_lw(db, data, len, oref);
IWRC(_unlock(db), rc);
return rc;
@@ -211,15 +217,17 @@ iwrc iwrdb_patch(IWRDB db, uint64_t ref, off_t skip, const void *data, int len)
size_t sz;
ssize_t sz2;
ssize_t tw = len;
uint8_t *rp = (uint8_t *) data;
uint8_t *rp = (uint8_t*) data;
ssize_t off = ref - 1 + skip;
_ENSURE_OPEN(db);
if (!ref || off < 0 || skip < 0) {
if (!ref || (off < 0) || (skip < 0)) {
return IW_ERROR_INVALID_ARGS;
}
rc = _wlock(db);
if (rc) return rc;
if (rc) {
return rc;
}
if (off + len > db->end + db->bp) {
rc = IW_ERROR_OUT_OF_BOUNDS;
goto finish;
@@ -251,11 +259,13 @@ iwrc iwrdb_read(IWRDB db, uint64_t ref, off_t skip, void *buf, int len, size_t *
*sp = 0;
_ENSURE_OPEN(db);
if (!ref || skip < 0 || len < 0) {
if (!ref || (skip < 0) || (len < 0)) {
return IW_ERROR_INVALID_ARGS;
}
rc = _rlock(db);
if (rc) return rc;
if (rc) {
return rc;
}
if (off + len > db->end + db->bp) {
off_t l = db->end + db->bp - off;
if (l < 0) {
@@ -271,7 +281,7 @@ iwrc iwrdb_read(IWRDB db, uint64_t ref, off_t skip, void *buf, int len, size_t *
wp += sz;
off += sz;
}
if (tr > 0 && db->bp > 0) {
if ((tr > 0) && (db->bp > 0)) {
sz = off - db->end;
memcpy(wp, db->buf + sz, tr);
}
+1 -2
View File
@@ -10,7 +10,7 @@ IW_EXTERN_C_START
typedef uint8_t iwrdb_oflags_t;
#define IWRDB_NOLOCKS ((iwrdb_oflags_t) 0x01U)
typedef struct _IWRDB *IWRDB;
typedef struct _IWRDB*IWRDB;
IW_EXPORT iwrc iwrdb_open(const char *path, iwrdb_oflags_t oflags, size_t bufsz, IWRDB *db);
@@ -26,4 +26,3 @@ IW_EXPORT iwrc iwrdb_read(IWRDB db, uint64_t ref, off_t skip, void *buf, int len
IW_EXTERN_C_END
#endif
+3 -3
View File
@@ -8,7 +8,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -33,7 +33,7 @@
#include "basedefs.h"
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
#define STR(x) STR_HELPER(x)
#include <stddef.h>
#include <stdint.h>
@@ -56,7 +56,7 @@
#error Unknown CPU bits
#endif
#define IOWOW_VERSION "@iowow_VERSION@"
#define IOWOW_VERSION "@iowow_VERSION@"
#define IOWOW_VERSION_MAJOR @iowow_VERSION_MAJOR@
#define IOWOW_VERSION_MINOR @iowow_VERSION_MINOR@
#define IOWOW_VERSION_PATCH @iowow_VERSION_PATCH@
+1
View File
@@ -8,4 +8,5 @@ Description: @PROJECT_DESCRIPTION_SUMMARY@
URL: @PROJECT_WEBSITE@
Version: @PROJECT_VERSION@
Libs: -L${libdir} -l@PROJECT_NAME@
Libs.private: -lm
Cflags: -I${includedir}
+65 -41
View File
@@ -5,13 +5,15 @@
#include <stdlib.h>
#include <errno.h>
#include "iwlog.h"
#include "sort_r.h"
off_t iwarr_sorted_insert(void *restrict els,
size_t nels,
size_t elsize,
void *restrict eptr,
int (*cmp)(const void *, const void *),
bool skipeq) {
off_t iwarr_sorted_insert(
void* restrict els,
size_t nels,
size_t elsize,
void* restrict eptr,
int (*cmp)(const void*, const void*),
bool skipeq) {
#define EL(idx_) (elsptr + (idx_) * elsize)
@@ -51,11 +53,12 @@ off_t iwarr_sorted_insert(void *restrict els,
#undef EL
}
off_t iwarr_sorted_remove(void *restrict els,
size_t nels,
size_t elsize,
void *restrict eptr,
int (*cmp)(const void *, const void *)) {
off_t iwarr_sorted_remove(
void* restrict els,
size_t nels,
size_t elsize,
void* restrict eptr,
int (*cmp)(const void*, const void*)) {
#define EL(idx_) (elsptr + (idx_) * elsize)
@@ -91,11 +94,12 @@ off_t iwarr_sorted_remove(void *restrict els,
#undef EL
}
off_t iwarr_sorted_find(void *restrict els,
size_t nels,
size_t elsize,
void *restrict eptr,
int (*cmp)(const void *, const void *)) {
off_t iwarr_sorted_find(
void* restrict els,
size_t nels,
size_t elsize,
void* restrict eptr,
int (*cmp)(const void*, const void*)) {
#define EL(idx_) (elsptr + (idx_) * elsize)
@@ -128,13 +132,14 @@ off_t iwarr_sorted_find(void *restrict els,
#undef EL
}
off_t iwarr_sorted_find2(void *restrict els,
size_t nels,
size_t elsize,
void *restrict eptr,
void *op,
bool *found,
iwrc(*cmp)(const void *, const void *, void *, int *res)) {
off_t iwarr_sorted_find2(
void* restrict els,
size_t nels,
size_t elsize,
void* restrict eptr,
void *op,
bool *found,
iwrc (*cmp)(const void*, const void*, void*, int *res)) {
#define EL(idx_) (elsptr + (idx_) * elsize)
@@ -192,7 +197,7 @@ iwrc iwulist_init(IWULIST *list, size_t initial_length, size_t unit_size) {
return 0;
}
IWULIST *iwulist_create(size_t initial_length, size_t unit_size) {
IWULIST* iwulist_create(size_t initial_length, size_t unit_size) {
IWULIST *list = malloc(sizeof(*list));
if (!list) {
return 0;
@@ -233,7 +238,7 @@ size_t iwulist_length(IWULIST *list) {
return list->num;
}
IWULIST *iwulist_clone(IWULIST *list) {
IWULIST* iwulist_clone(IWULIST *list) {
if (!list->num) {
return iwulist_create(list->anum, list->usize);
}
@@ -255,7 +260,7 @@ IWULIST *iwulist_clone(IWULIST *list) {
return nlist;
}
void *iwulist_at(IWULIST *list, size_t index, iwrc *orc) {
void* iwulist_at(IWULIST *list, size_t index, iwrc *orc) {
*orc = 0;
if (index >= list->num) {
*orc = IW_ERROR_OUT_OF_BOUNDS;
@@ -265,7 +270,7 @@ void *iwulist_at(IWULIST *list, size_t index, iwrc *orc) {
return list->array + index * list->usize;
}
void *iwulist_at2(IWULIST *list, size_t index) {
void* iwulist_at2(IWULIST *list, size_t index) {
if (index >= list->num) {
return 0;
}
@@ -294,9 +299,9 @@ iwrc iwulist_pop(IWULIST *list) {
return IW_ERROR_OUT_OF_BOUNDS;
}
size_t num = list->num - 1;
if (list->anum > IWULIST_ALLOC_UNIT && list->anum >= num * 2) {
if ((list->anum > IWULIST_ALLOC_UNIT) && (list->anum >= num * 2)) {
if (list->start) {
memcpy(list->array, list->array + list->start * list->usize, num * list->usize);
memmove(list->array, list->array + list->start * list->usize, num * list->usize);
list->start = 0;
}
size_t anum = num > IWULIST_ALLOC_UNIT ? num : IWULIST_ALLOC_UNIT;
@@ -317,9 +322,9 @@ iwrc iwulist_shift(IWULIST *list) {
}
size_t num = list->num - 1;
size_t start = list->start + 1;
if (list->anum > IWULIST_ALLOC_UNIT && list->anum >= num * 2) {
if ((list->anum > IWULIST_ALLOC_UNIT) && (list->anum >= num * 2)) {
if (start) {
memcpy(list->array, list->array + start * list->usize, num * list->usize);
memmove(list->array, list->array + start * list->usize, num * list->usize);
start = 0;
}
size_t anum = num > IWULIST_ALLOC_UNIT ? num : IWULIST_ALLOC_UNIT;
@@ -374,9 +379,9 @@ iwrc iwulist_remove(IWULIST *list, size_t index) {
--list->num;
memmove(list->array + index * list->usize, list->array + (index + 1) * list->usize,
(list->start + list->num - index) * list->usize);
if (list->anum > IWULIST_ALLOC_UNIT && list->anum >= list->num * 2) {
if ((list->anum > IWULIST_ALLOC_UNIT) && (list->anum >= list->num * 2)) {
if (list->start) {
memcpy(list->array, list->array + list->start * list->usize, list->num * list->usize);
memmove(list->array, list->array + list->start * list->usize, list->num * list->usize);
list->start = 0;
}
size_t anum = list->num > IWULIST_ALLOC_UNIT ? list->num : IWULIST_ALLOC_UNIT;
@@ -410,6 +415,10 @@ iwrc iwulist_unshift(IWULIST *list, const void *data) {
return 0;
}
void iwulist_sort(IWULIST *list, int (*compar)(const void*, const void*, void*), void *op) {
sort_r(list->array + list->start * list->usize, list->num, list->usize, compar, op);
}
///////////////////////////////////////////////////////////////////////////
// Array list implementation //
///////////////////////////////////////////////////////////////////////////
@@ -428,7 +437,7 @@ iwrc iwlist_init(IWLIST *list, size_t anum) {
return 0;
}
IWLIST *iwlist_create(size_t anum) {
IWLIST* iwlist_create(size_t anum) {
IWLIST *list = malloc(sizeof(*list));
if (!list) {
return 0;
@@ -471,7 +480,7 @@ size_t iwlist_length(IWLIST *list) {
return list->num;
}
IWLIST *iwlist_clone(IWLIST *list) {
IWLIST* iwlist_clone(IWLIST *list) {
size_t num = list->num;
if (!num) {
return iwlist_create(0);
@@ -503,7 +512,7 @@ IWLIST *iwlist_clone(IWLIST *list) {
return nlist;
}
void *iwlist_at(IWLIST *list, size_t index, size_t *osize, iwrc *orc) {
void* iwlist_at(IWLIST *list, size_t index, size_t *osize, iwrc *orc) {
*orc = 0;
if (index >= list->num) {
*orc = IW_ERROR_OUT_OF_BOUNDS;
@@ -516,6 +525,17 @@ void *iwlist_at(IWLIST *list, size_t index, size_t *osize, iwrc *orc) {
return list->array[index].val;
}
void* iwlist_at2(IWLIST *list, size_t index, size_t *osize) {
if (index >= list->num) {
return 0;
}
index += list->start;
if (osize) {
*osize = list->array[index].size;
}
return list->array[index].val;
}
iwrc iwlist_push(IWLIST *list, const void *data, size_t data_size) {
size_t index = list->start + list->num;
if (index >= list->anum) {
@@ -539,7 +559,7 @@ iwrc iwlist_push(IWLIST *list, const void *data, size_t data_size) {
return 0;
}
void *iwlist_pop(IWLIST *list, size_t *osize, iwrc *orc) {
void* iwlist_pop(IWLIST *list, size_t *osize, iwrc *orc) {
*orc = 0;
if (!list->num) {
*orc = IW_ERROR_OUT_OF_BOUNDS;
@@ -577,7 +597,7 @@ iwrc iwlist_unshift(IWLIST *list, const void *data, size_t data_size) {
return 0;
}
void *iwlist_shift(IWLIST *list, size_t *osize, iwrc *orc) {
void* iwlist_shift(IWLIST *list, size_t *osize, iwrc *orc) {
*orc = 0;
if (!list->num) {
*orc = IW_ERROR_OUT_OF_BOUNDS;
@@ -588,7 +608,7 @@ void *iwlist_shift(IWLIST *list, size_t *osize, iwrc *orc) {
--list->num;
*osize = list->array[index].size;
void *rv = list->array[index].val;
if (!(list->start & 0xff) && list->start > list->num / 2) {
if (!(list->start & 0xff) && (list->start > list->num / 2)) {
memmove(list->array, list->array + list->start, list->num * sizeof(list->array[0]));
list->start = 0;
}
@@ -619,7 +639,7 @@ iwrc iwlist_insert(IWLIST *list, size_t index, const void *data, size_t data_siz
return 0;
}
iwrc iwlist_set(IWLIST *list, size_t index, const void *data, size_t data_size) {
iwrc iwlist_set(IWLIST *list, size_t index, const void *data, size_t data_size) {
if (index >= list->num) {
return IW_ERROR_OUT_OF_BOUNDS;
}
@@ -637,7 +657,7 @@ iwrc iwlist_set(IWLIST *list, size_t index, const void *data, size_t data_size)
return 0;
}
void *iwlist_remove(IWLIST *list, size_t index, size_t *osize, iwrc *orc) {
void* iwlist_remove(IWLIST *list, size_t index, size_t *osize, iwrc *orc) {
*orc = 0;
if (index >= list->num) {
*orc = IW_ERROR_OUT_OF_BOUNDS;
@@ -652,3 +672,7 @@ void *iwlist_remove(IWLIST *list, size_t index, size_t *osize, iwrc *orc) {
return rv;
}
void iwlist_sort(IWLIST *list, int (*compar)(const IWLISTITEM*, const IWLISTITEM*, void*), void *op) {
sort_r(list->array + list->start, list->num, sizeof(list->array[0]),
(int (*)(const void*, const void*, void*)) compar, op);
}
+72 -42
View File
@@ -22,12 +22,13 @@ IW_EXTERN_C_START
* @param skipeq If true and `eptr` is found in array it will not be inserted and method will return -1
* @return Index of inserted element
*/
IW_EXPORT off_t iwarr_sorted_insert(void *restrict els,
size_t nels,
size_t elsize,
void *restrict eptr,
int (*cmp)(const void *, const void *),
bool skipeq);
IW_EXPORT off_t iwarr_sorted_insert(
void* restrict els,
size_t nels,
size_t elsize,
void* restrict eptr,
int (*cmp)(const void*, const void*),
bool skipeq);
/**
* @brief Remove element from a sorteed array.
@@ -40,34 +41,37 @@ IW_EXPORT off_t iwarr_sorted_insert(void *restrict els,
* @param cmp Elements comparison function
* @return Index of removed element or -1
*/
IW_EXPORT off_t iwarr_sorted_remove(void *restrict els,
size_t nels,
size_t elsize,
void *restrict eptr,
int (*cmp)(const void *, const void *));
IW_EXPORT off_t iwarr_sorted_remove(
void* restrict els,
size_t nels,
size_t elsize,
void* restrict eptr,
int (*cmp)(const void*, const void*));
IW_EXPORT off_t iwarr_sorted_find(void *restrict els,
size_t nels,
size_t elsize,
void *restrict eptr,
int (*cmp)(const void *, const void *));
IW_EXPORT off_t iwarr_sorted_find(
void* restrict els,
size_t nels,
size_t elsize,
void* restrict eptr,
int (*cmp)(const void*, const void*));
IW_EXPORT off_t iwarr_sorted_find2(void *restrict els,
size_t nels,
size_t elsize,
void *restrict eptr,
void *op,
bool *found,
iwrc(*cmp)(const void *, const void *, void *, int *res));
IW_EXPORT off_t iwarr_sorted_find2(
void* restrict els,
size_t nels,
size_t elsize,
void* restrict eptr,
void *op,
bool *found,
iwrc (*cmp)(const void*, const void*, void*, int *res));
///////////////////////////////////////////////////////////////////////////
// Fixed sized item list //
///////////////////////////////////////////////////////////////////////////
typedef struct {
char *array; /**< Continuous units array */
char *array; /**< Continuous units array */
size_t usize; /**< Unit size */
size_t num; /**< Number of elements in units array */
size_t anum; /**< Actual number of allocated units */
@@ -90,7 +94,7 @@ IW_EXPORT iwrc iwulist_init(IWULIST *list, size_t initial_length, size_t unit_si
* @param unit_size Unit size
* @return Zero if memory allocation failed `errno` will be set respectively
*/
IW_EXPORT IWULIST *iwulist_create(size_t initial_length, size_t unit_size);\
IW_EXPORT IW_ALLOC IWULIST* iwulist_create(size_t initial_length, size_t unit_size);
/**
* @brief Cleanup units list.
@@ -121,7 +125,7 @@ IW_EXPORT size_t iwulist_length(IWULIST *list);
/**
* @brief Clones a given list.
*/
IW_EXPORT IWULIST *iwulist_clone(IWULIST *list);
IW_EXPORT IW_ALLOC IWULIST* iwulist_clone(IWULIST *list);
/**
* @brief Gets pinter to element at given `index`
@@ -129,9 +133,9 @@ IW_EXPORT IWULIST *iwulist_clone(IWULIST *list);
* @param index Index of element
* @param [out] orc Set to `IW_ERROR_OUT_OF_BOUNDS` if index is invalid
*/
IW_EXPORT void *iwulist_at(IWULIST *list, size_t index, iwrc *orc);
IW_EXPORT void* iwulist_at(IWULIST *list, size_t index, iwrc *orc);
IW_EXPORT void *iwulist_at2(IWULIST *list, size_t index);
IW_EXPORT void* iwulist_at2(IWULIST *list, size_t index);
/**
* @brief Inserts new element at given index.
@@ -181,20 +185,29 @@ IW_EXPORT iwrc iwulist_unshift(IWULIST *list, const void *data);
*/
IW_EXPORT iwrc iwulist_shift(IWULIST *list);
/**
* @brief Sorts list using given `compar` function.
*
* @param list IWULIST
* @param compar Elements comparator accepts user data as last argument
* @param op User data
*/
IW_EXPORT void iwulist_sort(IWULIST *list, int (*compar)(const void*, const void*, void*), void *op);
///////////////////////////////////////////////////////////////////////////
// Array list implementation //
///////////////////////////////////////////////////////////////////////////
typedef struct {
char *val;
char *val;
size_t size;
} IWLISTITEM;
typedef struct {
IWLISTITEM *array;
size_t anum; /**< Number of elements allocated */
size_t start; /**< Index of first element */
size_t num; /**< Actual number of elements */
size_t anum; /**< Number of elements allocated */
size_t start; /**< Index of first element */
size_t num; /**< Actual number of elements */
} IWLIST;
/**
@@ -212,7 +225,7 @@ IW_EXPORT iwrc iwlist_init(IWLIST *list, size_t anum);
* @param anum Number of elements to allocate or zero to use defaults
* @return Zero if allocation failed, `errno` will be set.
*/
IW_EXPORT IWLIST *iwlist_create(size_t anum);
IW_EXPORT IW_ALLOC IWLIST* iwlist_create(size_t anum);
/**
* @brief Destroys a given list object.
@@ -235,17 +248,25 @@ IW_EXPORT size_t iwlist_length(IWLIST *list);
* @brief Clone a given list.
* @return Zero if allocation failed, `errno` will be set.
*/
IW_EXPORT IWLIST *iwlist_clone(IWLIST *list);
IW_EXPORT IW_ALLOC IWLIST* iwlist_clone(IWLIST *list);
/**
* @brief Get element at specified index
* @brief Get element at specified index.
*
* @param index Element index
* @param [out] osize Optional size of returned element
* @param [out] osize Optional size of returned element data in bytes
* @param [out] orc Set to `IW_ERROR_OUT_OF_BOUNDS` if index is invalid
* @return IW_EXPORT* iwlist_at
* @return Elements data buffer
*/
IW_EXPORT void *iwlist_at(IWLIST *list, size_t index, size_t *osize, iwrc *orc);
IW_EXPORT void* iwlist_at(IWLIST *list, size_t index, size_t *osize, iwrc *orc);
/**
* @brief Get element at specified index.
* @param index Element index
* @param [out] osize Optional size of returned element data in bytes
* @return Elements data buffer or zero if element is not found
*/
IW_EXPORT void* iwlist_at2(IWLIST *list, size_t index, size_t *osize);
/**
* @brief Add element to end of list.
@@ -259,7 +280,7 @@ IW_EXPORT iwrc iwlist_push(IWLIST *list, const void *data, size_t data_size);
* @param [out] orc Set to `IW_ERROR_OUT_OF_BOUNDS` if list is empty
* @return IW_EXPORT* iwlist_pop
*/
IW_EXPORT void *iwlist_pop(IWLIST *list, size_t *osize, iwrc *orc);
IW_EXPORT void* iwlist_pop(IWLIST *list, size_t *osize, iwrc *orc);
/**
* @brief Add element to start of list
@@ -273,7 +294,7 @@ IW_EXPORT iwrc iwlist_unshift(IWLIST *list, const void *data, size_t data_size);
* @param orc Set to `IW_ERROR_OUT_OF_BOUNDS` if list is empty
* @return IW_EXPORT* iwlist_shift
*/
IW_EXPORT void *iwlist_shift(IWLIST *list, size_t *osize, iwrc *orc);
IW_EXPORT void* iwlist_shift(IWLIST *list, size_t *osize, iwrc *orc);
/**
* @brief Inserts element at given position.
@@ -283,14 +304,23 @@ IW_EXPORT iwrc iwlist_insert(IWLIST *list, size_t index, const void *data, size_
/**
* @brief Set/overwrite element at given position.
*/
IW_EXPORT iwrc iwlist_set(IWLIST *list, size_t index, const void *data, size_t data_size);
IW_EXPORT iwrc iwlist_set(IWLIST *list, size_t index, const void *data, size_t data_size);
/**
* @brief Remove element at given index.
*
* @param osize Optional size of removed element
*/
IW_EXPORT void *iwlist_remove(IWLIST *list, size_t index, size_t *osize, iwrc *orc);
IW_EXPORT void* iwlist_remove(IWLIST *list, size_t index, size_t *osize, iwrc *orc);
/**
* @brief Sorts list using given `compar` function.
*
* @param list IWLIST
* @param compar Elements comparator accepts user data as last argument
* @param op User data
*/
IW_EXPORT void iwlist_sort(IWLIST *list, int (*compar)(const IWLISTITEM*, const IWLISTITEM*, void*), void *op);
IW_EXTERN_C_END
#endif
+4 -4
View File
@@ -7,7 +7,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -113,9 +113,9 @@ IW_INLINE uint8_t iwbits_find_last_sbit64(uint64_t x) {
*/
IW_INLINE uint64_t iwbits_reverse_64(uint64_t x) {
uint64_t t;
x = (x << 32) | (x >> 32); /* Swap register halves. */
x = (x & 0x0001ffff0001ffffLL) << 15 | /* Rotate left */
(x & 0xfffe0000fffe0000LL) >> 17; /* 15. */
x = (x << 32) | (x >> 32); /* Swap register halves. */
x = (x & 0x0001ffff0001ffffLL) << 15 /* Rotate left */
| (x & 0xfffe0000fffe0000LL) >> 17; /* 15. */
t = (x ^ (x >> 10)) & 0x003f801f003f801fLL;
x = (t | (t << 10)) ^ x;
t = (x ^ (x >> 4)) & 0x0e0384210e038421LL;
+202 -29
View File
@@ -2,6 +2,8 @@
#include <math.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
// mapping of ASCII characters to hex values
const uint8_t ascii2hex[] = {
@@ -52,19 +54,49 @@ size_t iwhex2bin(const char *hex, int hexlen, char *out, int max) {
idx1 = hex[pos + 1];
pos += 2;
}
out[vpos++] = (uint8_t)(ascii2hex[idx0] << 4) | ascii2hex[idx1];
out[vpos++] = (uint8_t) (ascii2hex[idx0] << 4) | ascii2hex[idx1];
if (vpos >= max) {
return vpos;
}
};
}
;
return vpos;
}
char* iwbin2hex(
char* const hex,
const size_t hex_maxlen,
const unsigned char* const bin,
const size_t bin_len) {
size_t i = (size_t) 0U;
unsigned int x;
int b;
int c;
if ((bin_len >= SIZE_MAX / 2) || (hex_maxlen <= bin_len * 2U)) {
//errx(2, "bin2hex length wrong");
return 0;
}
while (i < bin_len) {
c = bin[i] & 0xf;
b = bin[i] >> 4;
x = (unsigned char) (87U + c + (((c - 10U) >> 8) & ~38U)) << 8
| (unsigned char) (87U + b + (((b - 10U) >> 8) & ~38U));
hex[i * 2U] = (char) x;
x >>= 8;
hex[i * 2U + 1U] = (char) x;
i++;
}
hex[i * 2U] = 0U;
return hex;
}
int iwitoa(int64_t v, char *buf, int max) {
#define ITOA_SZSTEP(_step) if ((ret += (_step)) >= max) { \
*ptr = 0; \
return ret; \
}
}
int ret = 0;
char c, *ptr = buf, *p, *p1;
if (!v) {
@@ -77,7 +109,7 @@ int iwitoa(int64_t v, char *buf, int max) {
if (v < 0) {
v = -v;
ITOA_SZSTEP(1)
*ptr++ = '-';
* ptr++ = '-';
}
// save start pointer
p = ptr;
@@ -104,7 +136,7 @@ int iwitoa(int64_t v, char *buf, int max) {
#undef ITOA_SZSTEP
}
char *iwftoa(long double n, char s[static IWFTOA_BUFSIZE]) {
char* iwftoa(long double n, char s[static IWFTOA_BUFSIZE]) {
static double PRECISION = 0.00000000000001;
// handle special cases
if (isnan(n)) {
@@ -141,12 +173,12 @@ char *iwftoa(long double n, char s[static IWFTOA_BUFSIZE]) {
// convert the number
while (n > PRECISION || m >= 0) {
double weight = pow(10.0, m);
if (weight > 0 && !isinf(weight)) {
if ((weight > 0) && !isinf(weight)) {
digit = (int) floorl(n / weight);
n -= (digit * weight);
*(c++) = '0' + digit;
}
if (m == 0 && n > 0) {
if ((m == 0) && (n > 0)) {
*(c++) = '.';
}
m--;
@@ -193,9 +225,13 @@ int64_t iwatoi(const char *str) {
} else if (*str == '+') {
str++;
}
if (!strcmp(str, "inf")) return (INT64_MAX * sign);
if (!strcmp(str, "inf")) {
return (INT64_MAX * sign);
}
while (*str != '\0') {
if (*str < '0' || *str > '9') break;
if ((*str < '0') || (*str > '9')) {
break;
}
num = num * 10 + *str - '0';
str++;
}
@@ -219,7 +255,7 @@ long double iwatof(const char *str) {
}
long double num = 0;
while (*str != '\0') {
if (*str < '0' || *str > '9') {
if ((*str < '0') || (*str > '9')) {
break;
}
num = num * 10 + *str - '0';
@@ -230,7 +266,7 @@ long double iwatof(const char *str) {
long double fract = 0.0;
long double base = 10;
while (*str != '\0') {
if (*str < '0' || *str > '9') {
if ((*str < '0') || (*str > '9')) {
break;
}
fract += (*str - '0') / base;
@@ -239,7 +275,7 @@ long double iwatof(const char *str) {
}
num += fract;
}
if (*str == 'e' || *str == 'E') {
if ((*str == 'e') || (*str == 'E')) {
str++;
num *= pow(10, iwatoi(str));
}
@@ -250,8 +286,8 @@ long double iwatof(const char *str) {
* Compare two strings as real numbers
*/
int iwafcmp(const char *aptr, int asiz, const char *bptr, int bsiz) {
const unsigned char *arp = (const unsigned char *) aptr;
const unsigned char *brp = (const unsigned char *) bptr;
const unsigned char *arp = (const unsigned char*) aptr;
const unsigned char *brp = (const unsigned char*) bptr;
int alen = asiz, blen = bsiz;
int64_t anum = 0, bnum = 0;
int asign = 1, bsign = 1;
@@ -261,14 +297,16 @@ int iwafcmp(const char *aptr, int asiz, const char *bptr, int bsiz) {
arp++;
alen--;
}
if (alen > 0 && *arp == '-') {
if ((alen > 0) && (*arp == '-')) {
arp++;
alen--;
asign = -1;
}
while (alen > 0) {
int c = *arp;
if (c < '0' || c > '9') break;
if ((c < '0') || (c > '9')) {
break;
}
anum = anum * 10 + c - '0';
arp++;
alen--;
@@ -280,31 +318,41 @@ int iwafcmp(const char *aptr, int asiz, const char *bptr, int bsiz) {
brp++;
blen--;
}
if (blen > 0 && *brp == '-') {
if ((blen > 0) && (*brp == '-')) {
brp++;
blen--;
bsign = -1;
}
while (blen > 0) {
int c = *brp;
if (c < '0' || c > '9') break;
if ((c < '0') || (c > '9')) {
break;
}
bnum = bnum * 10 + c - '0';
brp++;
blen--;
}
bnum *= bsign;
if (anum < bnum) return -1;
if (anum > bnum) return 1;
if ((alen > 1 && *arp == '.') || (blen > 1 && *brp == '.')) {
if (anum < bnum) {
return -1;
}
if (anum > bnum) {
return 1;
}
if (((alen > 1) && (*arp == '.')) || ((blen > 1) && (*brp == '.'))) {
long double aflt = 0;
long double bflt = 0;
if (alen > 1 && *arp == '.') {
if ((alen > 1) && (*arp == '.')) {
arp++;
alen--;
if (alen > IWFTOA_BUFSIZE) alen = IWFTOA_BUFSIZE;
if (alen > IWFTOA_BUFSIZE) {
alen = IWFTOA_BUFSIZE;
}
long double base = 10;
while (alen > 0) {
if (*arp < '0' || *arp > '9') break;
if ((*arp < '0') || (*arp > '9')) {
break;
}
aflt += (*arp - '0') / base;
arp++;
alen--;
@@ -312,13 +360,17 @@ int iwafcmp(const char *aptr, int asiz, const char *bptr, int bsiz) {
}
aflt *= asign;
}
if (blen > 1 && *brp == '.') {
if ((blen > 1) && (*brp == '.')) {
brp++;
blen--;
if (blen > IWFTOA_BUFSIZE) blen = IWFTOA_BUFSIZE;
if (blen > IWFTOA_BUFSIZE) {
blen = IWFTOA_BUFSIZE;
}
long double base = 10;
while (blen > 0) {
if (*brp < '0' || *brp > '9') break;
if ((*brp < '0') || (*brp > '9')) {
break;
}
bflt += (*brp - '0') / base;
brp++;
blen--;
@@ -326,8 +378,12 @@ int iwafcmp(const char *aptr, int asiz, const char *bptr, int bsiz) {
}
bflt *= bsign;
}
if (aflt < bflt) return -1;
if (aflt > bflt) return 1;
if (aflt < bflt) {
return -1;
}
if (aflt > bflt) {
return 1;
}
}
int rv = strncmp(aptr, bptr, MIN(asiz, bsiz));
if (!rv) {
@@ -336,3 +392,120 @@ int iwafcmp(const char *aptr, int asiz, const char *bptr, int bsiz) {
return rv;
}
}
/// MIT Licensed
/// Taken https://github.com/mattn/strtod/blob/master/strtod.c
static const char* skipwhite(const char *q) {
const char *p = q;
while (isspace(*p)) {
++p;
}
return p;
}
double iwstrtod(const char *str, char **end) {
double d = 0.0;
int sign;
int n = 0;
const char *p, *a;
a = p = str;
p = skipwhite(p);
/* decimal part */
sign = 1;
if (*p == '-') {
sign = -1;
++p;
} else if (*p == '+') {
++p;
}
if (isdigit(*p)) {
d = (double) (*p++ - '0');
while (*p && isdigit(*p)) {
d = d * 10.0 + (double) (*p - '0');
++p;
++n;
}
a = p;
} else if (*p != '.') {
goto done;
}
d *= sign;
/* fraction part */
if (*p == '.') {
double f = 0.0;
double base = 0.1;
++p;
if (isdigit(*p)) {
while (*p && isdigit(*p)) {
f += base * (*p - '0');
base /= 10.0;
++p;
++n;
}
}
d += f * sign;
a = p;
}
/* exponential part */
if ((*p == 'E') || (*p == 'e')) {
int e = 0;
++p;
sign = 1;
if (*p == '-') {
sign = -1;
++p;
} else if (*p == '+') {
++p;
}
if (isdigit(*p)) {
while (*p == '0') {
++p;
}
if (*p == '\0') {
--p;
}
e = (*p++ - '0');
while (*p && isdigit(*p)) {
e = e * 10 + (*p - '0');
++p;
}
e *= sign;
} else if (!isdigit(*(a - 1))) {
a = str;
goto done;
} else if (*p == 0) {
goto done;
}
if (d == 2.2250738585072011 && e == -308) {
d = 0.0;
a = p;
errno = ERANGE;
goto done;
}
if (d == 2.2250738585072012 && e <= -308) {
d *= 1.0e-308;
a = p;
goto done;
}
d *= pow(10.0, (double) e);
a = p;
} else if (p > str && !isdigit(*(p - 1))) {
a = str;
goto done;
}
done:
if (end) {
*end = (char*) a;
}
return d;
}
+9 -1
View File
@@ -7,7 +7,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -41,6 +41,8 @@ IW_EXPORT int64_t iwatoi(const char *str);
IW_EXPORT long double iwatof(const char *str);
IW_EXPORT double iwstrtod(const char *str, char **end);
IW_EXPORT int iwitoa(int64_t v, char *buf, int max);
/**
@@ -57,6 +59,12 @@ IW_EXPORT int iwafcmp(const char *aptr, int asiz, const char *bptr, int bsiz);
IW_EXPORT size_t iwhex2bin(const char *hex, int hexlen, char *out, int max);
IW_EXPORT char* iwbin2hex(
char* const hex,
const size_t hex_maxlen,
const unsigned char* const bin,
const size_t bin_len);
IW_EXTERN_C_END
#endif
+24 -24
View File
@@ -8,11 +8,11 @@
#include <assert.h>
#define MIN_BUCKETS 64
#define STEPS 4
#define STEPS 4
typedef struct {
void *key;
void *val;
void *key;
void *val;
uint32_t hash;
} entry_t;
@@ -23,18 +23,17 @@ typedef struct {
} bucket_t;
typedef struct _IWHMAP {
uint32_t count;
uint32_t buckets_mask;
uint32_t count;
uint32_t buckets_mask;
bucket_t *buckets;
int (*cmp_fn)(const void *, const void *);
uint32_t (*hash_key_fn)(const void *);
void (*kv_free_fn)(void *, void *);
int (*cmp_fn)(const void*, const void*);
uint32_t (*hash_key_fn)(const void*);
void (*kv_free_fn)(void*, void*);
bool int_key_as_pointer_value;
} hmap_t;
static void _noop_kv_free(void *key, void *val) {
}
@@ -106,9 +105,10 @@ IW_INLINE uint32_t _hash_buf_key(const void *key) {
return murmur3(key, strlen(key));
}
IWHMAP *iwhmap_create(int (*cmp_fn)(const void *, const void *),
uint32_t (*hash_key_fn)(const void *),
void (*kv_free_fn)(void *, void *)) {
IWHMAP* iwhmap_create(
int (*cmp_fn)(const void*, const void*),
uint32_t (*hash_key_fn)(const void*),
void (*kv_free_fn)(void*, void*)) {
if (!hash_key_fn) {
return 0;
@@ -138,7 +138,7 @@ IWHMAP *iwhmap_create(int (*cmp_fn)(const void *, const void *),
return hm;
}
IWHMAP *iwhmap_create_i64(void (*kv_free_fn)(void *, void *)) {
IWHMAP* iwhmap_create_i64(void (*kv_free_fn)(void*, void*)) {
hmap_t *hm = iwhmap_create(_int64_cmp, _hash_int64_key, kv_free_fn);
if (hm) {
#ifdef IW_64
@@ -148,7 +148,7 @@ IWHMAP *iwhmap_create_i64(void (*kv_free_fn)(void *, void *)) {
return hm;
}
IWHMAP *iwhmap_create_i32(void (*kv_free_fn)(void *, void *)) {
IWHMAP* iwhmap_create_i32(void (*kv_free_fn)(void*, void*)) {
hmap_t *hm = iwhmap_create(_int32_cmp, _hash_int32_key, kv_free_fn);
if (hm) {
hm->int_key_as_pointer_value = true;
@@ -156,22 +156,22 @@ IWHMAP *iwhmap_create_i32(void (*kv_free_fn)(void *, void *)) {
return hm;
}
IWHMAP *iwhmap_create_str(void (*kv_free_fn)(void *, void *)) {
return iwhmap_create((int (*)(const void *, const void *)) strcmp, _hash_buf_key, kv_free_fn);
IWHMAP* iwhmap_create_str(void (*kv_free_fn)(void*, void*)) {
return iwhmap_create((int (*)(const void*, const void*)) strcmp, _hash_buf_key, kv_free_fn);
}
static entry_t *_entry_find(IWHMAP *hm, const void *key, uint32_t hash) {
static entry_t* _entry_find(IWHMAP *hm, const void *key, uint32_t hash) {
bucket_t *bucket = hm->buckets + (hash & hm->buckets_mask);
entry_t *entry = bucket->entries;
for (entry_t *end = entry + bucket->used; entry < end; ++entry) {
if (hash == entry->hash && hm->cmp_fn(key, entry->key) == 0) {
if ((hash == entry->hash) && (hm->cmp_fn(key, entry->key) == 0)) {
return entry;
}
}
return 0;
}
static entry_t *_entry_add(IWHMAP *hm, void *key, uint32_t hash) {
static entry_t* _entry_add(IWHMAP *hm, void *key, uint32_t hash) {
entry_t *entry;
bucket_t *bucket = hm->buckets + (hash & hm->buckets_mask);
@@ -191,7 +191,7 @@ static entry_t *_entry_add(IWHMAP *hm, void *key, uint32_t hash) {
entry = bucket->entries;
for (entry_t *end = entry + bucket->used; entry < end; ++entry) {
// NOLINTNEXTLINE (clang-analyzer-core.UndefinedBinaryOperatorResult)
if (hash == entry->hash && hm->cmp_fn(key, entry->key) == 0) {
if ((hash == entry->hash) && (hm->cmp_fn(key, entry->key) == 0)) {
return entry;
}
}
@@ -224,7 +224,7 @@ static void _rehash(hmap_t *hm, uint32_t num_buckets) {
for (bucket = hm->buckets; bucket < bucket_end; ++bucket) {
entry_t *entry_old = bucket->entries;
entry_t *entry_old_end = entry_old + bucket->used;
for (; entry_old < entry_old_end; ++entry_old) {
for ( ; entry_old < entry_old_end; ++entry_old) {
entry_t *entry_new = _entry_add(&hm_copy, entry_old->key, entry_old->hash);
if (!entry_new) {
goto fail;
@@ -270,7 +270,7 @@ iwrc iwhmap_put(IWHMAP *hm, void *key, void *val) {
return 0;
}
void *iwhmap_get(IWHMAP *hm, const void *key) {
void* iwhmap_get(IWHMAP *hm, const void *key) {
uint32_t hash = hm->hash_key_fn(key);
entry_t *entry = _entry_find(hm, key, hash);
if (entry) {
@@ -300,7 +300,7 @@ void iwhmap_remove(IWHMAP *hm, const void *key) {
--bucket->used;
--hm->count;
if (hm->buckets_mask > MIN_BUCKETS - 1 && hm->count < hm->buckets_mask / 2) {
if ((hm->buckets_mask > MIN_BUCKETS - 1) && (hm->count < hm->buckets_mask / 2)) {
_rehash(hm, _n_buckets(hm) / 2);
} else {
uint32_t steps_used = bucket->used / STEPS;
@@ -310,7 +310,7 @@ void iwhmap_remove(IWHMAP *hm, const void *key) {
entry_t *entries_new = realloc(bucket->entries, (steps_used + 1) * STEPS * sizeof(entries_new[0]));
if (entries_new) {
bucket->entries = entries_new;
bucket->total = (steps_used + 1) * STEPS;
bucket->total = (steps_used + 1) * STEPS;
}
}
}
+12 -11
View File
@@ -9,7 +9,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -37,11 +37,11 @@ struct _IWHMAP;
typedef struct _IWHMAP IWHMAP;
typedef struct {
IWHMAP *hm;
IWHMAP *hm;
const void *key;
const void *val;
uint32_t bucket;
int32_t entry;
uint32_t bucket;
int32_t entry;
} IWHMAP_ITER;
/**
@@ -52,21 +52,22 @@ typedef struct {
*/
IW_EXPORT void iwhmap_kv_free(void *key, void *val);
IW_EXPORT IWHMAP *iwhmap_create(int (*cmp_fn)(const void *, const void *),
uint32_t (*hash_key_fn)(const void *),
void (*kv_free_fn)(void *, void *));
IW_EXPORT IWHMAP* iwhmap_create(
int (*cmp_fn)(const void*, const void*),
uint32_t (*hash_key_fn)(const void*),
void (*kv_free_fn)(void*, void*));
IW_EXPORT IWHMAP *iwhmap_create_i64(void (*kv_free_fn)(void *, void *));
IW_EXPORT IWHMAP* iwhmap_create_i64(void (*kv_free_fn)(void*, void*));
IW_EXPORT IWHMAP *iwhmap_create_i32(void (*kv_free_fn)(void *, void *));
IW_EXPORT IWHMAP* iwhmap_create_i32(void (*kv_free_fn)(void*, void*));
IW_EXPORT IWHMAP *iwhmap_create_str(void (*kv_free_fn)(void *, void *));
IW_EXPORT IWHMAP* iwhmap_create_str(void (*kv_free_fn)(void*, void*));
IW_EXPORT iwrc iwhmap_put(IWHMAP *hm, void *key, void *val);
IW_EXPORT void iwhmap_remove(IWHMAP *hm, const void *key);
IW_EXPORT void *iwhmap_get(IWHMAP *hm, const void *key);
IW_EXPORT void* iwhmap_get(IWHMAP *hm, const void *key);
IW_EXPORT int iwhmap_count(IWHMAP *hm);
+47 -29
View File
@@ -11,21 +11,21 @@
/** Atomic heap unit */
typedef struct IWPOOL_UNIT {
void *heap;
void *heap;
struct IWPOOL_UNIT *next;
} IWPOOL_UNIT;
/** Memory pool */
struct _IWPOOL {
size_t usiz; /**< Used size */
size_t asiz; /**< Allocated size */
char *heap; /**< Current pool heap ptr */
IWPOOL_UNIT *unit; /**< Current heap unit */
void *user_data; /**< Associated user data */
void (*user_data_free_fn)(void *); /**< User data dispose function */
size_t usiz; /**< Used size */
size_t asiz; /**< Allocated size */
char *heap; /**< Current pool heap ptr */
IWPOOL_UNIT *unit; /**< Current heap unit */
void *user_data; /**< Associated user data */
void (*user_data_free_fn)(void*); /**< User data dispose function */
};
IWPOOL *iwpool_create(size_t siz) {
IWPOOL* iwpool_create(size_t siz) {
IWPOOL *pool;
siz = siz < 1 ? IWPOOL_POOL_SIZ : siz;
siz = IW_ROUNDUP(siz, IWPOOL_UNIT_ALIGN_SIZE);
@@ -60,12 +60,12 @@ error:
return 0;
}
IWPOOL *iwpool_create_empty(void) {
IWPOOL* iwpool_create_empty(void) {
return calloc(1, sizeof(struct _IWPOOL));
}
IW_INLINE int iwpool_extend(IWPOOL *pool, size_t siz) {
IWPOOL_UNIT *nunit = malloc(sizeof(*nunit));
IWPOOL_UNIT *nunit = malloc(sizeof(*nunit));
if (!nunit) {
return 0;
}
@@ -83,7 +83,7 @@ IW_INLINE int iwpool_extend(IWPOOL *pool, size_t siz) {
return 1;
}
void *iwpool_alloc(size_t siz, IWPOOL *pool) {
void* iwpool_alloc(size_t siz, IWPOOL *pool) {
siz = IW_ROUNDUP(siz, IWPOOL_UNIT_ALIGN_SIZE);
size_t usiz = pool->usiz + siz;
if (SIZE_T_MAX - pool->usiz < siz) {
@@ -105,7 +105,7 @@ void *iwpool_alloc(size_t siz, IWPOOL *pool) {
return h;
}
void *iwpool_calloc(size_t siz, IWPOOL *pool) {
void* iwpool_calloc(size_t siz, IWPOOL *pool) {
void *res = iwpool_alloc(siz, pool);
if (!res) {
return 0;
@@ -114,7 +114,7 @@ void *iwpool_calloc(size_t siz, IWPOOL *pool) {
return res;
}
char *iwpool_strndup(IWPOOL *pool, const char *str, size_t len, iwrc *rcp) {
char* iwpool_strndup(IWPOOL *pool, const char *str, size_t len, iwrc *rcp) {
char *ret = iwpool_alloc(len + 1, pool);
if (!ret) {
*rcp = iwrc_set_errno(IW_ERROR_ALLOC, errno);
@@ -127,16 +127,26 @@ char *iwpool_strndup(IWPOOL *pool, const char *str, size_t len, iwrc *rcp) {
return ret;
}
char *iwpool_strdup(IWPOOL *pool, const char *str, iwrc *rcp) {
char* iwpool_strdup(IWPOOL *pool, const char *str, iwrc *rcp) {
return iwpool_strndup(pool, str, strlen(str), rcp);
}
char* iwpool_strdup2(IWPOOL *pool, const char *str) {
iwrc rc;
return iwpool_strndup(pool, str, strlen(str), &rc);
}
char* iwpool_strndup2(IWPOOL *pool, const char *str, size_t len) {
iwrc rc;
return iwpool_strndup(pool, str, len, &rc);
}
IW_INLINE int _iwpool_printf_estimate_size(const char *format, va_list ap) {
char buf[1];
return vsnprintf(buf, sizeof(buf), format, ap) + 1;
}
static char *_iwpool_printf_va(IWPOOL *pool, int size, const char *format, va_list ap) {
static char* _iwpool_printf_va(IWPOOL *pool, int size, const char *format, va_list ap) {
char *wbuf = iwpool_alloc(size, pool);
if (!wbuf) {
return 0;
@@ -145,7 +155,7 @@ static char *_iwpool_printf_va(IWPOOL *pool, int size, const char *format, va_li
return wbuf;
}
char *iwpool_printf(IWPOOL *pool, const char *format, ...) {
char* iwpool_printf(IWPOOL *pool, const char *format, ...) {
va_list ap;
va_start(ap, format);
int size = _iwpool_printf_estimate_size(format, ap);
@@ -156,27 +166,34 @@ char *iwpool_printf(IWPOOL *pool, const char *format, ...) {
return res;
}
char **iwpool_split_string(IWPOOL *pool, const char *haystack, const char *split_chars,
bool ignore_whitespace) {
char** iwpool_split_string(
IWPOOL *pool, const char *haystack, const char *split_chars,
bool ignore_whitespace) {
size_t hsz = strlen(haystack);
char **ret = iwpool_alloc((hsz + 1) * sizeof(char *), pool);
if (!ret) return 0;
char **ret = iwpool_alloc((hsz + 1) * sizeof(char*), pool);
if (!ret) {
return 0;
}
const char *sp = haystack;
const char *ep = sp;
int j = 0;
for (int i = 0; *ep; ++i, ++ep) {
const char ch = haystack[i];
const char *sch = strchr(split_chars, ch);
if (ep >= sp && (sch || *(ep + 1) == '\0')) {
if (!sch && *(ep + 1) == '\0') ++ep;
if ((ep >= sp) && (sch || (*(ep + 1) == '\0'))) {
if (!sch && (*(ep + 1) == '\0')) {
++ep;
}
if (ignore_whitespace) {
while (isspace(*sp)) ++sp;
while (isspace(*(ep - 1))) --ep;
}
if (ep >= sp) {
char *s = iwpool_alloc(ep - sp + 1, pool);
if (!s) return 0;
if (!s) {
return 0;
}
memcpy(s, sp, ep - sp);
s[ep - sp] = '\0';
ret[j++] = s;
@@ -189,9 +206,10 @@ char **iwpool_split_string(IWPOOL *pool, const char *haystack, const char *split
return ret;
}
char **iwpool_printf_split(IWPOOL *pool,
const char *split_chars, bool ignore_whitespace,
const char *format, ...) {
char** iwpool_printf_split(
IWPOOL *pool,
const char *split_chars, bool ignore_whitespace,
const char *format, ...) {
va_list ap;
va_start(ap, format);
@@ -213,7 +231,7 @@ void iwpool_free_fn(void *pool) {
iwpool_destroy(pool);
}
void iwpool_user_data_set(IWPOOL *pool, void *data, void (*free_fn)(void *)) {
void iwpool_user_data_set(IWPOOL *pool, void *data, void (*free_fn)(void*)) {
if (pool->user_data_free_fn) {
pool->user_data_free_fn(pool->user_data);
}
@@ -221,12 +239,12 @@ void iwpool_user_data_set(IWPOOL *pool, void *data, void (*free_fn)(void *)) {
pool->user_data = data;
}
void *iwpool_user_data_detach(IWPOOL *pool) {
void* iwpool_user_data_detach(IWPOOL *pool) {
pool->user_data_free_fn = 0;
return pool->user_data;
}
void *iwpool_user_data_get(IWPOOL *pool) {
void* iwpool_user_data_get(IWPOOL *pool) {
return pool->user_data;
}
+23 -17
View File
@@ -9,7 +9,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -34,7 +34,7 @@
IW_EXTERN_C_START
#ifndef IWPOOL_POOL_SIZ
#define IWPOOL_POOL_SIZ (8 * 1024)
#define IWPOOL_POOL_SIZ (8 * 1024)
#endif
struct _IWPOOL;
@@ -47,13 +47,13 @@ typedef struct _IWPOOL IWPOOL;
* @param siz Initial memory buffer size. Can be zero.
* @return Pointer to the new pool or `zero` if allocation is failed.
*/
IW_EXPORT IWPOOL *iwpool_create(size_t siz);
IW_EXPORT IW_ALLOC IWPOOL* iwpool_create(size_t siz);
/**
* @brief Create empty pool with no preallocated buffer.
* @return Pointer to the new pool or `zero` if allocation is failed.
*/
IW_EXPORT IWPOOL *iwpool_create_empty(void);
IW_EXPORT IW_ALLOC IWPOOL* iwpool_create_empty(void);
/**
* @brief Allocates buffer of specified size.
@@ -62,7 +62,7 @@ IW_EXPORT IWPOOL *iwpool_create_empty(void);
* @param pool Pointer to memory pool.
* @return Pointer to buffer or `zero` if allocation is failed.
*/
IW_EXPORT void *iwpool_alloc(size_t siz, IWPOOL *pool);
IW_EXPORT void* iwpool_alloc(size_t siz, IWPOOL *pool);
/**
* @brief Allocates zero initialized memory buffer
@@ -72,7 +72,7 @@ IW_EXPORT void *iwpool_alloc(size_t siz, IWPOOL *pool);
* @param pool Pointer to memory pool.
* @return Pointer to buffer or `zero` if allocation is failed.
*/
IW_EXPORT void *iwpool_calloc(size_t siz, IWPOOL *pool);
IW_EXPORT void* iwpool_calloc(size_t siz, IWPOOL *pool);
/**
* @brief Copy a given `str` of size `len` into memory pool.
@@ -83,7 +83,7 @@ IW_EXPORT void *iwpool_calloc(size_t siz, IWPOOL *pool);
* @param rcp Pointer to status code holder.
* @return Pointer to copied buffer or `zero` if operation failed.
*/
IW_EXPORT char *iwpool_strndup(IWPOOL *pool, const char *str, size_t len, iwrc *rcp);
IW_EXPORT char* iwpool_strndup(IWPOOL *pool, const char *str, size_t len, iwrc *rcp);
/**
* @brief Copy a given zero terminated char buffer into memory pool.
@@ -93,7 +93,11 @@ IW_EXPORT char *iwpool_strndup(IWPOOL *pool, const char *str, size_t len, iwrc *
* @param rcp Pointer to status code holder.
* @return Pointer to copied buffer or `zero` if operation failed.
*/
IW_EXPORT char *iwpool_strdup(IWPOOL *pool, const char *str, iwrc *rcp);
IW_EXPORT char* iwpool_strdup(IWPOOL *pool, const char *str, iwrc *rcp);
IW_EXPORT char* iwpool_strdup2(IWPOOL *pool, const char *str);
IW_EXPORT char* iwpool_strndup2(IWPOOL *pool, const char *str, size_t len);
/**
* @brief Do `fprintf` into string allocated in this memory pool.
@@ -103,14 +107,16 @@ IW_EXPORT char *iwpool_strdup(IWPOOL *pool, const char *str, iwrc *rcp);
* @param ...
* @return Pointer to resulted string of `zero` if operation is failed.
*/
IW_EXPORT char *iwpool_printf(IWPOOL *pool, const char *format, ...);
IW_EXPORT char* iwpool_printf(IWPOOL *pool, const char *format, ...) __attribute__((format(__printf__, 2, 3)));
IW_EXPORT char **iwpool_split_string(IWPOOL *pool, const char *haystack,
const char *split_chars, bool ignore_whitespace);
IW_EXPORT char** iwpool_split_string(
IWPOOL *pool, const char *haystack,
const char *split_chars, bool ignore_whitespace);
IW_EXPORT char **iwpool_printf_split(IWPOOL *pool,
const char *split_chars, bool ignore_whitespace,
const char *format, ...);
IW_EXPORT char** iwpool_printf_split(
IWPOOL *pool,
const char *split_chars, bool ignore_whitespace,
const char *format, ...) __attribute__((format(__printf__, 4, 5)));
/**
* @brief Destroys a given memory pool and frees its resources.
@@ -135,12 +141,12 @@ IW_EXPORT void iwpool_free_fn(void *pool);
* @param data User data. Can be zero.
* @param free_fn User data dispose function. Can be zero.
*/
IW_EXPORT void iwpool_user_data_set(IWPOOL *pool, void *data, void (*free_fn)(void *));
IW_EXPORT void iwpool_user_data_set(IWPOOL *pool, void *data, void (*free_fn)(void*));
/**
* @brief Returns pointer to user data associated with this pool. Or zero.
*/
IW_EXPORT void *iwpool_user_data_get(IWPOOL *pool);
IW_EXPORT void* iwpool_user_data_get(IWPOOL *pool);
/**
* @brief Reset user data free function for current user data stored in pool.
@@ -148,7 +154,7 @@ IW_EXPORT void *iwpool_user_data_get(IWPOOL *pool);
* @param pool Pointer to memory pool.
* @return Pointer to current user data stored or zero,
*/
IW_EXPORT void *iwpool_user_data_detach(IWPOOL *pool);
IW_EXPORT void* iwpool_user_data_detach(IWPOOL *pool);
/**
* @brief Returns number of bytes allocated for this memory pool.
+112
View File
@@ -0,0 +1,112 @@
#include "iwrb.h"
#include <stdlib.h>
#include <string.h>
IWRB* iwrb_create(size_t usize, size_t len) {
IWRB *rb = malloc(sizeof(*rb) + usize * len);
if (!rb) {
return 0;
}
rb->pos = 0;
rb->len = len;
rb->usize = usize;
rb->buf = (char*) rb + sizeof(*rb);
return rb;
}
void iwrb_destroy(IWRB **rbp) {
if (rbp && *rbp) {
free(*rbp);
*rbp = 0;
}
}
IWRB* iwrb_wrap(void *buf, size_t len, size_t usize) {
if (buf == 0 || len < sizeof(IWRB) + usize) {
return 0;
}
IWRB *rb = buf;
rb->pos = 0;
rb->len = (len - sizeof(IWRB)) / usize;
rb->usize = usize;
rb->buf = (char*) buf + sizeof(*rb);
return rb;
}
void iwrb_put(IWRB *rb, const void *buf) {
if (rb->pos != 0) {
size_t upos = rb->pos > 0 ? rb->pos : -rb->pos;
if (upos == rb->len) {
memcpy(rb->buf, buf, rb->usize);
rb->pos = 1;
} else {
memcpy(rb->buf + upos * rb->usize, buf, rb->usize);
rb->pos = rb->pos > 0 ? rb->pos + 1 : rb->pos - 1;
}
} else {
memcpy(rb->buf, buf, rb->usize);
rb->pos = -1;
}
}
void iwrb_back(IWRB *rb) {
if (rb->pos > 0) {
--rb->pos;
} else if (rb->pos < 0) {
++rb->pos;
}
}
void* iwrb_peek(const IWRB *rb) {
if (rb->pos == 0) {
return 0;
}
size_t upos = rb->pos > 0 ? rb->pos : -rb->pos;
return rb->buf + (upos - 1) * rb->usize;
}
void iwrb_clear(IWRB *rb) {
rb->pos = 0;
}
size_t iwrb_num_cached(const IWRB *rb) {
if (rb->pos <= 0) {
return -rb->pos;
} else {
return rb->len;
}
}
void iwrb_iter_init(const IWRB *rb, IWRB_ITER *iter) {
iter->rb = rb;
iter->pos = rb->pos > 0 ? rb->pos : -rb->pos;
iter->ipos = rb->pos > 0 ? -rb->pos : rb->pos;
}
void* iwrb_iter_prev(IWRB_ITER *iter) {
const IWRB *rb = iter->rb;
if (iter->ipos == 0) {
return 0;
}
if (rb->pos < 0) {
if (iter->pos == 0) {
return 0;
}
if (iter->ipos < 0) {
iter->ipos = -iter->ipos;
}
return rb->buf + --iter->pos * rb->usize;
} else {
if (iter->pos == 0) {
iter->pos = rb->len;
}
if (iter->ipos < 0) {
iter->ipos = -iter->ipos;
} else if (iter->ipos == iter->pos) {
iter->ipos = 0;
return 0;
}
return rb->buf + --iter->pos * rb->usize;
}
}
+71
View File
@@ -0,0 +1,71 @@
#pragma once
#ifndef IWRB_H
#define IWRB_H
/**************************************************************************************************
* Ring buffer.
*
* IOWOW library
*
* MIT License
*
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*************************************************************************************************/
#include "basedefs.h"
IW_EXTERN_C_START
typedef struct {
ssize_t pos;
size_t len;
size_t usize;
char *buf;
} IWRB;
typedef struct {
const IWRB *rb;
size_t pos;
ssize_t ipos;
} IWRB_ITER;
IW_EXPORT IW_ALLOC IWRB* iwrb_create(size_t usize, size_t len);
IW_EXPORT void iwrb_clear(IWRB *rb);
IW_EXPORT void iwrb_destroy(IWRB **rbp);
IW_EXPORT IWRB* iwrb_wrap(void *buf, size_t len, size_t usize);
IW_EXPORT void iwrb_put(IWRB *rb, const void *buf);
IW_EXPORT void iwrb_back(IWRB *rb);
IW_EXPORT void* iwrb_peek(const IWRB *rb);
IW_EXPORT size_t iwrb_num_cached(const IWRB *rb);
IW_EXPORT void iwrb_iter_init(const IWRB *rb, IWRB_ITER *iter);
IW_EXPORT void* iwrb_iter_prev(IWRB_ITER *iter);
IW_EXTERN_C_END
#endif
+994
View File
@@ -0,0 +1,994 @@
// -V::506
/* Copyright (c) 2014 by Ian Piumarta
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the 'Software'),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, provided that the above copyright notice(s) and this
* permission notice appear in all copies of the Software. Acknowledgement
* of the use of this Software in supporting documentation would be
* appreciated but is not required.
*
* THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK.
*/
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
#include <assert.h>
#include "iwre.h"
#ifndef RE_ERROR
# define RE_ERROR(RE, CODE, MESSAGE) { (RE)->error_message = (MESSAGE); \
longjmp(*(RE)->error_env, (re->error_code = RE_ERROR_ ## CODE)); }
#endif
#ifndef RE_MALLOC
# define RE_MALLOC(RE, SIZE) re__malloc((RE), (SIZE))
static void* re__malloc(struct re *re, size_t size) {
void *p = malloc(size);
if (!p) {
RE_ERROR(re, NOMEM, "out of memory");
}
return p;
}
#endif
#ifndef RE_CALLOC
# define RE_CALLOC(RE, NMEMB, SIZE) re__calloc((RE), (NMEMB), (SIZE))
static void* re__calloc(struct re *re, size_t nmemb, size_t size) {
void *p = calloc(nmemb, size);
if (p) {
return p;
}
if (re) {
RE_ERROR(re, NOMEM, "out of memory");
}
return p;
}
#endif
#ifndef RE_REALLOC
# define RE_REALLOC(RE, PTR, SIZE) re__realloc((RE), (PTR), (SIZE))
static inline void* re__realloc(struct re *re, void *ptr, size_t size) {
void *p = realloc(ptr, size);
if (!p) {
RE_ERROR(re, NOMEM, "out of memory");
}
return p;
}
#endif
#ifndef RE_FREE
# define RE_FREE(RE, PTR) free(PTR)
#endif
/* arrays */
#define re_array_of(TYPE) \
struct { \
int size; \
int capacity; \
TYPE *at; \
}
#define RE_ARRAY_OF_INITIALISER { 0, 0, 0 }
#define re_array_append(RE, ARRAY, ELEMENT) \
((ARRAY).size++, \
(((ARRAY).size > (ARRAY).capacity) \
? ((ARRAY).at = RE_REALLOC((RE), (ARRAY).at, \
sizeof(*(ARRAY).at) * ((ARRAY).capacity = ((ARRAY).capacity \
? ((ARRAY).capacity * 2) \
: 8)))) \
: (ARRAY).at) \
[(ARRAY).size - 1] = (ELEMENT))
#define re_array_copy(RE, ARRAY) \
{ (ARRAY).size, \
(ARRAY).size, \
memcpy(RE_MALLOC((RE), sizeof((ARRAY).at[0]) * (ARRAY).size), \
(ARRAY).at, \
sizeof((ARRAY).at[0]) * (ARRAY).size) }
#define re_array_release(RE, ARRAY) { \
if ((ARRAY).at) { \
RE_FREE((RE), (ARRAY).at); \
(ARRAY).at = 0; \
} \
}
/* bit sets */
struct RE_BitSet;
typedef struct RE_BitSet RE_BitSet;
struct RE_BitSet {
int inverted;
unsigned char bits[256 / sizeof(unsigned char)];
};
static int re_bitset__includes(RE_BitSet *c, int i) {
if ((i < 0) || (255 < i)) {
return 0;
}
return (c->bits[i / 8] >> (i % 8)) & 1;
}
static int re_bitset_includes(RE_BitSet *c, int i) {
int inc = re_bitset__includes(c, i);
if (c->inverted) {
inc = !inc;
}
return inc;
}
static void re_bitset_add(RE_BitSet *c, int i) {
if ((i < 0) || (255 < i)) {
return;
}
c->bits[i / 8] |= (1 << (i % 8));
}
/* character classes */
static int re_make_char(struct re *re) {
const char *p = re->position;
if (!*p) {
return 0;
}
int c = *p++;
if (('\\' == c) && *p) {
c = *p++;
}
re->position = p;
return c;
}
static RE_BitSet* re_make_class(struct re *re) {
RE_BitSet *c = RE_CALLOC(re, 1, sizeof(RE_BitSet));
int last = -1;
c->inverted = ('^' == *re->position); // -V522
if (c->inverted) {
re->position++;
}
while (*re->position && (']' != *re->position)) {
int this = re->position[0];
if (('-' == this) && (last >= 0) && re->position[1] && (']' != re->position[1])) {
re->position++;
this = re_make_char(re);
do {
re_bitset_add(c, last++);
} while (last <= this);
last = -1;
} else {
this = re_make_char(re);
re_bitset_add(c, this);
last = this;
}
}
return c;
}
/* instructions */
enum { RE_Any, RE_Char, RE_Class, RE_Accept, RE_Jump, RE_Fork, RE_Begin, RE_End, };
struct RE_Insn;
typedef struct RE_Insn RE_Insn;
struct RE_Insn {
int opcode;
long x;
union {
long y;
RE_BitSet *c;
};
union {
RE_Insn *next;
const char *stamp;
};
};
struct RE_Compiled;
typedef struct RE_Compiled RE_Compiled;
/*
struct RE_Compiled
{
int size;
RE_Insn *first;
RE_Insn *last;
};
#define RE_COMPILED_INITIALISER { 0, 0, 0 }
*/
static RE_Compiled re_insn_new(struct re *re, int opc) {
RE_Insn *insn = RE_CALLOC(re, 1, sizeof(RE_Insn));
insn->opcode = opc; // -V522
RE_Compiled insns = { 1, insn, insn };
return insns;
}
static RE_Compiled re_new_Any(struct re *re) {
RE_Compiled insns = re_insn_new(re, RE_Any);
return insns;
}
static RE_Compiled re_new_Char(struct re *re, int c) {
RE_Compiled insns = re_insn_new(re, RE_Char);
insns.first->x = c;
return insns;
}
static RE_Compiled re_new_Class(struct re *re, RE_BitSet *c) {
RE_Compiled insns = re_insn_new(re, RE_Class);
insns.first->c = c;
return insns;
}
static RE_Compiled re_new_Accept(struct re *re) {
RE_Compiled insns = re_insn_new(re, RE_Accept);
return insns;
}
static RE_Compiled re_new_Jump(struct re *re, int x) {
RE_Compiled insns = re_insn_new(re, RE_Jump);
insns.first->x = x;
return insns;
}
static RE_Compiled re_new_Fork(struct re *re, int x, int y) {
RE_Compiled insns = re_insn_new(re, RE_Fork);
insns.first->x = x;
insns.first->y = y;
return insns;
}
static RE_Compiled re_new_Begin(struct re *re) {
RE_Compiled insns = re_insn_new(re, RE_Begin);
return insns;
}
static RE_Compiled re_new_End(struct re *re) {
RE_Compiled insns = re_insn_new(re, RE_End);
return insns;
}
static void re_program_append(RE_Compiled *insns, RE_Compiled tail) {
insns->last->next = tail.first;
insns->last = tail.last;
insns->size += tail.size;
}
static void re_program_prepend(RE_Compiled *insns, RE_Compiled head) {
head.last->next = insns->first;
insns->first = head.first;
insns->size += head.size;
}
static void re_program_free(struct re *re, RE_Compiled *insns) {
int i;
for (i = 0; i < insns->size; ++i) {
switch (insns->first[i].opcode) {
case RE_Class: {
RE_FREE(re, insns->first[i].c);
insns->first[i].c = 0;
break;
}
}
}
RE_FREE(re, insns->first);
insns->first = insns->last = 0;
insns->size = 0;
}
/* compilation */
/*
struct re
{
char *expression;
char *position;
jmp_buf *error_env;
int error_code;
char *error_message;
struct RE_Compiled code;
char **matches;
int nmatches;
};
*/
static RE_Compiled re_compile_expression(struct re *re);
static RE_Compiled re_compile_primary(struct re *re) {
int c = *re->position++;
assert(0 != c);
switch (c) {
case '\\': {
if (*re->position) {
c = *re->position++;
}
break;
}
case '.': {
return re_new_Any(re);
}
case '[': {
RE_BitSet *cc = re_make_class(re);
if (']' != *re->position) {
RE_FREE(re, cc);
RE_ERROR(re, CHARSET, "expected ']' at end of character set");
}
re->position++;
return re_new_Class(re, cc);
};
case '(': {
RE_Compiled insns = re_compile_expression(re);
if (')' != *re->position) {
RE_Insn *insn, *next;
for (insn = insns.first; insn; insn = next) {
next = insn->next;
RE_FREE(re, insn);
}
RE_ERROR(re, SUBEXP, "expected ')' at end of subexpression");
}
re->position++;
return insns;
}
case '{': {
RE_Compiled insns = re_compile_expression(re);
if ('}' != *re->position) {
RE_Insn *insn, *next;
for (insn = insns.first; insn; insn = next) {
next = insn->next;
RE_FREE(re, insn);
}
RE_ERROR(re, SUBMATCH, "expected '}' at end of submatch");
}
re_program_prepend(&insns, re_new_Begin(re));
re_program_append(&insns, re_new_End(re));
re->position++;
return insns;
}
}
return re_new_Char(re, c);
}
static RE_Compiled re_compile_suffix(struct re *re) {
RE_Compiled insns = re_compile_primary(re);
switch (*re->position) {
case '?': {
re->position++;
if ('?' == *re->position) {
re->position++;
re_program_prepend(&insns, re_new_Fork(re, insns.size, 0));
} else {
re_program_prepend(&insns, re_new_Fork(re, 0, insns.size));
}
break;
}
case '*': {
re->position++;
if ('?' == *re->position) {
re->position++;
re_program_prepend(&insns, re_new_Fork(re, insns.size + 1, 0));
} else {
re_program_prepend(&insns, re_new_Fork(re, 0, insns.size + 1));
}
re_program_append(&insns, re_new_Jump(re, -(insns.size + 1)));
break;
}
case '+': {
re->position++;
if ('?' == *re->position) {
re->position++;
re_program_append(&insns, re_new_Fork(re, 0, -(insns.size + 1)));
} else {
re_program_append(&insns, re_new_Fork(re, -(insns.size + 1), 0));
}
break;
}
}
return insns;
}
static RE_Compiled re_compile_sequence(struct re *re) {
if (!*re->position) {
return re_new_Accept(re);
}
RE_Compiled head = re_compile_suffix(re);
while (*re->position && !strchr("|)}>", *re->position)) {
re_program_append(&head, re_compile_suffix(re));
}
if (!*re->position) {
re_program_append(&head, re_new_Accept(re));
}
return head;
}
static RE_Compiled re_compile_expression(struct re *re) {
RE_Compiled head = re_compile_sequence(re);
while ('|' == *re->position) {
re->position++;
RE_Compiled tail = re_compile_sequence(re);
re_program_append(&head, re_new_Jump(re, tail.size));
re_program_prepend(&head, re_new_Fork(re, 0, head.size));
re_program_append(&head, tail);
}
return head;
}
static RE_Compiled re_compile(struct re *re) {
jmp_buf env;
RE_Compiled insns = RE_COMPILED_INITIALISER;
re->error_env = &env;
if (setjmp(env)) { /* syntax error */
return insns;
}
insns = re_compile_expression(re);
re_array_of(RE_Insn) program = RE_ARRAY_OF_INITIALISER;
RE_Insn *insn, *next;
for (insn = insns.first; insn; insn = next) {
re_array_append(re, program, *insn);
next = insn->next;
RE_FREE(re, insn);
}
#if 0
int i;
for (i = 0; i < program.size; ++i) {
RE_Insn *insn = &program.at[i];
printf("%03i ", i);
switch (insn->opcode) {
case RE_Any:
printf("Any\n");
break;
case RE_Char:
printf("Char %li\n", insn->x);
break;
case RE_Class: {
printf("Class ");
{
RE_BitSet *c = insn->c;
int i;
putchar('[');
if (c->inverted) {
putchar('^');
}
for (i = 0; i < 256; ++i)
if (re_bitset__includes(c, i)) {
switch (i) {
case '\a':
printf("\\a");
break;
case '\b':
printf("\\b");
break;
case '\t':
printf("\\t");
break;
case '\n':
printf("\\n");
break;
case '\v':
printf("\\v");
break;
case '\f':
printf("\\f");
break;
case '\r':
printf("\\r");
break;
case '\\':
printf("\\\\");
break;
case ']':
printf("\\]");
break;
case '^':
printf("\\^");
break;
case '-':
printf("\\-");
break;
default:
if (isprint(i)) {
putchar(i);
} else {
printf("\\x%02x", i);
}
}
}
putchar(']');
}
putchar('\n');
break;
}
case RE_Accept:
printf("Accept\n");
break;
case RE_Jump:
printf("Jump %li -> %03li\n", insn->x, i + 1 + insn->x);
break;
case RE_Fork:
printf("Fork %li %li -> %03li %03li\n", insn->x, insn->y, i + 1 + insn->x, i + 1 + insn->y);
break;
case RE_Begin:
printf("Begin\n");
break;
case RE_End:
printf("End\n");
break;
default:
printf("?%i\n", insn->opcode);
break;
}
}
#endif
assert(program.size == insns.size);
insns.first = program.at;
insns.last = insns.first + insns.size;
return insns;
}
/* submatch recording */
typedef re_array_of(const char*) re_array_of_charp;
struct RE_Submatches;
typedef struct RE_Submatches RE_Submatches;
struct RE_Submatches {
int refs;
re_array_of_charp beginnings;
re_array_of_charp endings;
};
static RE_Submatches* re_submatches_copy(struct re *re, RE_Submatches *orig) {
RE_Submatches *subs = RE_CALLOC(re, 1, sizeof(RE_Submatches));
if (orig) {
subs->beginnings = (re_array_of_charp) re_array_copy(re, orig->beginnings); // -V522
subs->endings = (re_array_of_charp) re_array_copy(re, orig->endings);
}
return subs;
}
static void re_submatches_free(struct re *re, RE_Submatches *subs) {
assert(subs);
assert(!subs->refs);
re_array_release(re, subs->beginnings);
re_array_release(re, subs->endings);
RE_FREE(re, subs);
}
static inline RE_Submatches* re_submatches_link(RE_Submatches *subs) {
if (subs) {
subs->refs++;
}
return subs;
}
static inline void re_submatches_unlink(struct re *re, RE_Submatches *subs) {
if (subs && (0 == --(subs->refs))) {
re_submatches_free(re, subs);
}
}
/* matching */
struct RE_Thread;
typedef struct RE_Thread RE_Thread;
struct RE_Thread {
RE_Insn *pc;
RE_Submatches *submatches;
};
struct RE_ThreadList;
typedef struct RE_ThreadList RE_ThreadList;
struct RE_ThreadList {
int size;
RE_Thread *at;
};
static inline RE_Thread re_thread(RE_Insn *pc, RE_Submatches *subs) {
return (RE_Thread) {
pc, subs
};
}
static void re_thread_schedule(
struct re *re, RE_ThreadList *threads, RE_Insn *pc, const char *sp,
RE_Submatches *subs
) {
if (pc->stamp == sp) {
return;
}
pc->stamp = sp;
switch (pc->opcode) {
case RE_Jump:
re_thread_schedule(re, threads, pc + 1 + pc->x, sp, subs);
return;
case RE_Fork:
re_thread_schedule(re, threads, pc + 1 + pc->x, sp, subs);
re_thread_schedule(re, threads, pc + 1 + pc->y, sp, subs);
return;
case RE_Begin:
subs = re_submatches_copy(re, subs);
re_array_append(re, subs->beginnings, sp); // -V522
re_thread_schedule(re, threads, pc + 1, sp, subs);
if (!subs->refs) {
re_submatches_free(re, subs);
}
return;
case RE_End: {
subs = re_submatches_copy(re, subs);
# if 0 /* non-nesting groups: ab{cd{ef}gh}ij => {cdef} {efgh} */
re_array_append(re, subs->endings, sp);
# else /* nesting groups: ab{cd{ef}gh}ij => {cdefgh} {ef} */
while (subs->endings.size < subs->beginnings.size) re_array_append(re, subs->endings, 0);
int i;
for (i = subs->endings.size; i--; ) {
if (!subs->endings.at[i]) {
subs->endings.at[i] = sp;
break;
}
}
# endif
re_thread_schedule(re, threads, pc + 1, sp, subs);
if (!subs->refs) {
re_submatches_free(re, subs);
}
return;
}
}
threads->at[threads->size++] = re_thread(pc, re_submatches_link(subs));
}
static int re_program_run(struct re *re, const char *input, char const ***saved, int *nsaved) {
int matched = RE_ERROR_NOMATCH;
if (!re) {
return matched;
}
RE_Submatches *submatches = 0;
RE_ThreadList a = { 0, 0 }, b = { 0, 0 }, *here = &a, *next = &b;
const char *sp = input;
re->position = 0;
jmp_buf env;
re->error_env = &env;
if (setjmp(env)) { /* out of memory */
matched = re->error_code;
goto bailout;
}
a.at = RE_CALLOC(re, re->code.size, sizeof(RE_Thread));
b.at = RE_CALLOC(re, re->code.size, sizeof(RE_Thread));
re_thread_schedule(re, here, re->code.first, input, 0);
{
int i;
for (i = 0; i < re->code.size; ++i) {
re->code.first[i].stamp = 0;
}
}
for (sp = input; here->size; ++sp) {
int i;
for (i = 0; i < here->size; ++i) {
RE_Thread t = here->at[i];
switch (t.pc->opcode) {
case RE_Any: {
if (*sp) {
re_thread_schedule(re, next, t.pc + 1, sp + 1, t.submatches);
}
break;
}
case RE_Char: {
if (*sp == t.pc->x) {
re_thread_schedule(re, next, t.pc + 1, sp + 1, t.submatches);
}
break;
}
case RE_Class: {
if (re_bitset_includes(t.pc->c, *sp)) {
re_thread_schedule(re, next, t.pc + 1, sp + 1, t.submatches);
}
break;
}
case RE_Accept: {
matched = sp - input;
re_submatches_unlink(re, submatches);
submatches = re_submatches_link(t.submatches);
while (i < here->size) re_submatches_unlink(re, here->at[i++].submatches);
goto nextchar;
}
default:
RE_ERROR(re, ENGINE, "illegal instruction in compiled regular expression (please report this bug)");
}
re_submatches_unlink(re, t.submatches);
}
nextchar:
;
RE_ThreadList *tmp = here;
here = next;
next = tmp;
next->size = 0;
if (!*sp) {
break;
}
}
bailout:
re->position = sp;
{
int i;
for (i = 0; i < here->size; ++i) {
re_submatches_unlink(re, here->at[i].submatches);
}
}
RE_FREE(re, a.at);
RE_FREE(re, b.at);
if (submatches) {
if (saved && nsaved && (matched >= 0)) {
assert(submatches->beginnings.size == submatches->endings.size);
*nsaved = submatches->beginnings.size * 2;
*saved = RE_CALLOC(re, *nsaved, sizeof(char*));
int i;
for (i = 0; i < *nsaved; i += 2) {
(*saved)[i + 0] = submatches->beginnings.at[i / 2];
(*saved)[i + 1] = submatches->endings.at[i / 2];
}
}
re_submatches_unlink(re, submatches);
}
return matched;
}
/* public interface */
struct re* iwre_new(const char *expr) {
struct re *re = RE_CALLOC(0, 1, sizeof(struct re));
if (re) {
re->expression = expr;
}
return re;
}
int iwre_match(struct re *re, const char *input) {
RE_FREE(re, re->matches);
re->matches = 0;
re->nmatches = 0;
if (!re->expression) {
return 0;
}
if (!re->code.size) {
re->position = re->expression;
re->error_code = 0;
re->error_message = 0;
re->code = re_compile(re);
if (re->error_code) {
return re->error_code;
}
re->position = 0;
}
return re_program_run(re, input, &re->matches, &re->nmatches);
}
void iwre_release(struct re *re) {
RE_FREE(re, re->matches);
if (re->code.first) {
re_program_free(re, &re->code);
}
memset(re, 0, sizeof(*re));
}
void iwre_reset(struct re *re, const char *expression) {
iwre_release(re);
re->expression = expression;
}
void iwre_free(struct re *re) {
iwre_release(re);
RE_FREE(0, re);
}
/* utility */
static int re_digit(int c, int base) {
if ((c >= '0') && (c <= '9')) {
c -= '0';
} else if ((c >= 'A') && (c <= 'Z')) {
c -= ('A' - 10);
} else if ((c >= 'a') && (c <= 'z')) {
c -= ('a' - 10);
} else {
return -1;
}
if (c >= base) {
return -1;
}
return c;
}
static int re_byte(char **sp, int least, int most, int base, int liberal) {
int c = 0;
char *s = *sp;
while (s - *sp < most) {
int d = re_digit(*s, base);
if (d < 0) {
break;
}
++s;
c = c * base + d;
}
if (s - *sp < least) {
if (liberal) {
return (*sp)[-1];
}
--*sp;
return '\\';
}
*sp = s;
return c;
}
static int re_log2floor(unsigned int n) {
if (!n) {
return 0;
}
int b = 1;
# define _do(x) if (n >= (1U << x)) (b += x), (n >>= x)
_do(16);
_do(8);
_do(4);
_do(2);
_do(1);
# undef _do
return b;
}
static void re_escape_utf8(char **sp, unsigned int c) {
char *s = *sp;
if (c < 128) {
*s++ = c;
} else { /* this is good for up to 36 bits of c, which proves that Gordon Bell was right all along */
int n = re_log2floor(c) / 6;
int m = 6 * n;
*s++ = (0xff << (7 - n)) + (c >> m);
while ((m -= 6) >= 0) *s++ = 0x80 + ((c >> m) & 0x3F);
}
*sp = s;
}
char* iwre_escape(char *s, int liberal) {
char *in = s, *out = s;
int c;
while ((c = *in++)) {
int u = 0;
if ('\\' == c) {
c = *in++;
switch (c) {
case '0':
case '1':
c = re_byte(&in, 1, 3, 8, liberal);
break;
case '\\':
//c = '\\';
break;
case 'a':
c = '\a';
break;
case 'b':
c = '\b';
break;
case 'f':
c = '\f';
break;
case 'n':
c = '\n';
break;
case 'r':
c = '\r';
break;
case 't':
c = '\t';
break;
case 'U':
c = re_byte(&in, 8, 8, 16, liberal);
u = 1;
break;
case 'u':
c = re_byte(&in, 4, 4, 16, liberal);
u = 1;
break;
case 'v':
c = '\v';
break;
case 'x':
c = re_byte(&in, 1, 2, 16, liberal);
break;
default: {
if (!liberal) { /* pass escape character through unharmed */
--in;
c = '\\';
}
break;
}
}
}
if (u) {
re_escape_utf8(&out, c);
} else {
*out++ = c;
}
}
assert(out <= in);
*out = 0;
return s;
}
/* testing */
#ifdef LWRE_TEST
#include <stdio.h>
/* echo stdin to stout with ANSI terminal escapes to turn every number red */
int main(int argc, char **argv) {
static struct re re = RE_INITIALISER("(.*?{[0-9]+})*");
char buf[1024];
while (fgets(buf, sizeof(buf), stdin)) {
int n;
if (((n = lwre_match(&re, buf)) < 0) && (RE_ERROR_NOMATCH != n)) {
fprintf(stderr, "%i %ss: %s\n", n, re.error_message, re.position);
break;
} else {
char *p = buf;
int n = 0;
while (*p) {
if ((n < re.nmatches) && (p == re.matches[n])) {
if (n & 1) {
printf("\033[0m"); /* end of match: clear all attributes */
} else {
printf("\033[1;31m"); /* start of match: bold and foreground red */
}
++n;
}
putchar(*p++);
}
}
}
lwre_release(&re);
return 0;
}
#endif /* REGEXP_TEST */
+75
View File
@@ -0,0 +1,75 @@
#pragma once
#ifndef IWRE_H
#define IWRE_H
/**************************************************************************************************
* IOWOW library
*
* MIT License
*
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*************************************************************************************************/
#include <setjmp.h>
#include "basedefs.h"
struct RE_Insn;
struct RE_Compiled {
int size;
struct RE_Insn *first;
struct RE_Insn *last;
};
#define RE_COMPILED_INITIALISER { 0, 0, 0 }
struct re {
const char *expression;
const char *position;
jmp_buf *error_env;
int error_code;
char *error_message;
struct RE_Compiled code;
const char **matches;
int nmatches;
#ifdef RE_EXTRA_MEMBERS
RE_MEMBERS
#endif
};
#define RE_INITIALISER(EXPR) { (EXPR), 0, 0, 0, 0, RE_COMPILED_INITIALISER, 0, 0 }
#define RE_ERROR_NONE 0
#define RE_ERROR_NOMATCH -1
#define RE_ERROR_NOMEM -2
#define RE_ERROR_CHARSET -3
#define RE_ERROR_SUBEXP -4
#define RE_ERROR_SUBMATCH -5
#define RE_ERROR_ENGINE -6
IW_EXPORT IW_ALLOC struct re* iwre_new(const char *expression);
IW_EXPORT int iwre_match(struct re *re, const char *input);
IW_EXPORT void iwre_release(struct re *re);
IW_EXPORT void iwre_reset(struct re *re, const char *expression);
IW_EXPORT void iwre_free(struct re *re);
IW_EXPORT char* iwre_escape(char *string, int liberal);
#endif /* __lwre_h_ */
+15 -12
View File
@@ -2,7 +2,7 @@
#include <string.h>
#include <stdio.h>
#define CHUNK_SIZE 64
#define CHUNK_SIZE 64
#define TOTAL_LEN_LEN 8
/*
@@ -29,8 +29,8 @@ struct buffer_state {
const uint8_t *p;
size_t len;
size_t total_len;
int single_one_delivered; /* bool */
int total_len_delivered; /* bool */
int single_one_delivered; /* bool */
int total_len_delivered; /* bool */
};
IW_INLINE uint32_t right_rot(uint32_t value, unsigned int count) {
@@ -91,7 +91,7 @@ static int calc_chunk(uint8_t chunk[CHUNK_SIZE], struct buffer_state *state) {
chunk += left;
/* Storing of len * 8 as a big endian 64-bit without overflow. */
chunk[7] = (uint8_t)(len << 3);
chunk[7] = (uint8_t) (len << 3);
len >>= 5;
for (i = 6; i >= 0; i--) {
chunk[i] = (uint8_t) len;
@@ -116,7 +116,8 @@ static int calc_chunk(uint8_t chunk[CHUNK_SIZE], struct buffer_state *state) {
void iwsha256(const void *input, size_t len, uint8_t hash_out[32]) {
/*
* Note 1: All integers (expect indexes) are 32-bit unsigned integers and addition is calculated modulo 2^32.
* Note 2: For each round, there is one round constant k[i] and one entry in the message schedule array w[i], 0 = i = 63
* Note 2: For each round, there is one round constant k[i] and one entry in the message schedule array w[i], 0 = i =
* 63
* Note 3: The compression function uses 8 working variables, a through h
* Note 4: Big-endian convention is used when expressing the constants in this pseudocode,
* and when parsing message block data from bytes to words, for example,
@@ -168,13 +169,15 @@ void iwsha256(const void *input, size_t len, uint8_t hash_out[32]) {
for (j = 0; j < 16; j++) {
if (i == 0) {
w[j] = (uint32_t) p[0] << 24 | (uint32_t) p[1] << 16 |
(uint32_t) p[2] << 8 | (uint32_t) p[3];
w[j] = (uint32_t) p[0] << 24 | (uint32_t) p[1] << 16
| (uint32_t) p[2] << 8 | (uint32_t) p[3];
p += 4;
} else {
/* Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array: */
const uint32_t s0 = right_rot(w[(j + 1) & 0xf], 7) ^ right_rot(w[(j + 1) & 0xf], 18) ^ (w[(j + 1) & 0xf] >> 3);
const uint32_t s1 = right_rot(w[(j + 14) & 0xf], 17) ^ right_rot(w[(j + 14) & 0xf], 19) ^ (w[(j + 14) & 0xf] >> 10);
const uint32_t s0
= right_rot(w[(j + 1) & 0xf], 7) ^ right_rot(w[(j + 1) & 0xf], 18) ^ (w[(j + 1) & 0xf] >> 3);
const uint32_t s1
= right_rot(w[(j + 14) & 0xf], 17) ^ right_rot(w[(j + 14) & 0xf], 19) ^ (w[(j + 14) & 0xf] >> 10);
w[j] = w[j] + s0 + w[(j + 9) & 0xf] + s1;
}
const uint32_t s1 = right_rot(ah[4], 6) ^ right_rot(ah[4], 11) ^ right_rot(ah[4], 25);
@@ -203,9 +206,9 @@ void iwsha256(const void *input, size_t len, uint8_t hash_out[32]) {
/* Produce the final hash value (big-endian): */
for (i = 0, j = 0; i < 8; i++) {
hash_out[j++] = (uint8_t)(h[i] >> 24);
hash_out[j++] = (uint8_t)(h[i] >> 16);
hash_out[j++] = (uint8_t)(h[i] >> 8);
hash_out[j++] = (uint8_t) (h[i] >> 24);
hash_out[j++] = (uint8_t) (h[i] >> 16);
hash_out[j++] = (uint8_t) (h[i] >> 8);
hash_out[j++] = (uint8_t) h[i];
}
}
+51 -50
View File
@@ -1,30 +1,30 @@
/*
Copyright (c) 2011, Willem-Hendrik Thiart
Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
All rights reserved.
Copyright (c) 2011, Willem-Hendrik Thiart
Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* The names of its contributors may not be used to endorse or promote
* The names of its contributors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL WILLEM-HENDRIK THIART BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL WILLEM-HENDRIK THIART BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "iwstree.h"
#include "iwlog.h"
@@ -35,17 +35,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdint.h>
typedef struct tree_node_s {
struct tree_node_s *left;
struct tree_node_s *right;
struct tree_node_s *left;
struct tree_node_s *right;
void *key;
void *value;
} tree_node_t;
struct tree_iter_s {
IWSTREE *st; /**< Owner tree */
int spos; /**< Position of top element stack */
int slen; /**< Max number of elements in stack */
IWSTREE *st; /**< Owner tree */
int spos; /**< Position of top element stack */
int slen; /**< Max number of elements in stack */
tree_node_t **stack; /**< Bottom of iterator stack */
};
@@ -54,14 +54,14 @@ int iwstree_str_cmp(const void *o1, const void *o2) {
}
int iwstree_uint64_cmp(const void *o1, const void *o2) {
uint64_t v1 = *(uint64_t *) o1;
uint64_t v2 = *(uint64_t *) o2;
uint64_t v1 = *(uint64_t*) o1;
uint64_t v2 = *(uint64_t*) o2;
return v1 > v2 ? 1 : v1 < v2 ? -1 : 0;
}
int iwstree_int64_cmp(const void *o1, const void *o2) {
int64_t v1 = *(int64_t *) o1;
int64_t v2 = *(int64_t *) o2;
int64_t v1 = *(int64_t*) o1;
int64_t v2 = *(int64_t*) o2;
return v1 > v2 ? 1 : v1 < v2 ? -1 : 0;
}
@@ -69,8 +69,9 @@ static int _cmp_default(const void *k1, const void *k2) {
return k1 < k2 ? -1 : k1 > k2 ? 1 : 0;
}
IWSTREE *iwstree_create(int (*cmp)(const void *, const void *),
void (*kvfree)(void *, void *)) {
IWSTREE* iwstree_create(
int (*cmp)(const void*, const void*),
void (*kvfree)(void*, void*)) {
IWSTREE *st;
st = malloc(sizeof(IWSTREE));
if (!st) {
@@ -108,7 +109,7 @@ void iwstree_destroy(IWSTREE *st) {
free(st);
}
static tree_node_t *_init_node(void *key, void *value) {
static tree_node_t* _init_node(void *key, void *value) {
tree_node_t *n;
n = malloc(sizeof(tree_node_t));
if (!n) {
@@ -141,13 +142,13 @@ static void _rotate_left(tree_node_t **pa) {
/**
* bring this value to the top
* */
static tree_node_t *_splay(
IWSTREE *st,
int update_if_not_found,
static tree_node_t* _splay(
IWSTREE *st,
int update_if_not_found,
tree_node_t **gpa,
tree_node_t **pa,
tree_node_t **child,
const void *key) {
const void *key) {
int cmp;
tree_node_t *next;
@@ -194,22 +195,22 @@ static tree_node_t *_splay(
assert(gpa);
/* zig zig left */
if ((*pa)->left == next && (*gpa)->left == *pa) {
if (((*pa)->left == next) && ((*gpa)->left == *pa)) {
_rotate_right(pa);
_rotate_right(gpa);
}
/* zig zig right */
else if ((*pa)->right == next && (*gpa)->right == *pa) {
else if (((*pa)->right == next) && ((*gpa)->right == *pa)) {
_rotate_left(pa);
_rotate_left(gpa);
}
/* zig zag right */
else if ((*pa)->right == next && (*gpa)->left == *pa) {
else if (((*pa)->right == next) && ((*gpa)->left == *pa)) {
_rotate_left(pa);
_rotate_right(gpa);
}
/* zig zag left */
else if ((*pa)->left == next && (*gpa)->right == *pa) {
else if (((*pa)->left == next) && ((*gpa)->right == *pa)) {
_rotate_right(pa);
_rotate_left(gpa);
}
@@ -220,7 +221,7 @@ int iwstree_is_empty(IWSTREE *st) {
return st->root == 0;
}
void *iwstree_remove(IWSTREE *st, const void *key) {
void* iwstree_remove(IWSTREE *st, const void *key) {
tree_node_t *root, *tmp;
void *val;
@@ -237,8 +238,8 @@ void *iwstree_remove(IWSTREE *st, const void *key) {
} else {
tmp = root->right;
st->root = root->left;
_splay(st, 1, 0, 0, (tree_node_t **) &st->root, key);
((tree_node_t *) st->root)->right = tmp;
_splay(st, 1, 0, 0, (tree_node_t**) &st->root, key);
((tree_node_t*) st->root)->right = tmp;
}
st->count--;
assert(root != st->root);
@@ -249,8 +250,8 @@ void *iwstree_remove(IWSTREE *st, const void *key) {
/**
* get this item referred to by key. Slap it as root.
*/
void *iwstree_get(IWSTREE *st, const void *key) {
tree_node_t *node = _splay(st, 0, 0, 0, (tree_node_t **) &st->root, key);
void* iwstree_get(IWSTREE *st, const void *key) {
tree_node_t *node = _splay(st, 0, 0, 0, (tree_node_t**) &st->root, key);
return node ? node->value : 0;
}
@@ -258,8 +259,8 @@ int iwstree_count(IWSTREE *st) {
return st->count;
}
void *iwstree_peek(IWSTREE *st) {
return st->root ? ((tree_node_t *) st->root)->value : 0;
void* iwstree_peek(IWSTREE *st) {
return st->root ? ((tree_node_t*) st->root)->value : 0;
}
static iwrc _iwstree_put(IWSTREE *st, void *key, void *value, bool overwrite) {
@@ -273,8 +274,8 @@ static iwrc _iwstree_put(IWSTREE *st, void *key, void *value, bool overwrite) {
st->count++;
return 0;
}
n = _splay(st, 1, 0, 0, (tree_node_t **) &st->root, key);
cmp = st->cmp(((tree_node_t *) st->root)->key, key);
n = _splay(st, 1, 0, 0, (tree_node_t**) &st->root, key);
cmp = st->cmp(((tree_node_t*) st->root)->key, key);
if (cmp != 0) {
n = _init_node(key, value);
if (!n) {
@@ -333,7 +334,7 @@ iwrc iwstree_visit(IWSTREE *st, IWSTREE_VISITOR visitor, void *op) {
#define _ITER_STACK_AUNIT 32
static iwrc _iter_push(IWSTREE_ITER *iter, tree_node_t *n) {
static iwrc _iter_push(IWSTREE_ITER *iter, tree_node_t *n) {
if (iter->spos + 1 > iter->slen) {
void *np = realloc(iter->stack, (iter->slen + _ITER_STACK_AUNIT) * sizeof(*iter->stack));
if (!np) {
@@ -347,7 +348,7 @@ static iwrc _iter_push(IWSTREE_ITER *iter, tree_node_t *n) {
return 0;
}
static tree_node_t *_iter_pop(IWSTREE_ITER *iter) {
static tree_node_t* _iter_pop(IWSTREE_ITER *iter) {
if (iter->spos < 1) {
return 0;
}
+28 -28
View File
@@ -3,32 +3,32 @@
#define IWSTREE_H
/*
Copyright (c) 2011, Willem-Hendrik Thiart
Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
All rights reserved.
Copyright (c) 2011, Willem-Hendrik Thiart
Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* The names of its contributors may not be used to endorse or promote
* The names of its contributors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL WILLEM-HENDRIK THIART BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL WILLEM-HENDRIK THIART BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "basedefs.h"
#include <stdbool.h>
@@ -37,16 +37,16 @@ IW_EXTERN_C_START
typedef struct {
void *root;
int (*cmp)(const void *, const void *);
void (*kvfree)(void *, void *);
int (*cmp)(const void*, const void*);
void (*kvfree)(void*, void*);
int count;
} IWSTREE;
typedef struct _IWSTREE_ITER {
IWSTREE *st; /**< Owner tree */
int spos; /**< Position of top element stack */
int slen; /**< Max number of elements in stack */
void **stack; /**< Bottom of iterator stack */
int spos; /**< Position of top element stack */
int slen; /**< Max number of elements in stack */
void **stack; /**< Bottom of iterator stack */
} IWSTREE_ITER;
typedef bool (*IWSTREE_VISITOR)(void *key, void *val, void *op, iwrc *rcp);
@@ -58,10 +58,10 @@ typedef bool (*IWSTREE_VISITOR)(void *key, void *val, void *op, iwrc *rcp);
* @param kvfree Optional `(key, value)` free function
* @return IWSTREE* or NULL if memory allocation failed
*/
IW_EXPORT IWSTREE *iwstree_create(
int (*cmp)(const void *, const void *),
void (*kvfree)(void *, void *)
);
IW_EXPORT IW_ALLOC IWSTREE *iwstree_create(
int (*cmp)(const void*, const void*),
void (*kvfree)(void*, void*)
);
IW_EXPORT int iwstree_str_cmp(const void *o1, const void *o2);
+123 -36
View File
@@ -1,9 +1,12 @@
#include "iwstw.h"
#include "iwth.h"
#include "iwlog.h"
#include "iwp.h"
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
struct _TASK {
iwstw_task_f fn;
@@ -14,19 +17,25 @@ struct _TASK {
struct _IWSTW {
struct _TASK *head;
struct _TASK *tail;
char *thread_name;
pthread_mutex_t mtx;
pthread_barrier_t brr;
pthread_cond_t cond;
pthread_t thr;
int cnt;
int queue_limit;
pthread_cond_t cond;
pthread_cond_t cond_queue;
pthread_t thr;
int cnt;
int queue_limit;
bool queue_blocking;
bool queue_blocked;
volatile bool shutdown;
};
void *worker_fn(void *op) {
static void* _worker_fn(void *op) {
struct _IWSTW *stw = op;
assert(stw);
pthread_barrier_wait(&stw->brr);
if (stw->thread_name) {
iwp_set_current_thread_name(stw->thread_name);
}
while (true) {
void *arg;
@@ -38,8 +47,8 @@ void *worker_fn(void *op) {
fn = h->fn;
arg = h->arg;
stw->head = h->next;
if (stw->tail == h) {
stw->tail = stw->head;
if (stw->head == 0) {
stw->tail = 0;
}
--stw->cnt;
free(h);
@@ -52,11 +61,18 @@ void *worker_fn(void *op) {
pthread_mutex_lock(&stw->mtx);
if (stw->head) {
if (stw->queue_blocked && stw->cnt < stw->queue_limit) {
stw->queue_blocked = false;
pthread_cond_broadcast(&stw->cond_queue);
}
pthread_mutex_unlock(&stw->mtx);
continue;
} else if (stw->shutdown) {
pthread_mutex_unlock(&stw->mtx);
break;
} else if (stw->queue_blocked && stw->cnt < stw->queue_limit) {
stw->queue_blocked = false;
pthread_cond_broadcast(&stw->cond_queue);
}
pthread_cond_wait(&stw->cond, &stw->mtx);
pthread_mutex_unlock(&stw->mtx);
@@ -64,15 +80,20 @@ void *worker_fn(void *op) {
return 0;
}
void iwstw_shutdown(IWSTW *stwp, bool wait_for_all) {
iwrc iwstw_shutdown(IWSTW *stwp, bool wait_for_all) {
if (!stwp || !*stwp) {
return;
return 0;
}
IWSTW stw = *stwp;
pthread_mutex_lock(&stw->mtx);
if (stw->shutdown) {
pthread_mutex_unlock(&stw->mtx);
return;
return 0;
}
pthread_t st = pthread_self();
if (stw->thr == pthread_self()) {
iwlog_error("iwstw | Thread iwstw_shutdown() from self thread: %lu", (unsigned long) st);
return IW_ERROR_ASSERTION;
}
if (!wait_for_all) {
struct _TASK *t = stw->head;
@@ -87,17 +108,26 @@ void iwstw_shutdown(IWSTW *stwp, bool wait_for_all) {
}
stw->shutdown = true;
pthread_cond_broadcast(&stw->cond);
pthread_mutex_unlock(&stw->mtx);
int rci = pthread_join(stw->thr, 0);
if (rci) {
iwrc rc = iwrc_set_errno(IW_ERROR_THREADING_ERRNO, rci);
iwlog_ecode_error3(rc);
if (stw->queue_blocking) {
pthread_cond_broadcast(&stw->cond_queue);
}
pthread_barrier_destroy(&stw->brr);
pthread_mutex_unlock(&stw->mtx);
pthread_join(stw->thr, 0);
pthread_cond_destroy(&stw->cond);
pthread_mutex_destroy(&stw->mtx);
free(stw->thread_name);
free(stw);
*stwp = 0;
return 0;
}
int iwstw_queue_size(IWSTW stw) {
int res = 0;
pthread_mutex_lock(&stw->mtx);
res = stw->cnt;
pthread_mutex_unlock(&stw->mtx);
return res;
}
iwrc iwstw_schedule(IWSTW stw, iwstw_task_f fn, void *arg) {
@@ -121,11 +151,23 @@ iwrc iwstw_schedule(IWSTW stw, iwstw_task_f fn, void *arg) {
pthread_mutex_unlock(&stw->mtx);
goto finish;
}
if (stw->queue_limit && stw->cnt + 1 > stw->queue_limit) {
rc = IW_ERROR_OVERFLOW;
pthread_mutex_unlock(&stw->mtx);
goto finish;
while (stw->queue_limit && (stw->cnt + 1 > stw->queue_limit)) {
if (stw->queue_blocking) {
if (stw->shutdown) {
rc = IW_ERROR_INVALID_STATE;
pthread_mutex_unlock(&stw->mtx);
goto finish;
}
stw->queue_blocked = true;
pthread_cond_wait(&stw->cond_queue, &stw->mtx);
} else {
rc = IW_ERROR_OVERFLOW;
pthread_mutex_unlock(&stw->mtx);
goto finish;
}
}
if (stw->tail) {
stw->tail->next = task;
stw->tail = task;
@@ -144,10 +186,56 @@ finish:
return rc; // NOLINT (clang-analyzer-unix.Malloc)
}
iwrc iwstw_start(int queue_limit, IWSTW *stwp_out) {
iwrc iwstw_schedule_empty_only(IWSTW stw, iwstw_task_f fn, void *arg, bool *out_scheduled) {
if (!stw || !fn || !out_scheduled) {
return IW_ERROR_INVALID_ARGS;
}
*out_scheduled = false;
iwrc rc = 0;
struct _TASK *task = malloc(sizeof(*task));
RCA(task, finish);
*task = (struct _TASK) {
.fn = fn,
.arg = arg
};
int rci = pthread_mutex_lock(&stw->mtx);
if (rci) {
rc = iwrc_set_errno(IW_ERROR_THREADING_ERRNO, errno);
goto finish;
}
if (stw->shutdown) {
rc = IW_ERROR_INVALID_STATE;
pthread_mutex_unlock(&stw->mtx);
goto finish;
}
if (stw->head) {
pthread_mutex_unlock(&stw->mtx);
goto finish;
}
*out_scheduled = true;
stw->head = task;
stw->tail = task;
++stw->cnt;
pthread_cond_broadcast(&stw->cond);
pthread_mutex_unlock(&stw->mtx);
finish:
if (rc) {
free(task);
}
return rc; // NOLINT (clang-analyzer-unix.Malloc)
}
iwrc iwstw_start(const char *thread_name, int queue_limit, bool queue_blocking, IWSTW *out_stw) {
if (queue_limit < 0 || !out_stw) {
return IW_ERROR_INVALID_ARGS;
}
if (thread_name && strlen(thread_name) > 15) {
return IW_ERROR_INVALID_ARGS;
}
struct _IWSTW *stw = malloc(sizeof(*stw));
if (!stw) {
*stwp_out = 0;
*out_stw = 0;
return iwrc_set_errno(IW_ERROR_ALLOC, errno);
}
int rci;
@@ -155,28 +243,27 @@ iwrc iwstw_start(int queue_limit, IWSTW *stwp_out) {
*stw = (struct _IWSTW) {
.queue_limit = queue_limit,
.mtx = PTHREAD_MUTEX_INITIALIZER,
.cond = PTHREAD_COND_INITIALIZER
.cond = PTHREAD_COND_INITIALIZER,
.cond_queue = PTHREAD_COND_INITIALIZER,
.queue_blocking = queue_blocking
};
rci = pthread_barrier_init(&stw->brr, 0, 2);
if (thread_name) {
stw->thread_name = strdup(thread_name);
}
rci = pthread_create(&stw->thr, 0, _worker_fn, stw);
if (rci) {
rc = iwrc_set_errno(IW_ERROR_THREADING_ERRNO, errno);
goto finish;
}
rci = pthread_create(&stw->thr, 0, worker_fn, stw);
if (rci) {
rc = iwrc_set_errno(IW_ERROR_THREADING_ERRNO, errno);
pthread_barrier_destroy(&stw->brr);
goto finish;
}
pthread_barrier_wait(&stw->brr);
finish:
if (rc) {
*stwp_out = 0;
*out_stw = 0;
free(stw->thread_name);
free(stw);
} else {
*stwp_out = stw;
*out_stw = stw;
}
return 0;
}
+21 -8
View File
@@ -9,7 +9,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -35,7 +35,7 @@
IW_EXTERN_C_START
struct _IWSTW;
typedef struct _IWSTW *IWSTW;
typedef struct _IWSTW*IWSTW;
/**
* @brief Task to execute
@@ -43,33 +43,46 @@ typedef struct _IWSTW *IWSTW;
typedef void (*iwstw_task_f)(void *arg);
/**
* @brief Start single thread worker.
* @brief Starts a single thread worker.
* Function will block until start of worker thread.
*
* @param queue_limit Max length of pending tasks queue. Unlimited if zero.
* @param queue_blocking If true iwstw_schedule will block when queue reached its limit.
* @param[out] stwp_out Pointer to worker handler to be initialized.
*/
IW_EXPORT iwrc iwstw_start(int queue_limit, IWSTW *stwp_out);
IW_EXPORT iwrc iwstw_start(const char *thread_name, int queue_limit, bool queue_blocking, IWSTW *out_stw);
/**
* @brief Shutdowns worker and disposes all resources.
* Function will wait until current task completes or
* wait for all pednding tasks if `wait_for_all` is set to `true`.
* wait for all enqueued tasks if `wait_for_all` is set to `true`.
* No new tasks will be accepted during `iwstw_shutdown` call.
*
* @param stw Pointer to worker handler which should be destroyed.
* @param wait_for_all If true worker will wait for all pending tasks before shutdown.
* @param wait_for_all If true worker will wait for completion of all enqueued tasks before shutdown.
*/
IW_EXPORT void iwstw_shutdown(IWSTW *stwp, bool wait_for_all);
IW_EXPORT iwrc iwstw_shutdown(IWSTW *stwp, bool wait_for_all);
/**
* @brief Schedule task for execution.
* Task will be added to pending tasks queue.
*
* @note If tasks queue is reached its length limit `IW_ERROR_OVERFLOW` will be returned.
* @note If tasks queue is reached its length limit
* current thread will be blocked if `queue_blocking` is true
* or `IW_ERROR_OVERFLOW` will be returned.
* @note If worker is in process of stopping `IW_ERROR_INVALID_STATE` will be returned.
*/
IW_EXPORT iwrc iwstw_schedule(IWSTW stw, iwstw_task_f task, void *task_arg);
/**
* @brief Schedule task only if task queue is empty.
*/
IW_EXPORT iwrc iwstw_schedule_empty_only(IWSTW stw, iwstw_task_f task, void *task_arg, bool *out_scheduled);
/**
* @brief Returns size of tasks queue.
*/
IW_EXPORT int iwstw_queue_size(IWSTW stw);
IW_EXTERN_C_END
#endif
+16 -21
View File
@@ -7,26 +7,24 @@
#define __unused __attribute__((unused))
#endif
int
pthread_barrierattr_init(pthread_barrierattr_t *attr __unused) {
int pthread_barrierattr_init(pthread_barrierattr_t *attr __unused) {
return 0;
}
int
pthread_barrierattr_destroy(pthread_barrierattr_t *attr __unused) {
int pthread_barrierattr_destroy(pthread_barrierattr_t *attr __unused) {
return 0;
}
int
pthread_barrierattr_getpshared(const pthread_barrierattr_t *restrict attr __unused,
int *restrict pshared) {
int pthread_barrierattr_getpshared(
const pthread_barrierattr_t* restrict attr __unused,
int* restrict pshared) {
*pshared = PTHREAD_PROCESS_PRIVATE;
return 0;
}
int
pthread_barrierattr_setpshared(pthread_barrierattr_t *attr __unused,
int pshared) {
int pthread_barrierattr_setpshared(
pthread_barrierattr_t *attr __unused,
int pshared) {
if (pshared != PTHREAD_PROCESS_PRIVATE) {
errno = EINVAL;
return -1;
@@ -34,10 +32,10 @@ pthread_barrierattr_setpshared(pthread_barrierattr_t *attr __unused,
return 0;
}
int
pthread_barrier_init(pthread_barrier_t *restrict barrier,
const pthread_barrierattr_t *restrict attr __unused,
unsigned count) {
int pthread_barrier_init(
pthread_barrier_t* restrict barrier,
const pthread_barrierattr_t* restrict attr __unused,
unsigned count) {
if (count == 0) {
errno = EINVAL;
return -1;
@@ -60,15 +58,13 @@ pthread_barrier_init(pthread_barrier_t *restrict barrier,
return 0;
}
int
pthread_barrier_destroy(pthread_barrier_t *barrier) {
int pthread_barrier_destroy(pthread_barrier_t *barrier) {
pthread_mutex_destroy(&barrier->mutex);
pthread_cond_destroy(&barrier->cond);
return 0;
}
int
pthread_barrier_wait(pthread_barrier_t *barrier) {
int pthread_barrier_wait(pthread_barrier_t *barrier) {
pthread_mutex_lock(&barrier->mutex);
barrier->count++;
if (barrier->count >= barrier->limit) {
@@ -79,13 +75,12 @@ pthread_barrier_wait(pthread_barrier_t *barrier) {
return PTHREAD_BARRIER_SERIAL_THREAD;
} else {
unsigned phase = barrier->phase;
do
do {
pthread_cond_wait(&barrier->cond, &barrier->mutex);
while (phase == barrier->phase);
} while (phase == barrier->phase);
pthread_mutex_unlock(&barrier->mutex);
return 0;
}
}
#endif /* __APPLE__ */
+17 -14
View File
@@ -38,14 +38,14 @@ extern "C" {
#endif
#if !defined(PTHREAD_BARRIER_SERIAL_THREAD)
# define PTHREAD_BARRIER_SERIAL_THREAD (1)
# define PTHREAD_BARRIER_SERIAL_THREAD (1)
#endif
#if !defined(PTHREAD_PROCESS_PRIVATE)
# define PTHREAD_PROCESS_PRIVATE (42)
# define PTHREAD_PROCESS_PRIVATE (42)
#endif
#if !defined(PTHREAD_PROCESS_SHARED)
# define PTHREAD_PROCESS_SHARED (43)
# define PTHREAD_PROCESS_SHARED (43)
#endif
typedef struct {
@@ -54,23 +54,26 @@ typedef struct {
typedef struct {
pthread_mutex_t mutex;
pthread_cond_t cond;
unsigned int limit;
unsigned int count;
unsigned int phase;
pthread_cond_t cond;
unsigned int limit;
unsigned int count;
unsigned int phase;
} pthread_barrier_t;
IW_EXPORT int pthread_barrierattr_init(pthread_barrierattr_t *attr);
IW_EXPORT int pthread_barrierattr_destroy(pthread_barrierattr_t *attr);
IW_EXPORT int pthread_barrierattr_getpshared(const pthread_barrierattr_t *restrict attr,
int *restrict pshared);
IW_EXPORT int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr,
int pshared);
IW_EXPORT int pthread_barrierattr_getpshared(
const pthread_barrierattr_t* restrict attr,
int* restrict pshared);
IW_EXPORT int pthread_barrierattr_setpshared(
pthread_barrierattr_t *attr,
int pshared);
IW_EXPORT int pthread_barrier_init(pthread_barrier_t *restrict barrier,
const pthread_barrierattr_t *restrict attr,
unsigned int count);
IW_EXPORT int pthread_barrier_init(
pthread_barrier_t* restrict barrier,
const pthread_barrierattr_t* restrict attr,
unsigned int count);
IW_EXPORT int pthread_barrier_destroy(pthread_barrier_t *barrier);
IW_EXPORT int pthread_barrier_wait(pthread_barrier_t *barrier);
+211
View File
@@ -0,0 +1,211 @@
#include "iwtp.h"
#include "iwth.h"
#include "iwp.h"
#include "iwlog.h"
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
struct _TASK {
iwtp_task_f fn;
void *arg;
struct _TASK *next;
};
struct _IWTP {
struct _TASK *head;
struct _TASK *tail;
pthread_mutex_t mtx;
pthread_cond_t cond;
pthread_t *threads;
char *thread_name_prefix;
int num_threads;
int queue_limit;
int cnt;
volatile bool shutdown;
};
iwrc iwtp_schedule(IWTP tp, iwtp_task_f fn, void *arg) {
if (!tp || !fn) {
return IW_ERROR_INVALID_ARGS;
}
iwrc rc = 0;
struct _TASK *task = malloc(sizeof(*task));
RCA(task, finish);
*task = (struct _TASK) {
.fn = fn,
.arg = arg
};
int rci = pthread_mutex_lock(&tp->mtx);
if (rci) {
rc = iwrc_set_errno(IW_ERROR_THREADING_ERRNO, errno);
goto finish;
}
if (tp->shutdown) {
rc = IW_ERROR_INVALID_STATE;
pthread_mutex_unlock(&tp->mtx);
goto finish;
}
if (tp->queue_limit && (tp->cnt + 1 > tp->queue_limit)) {
rc = IW_ERROR_OVERFLOW;
pthread_mutex_unlock(&tp->mtx);
goto finish;
}
if (tp->tail) {
tp->tail->next = task;
tp->tail = task;
} else {
tp->head = task;
tp->tail = task;
}
++tp->cnt;
pthread_cond_signal(&tp->cond);
pthread_mutex_unlock(&tp->mtx);
finish:
if (rc) {
free(task);
}
return rc;
}
static void* _worker_fn(void *op) {
struct _IWTP *tp = op;
assert(tp);
if (tp->thread_name_prefix) {
pthread_t st = pthread_self();
for (int i = 0; i < tp->num_threads; ++i) {
if (tp->threads[i] == st) {
char nbuf[strlen(tp->thread_name_prefix) + 16];
snprintf(nbuf, sizeof(nbuf), "%s%d", tp->thread_name_prefix, i);
iwp_set_current_thread_name(nbuf);
break;
}
}
}
while (true) {
void *arg;
iwtp_task_f fn = 0;
pthread_mutex_lock(&tp->mtx);
if (tp->head) {
struct _TASK *h = tp->head;
fn = h->fn;
arg = h->arg;
tp->head = h->next;
if (tp->head == 0) {
tp->tail = 0;
}
--tp->cnt;
free(h);
}
pthread_mutex_unlock(&tp->mtx);
if (fn) {
fn(arg);
}
pthread_mutex_lock(&tp->mtx);
if (tp->head) {
pthread_mutex_unlock(&tp->mtx);
continue;
} else if (tp->shutdown) {
pthread_mutex_unlock(&tp->mtx);
break;
}
pthread_cond_wait(&tp->cond, &tp->mtx);
pthread_mutex_unlock(&tp->mtx);
}
return 0;
}
iwrc iwtp_start(const char *thread_name_prefix, int num_threads, int queue_limit, IWTP *out_tp) {
if (num_threads < 1 || num_threads > 1023 || queue_limit < 0 || !out_tp) {
return IW_ERROR_INVALID_ARGS;
}
if (thread_name_prefix && strlen(thread_name_prefix) > 15) {
return IW_ERROR_INVALID_ARGS;
}
struct _IWTP *tp = malloc(sizeof(*tp) + sizeof(pthread_t) * num_threads);
if (!tp) {
*out_tp = 0;
return iwrc_set_errno(IW_ERROR_ALLOC, errno);
}
*tp = (struct _IWTP) {
.num_threads = num_threads,
.queue_limit = queue_limit,
.mtx = PTHREAD_MUTEX_INITIALIZER,
.cond = PTHREAD_COND_INITIALIZER
};
if (thread_name_prefix) {
tp->thread_name_prefix = strdup(thread_name_prefix);
}
tp->threads = (void*) ((char*) tp + sizeof(*tp));
memset(tp->threads, 0, sizeof(pthread_t) * num_threads);
while (num_threads--) {
pthread_create(&tp->threads[num_threads], 0, _worker_fn, tp);
}
*out_tp = tp;
return 0;
}
iwrc iwtp_shutdown(IWTP *tpp, bool wait_for_all) {
if (!tpp || !*tpp) {
return 0;
}
IWTP tp = *tpp;
pthread_mutex_lock(&tp->mtx);
if (tp->shutdown) {
pthread_mutex_unlock(&tp->mtx);
return 0;
}
tp->shutdown = true;
pthread_t st = pthread_self();
for (int i = 0; i < tp->num_threads; ++i) {
if (tp->threads[i] == st) {
pthread_mutex_unlock(&tp->mtx);
iwlog_error("iwtp | Thread iwtp_shutdown() from one of pool thread: %lu", (unsigned long) st);
return IW_ERROR_ASSERTION;
}
}
if (!wait_for_all) {
struct _TASK *t = tp->head;
while (t) {
struct _TASK *o = t;
t = t->next;
free(o);
}
tp->head = 0;
tp->tail = 0;
tp->cnt = 0;
}
pthread_cond_broadcast(&tp->cond);
pthread_mutex_unlock(&tp->mtx);
for (int i = 0; i < tp->num_threads; ++i) {
if (tp->threads[i]) {
pthread_join(tp->threads[i], 0);
}
}
pthread_cond_destroy(&tp->cond);
pthread_mutex_destroy(&tp->mtx);
free(tp->thread_name_prefix);
free(tp);
*tpp = 0;
return 0;
}
int iwtp_queue_size(IWTP tp) {
int res = 0;
pthread_mutex_lock(&tp->mtx);
res = tp->cnt;
pthread_mutex_unlock(&tp->mtx);
return res;
}
+80
View File
@@ -0,0 +1,80 @@
#pragma once
#ifndef IWTP_H
#define IWTP_H
/**************************************************************************************************
* Threads pool.
*
* IOWOW library
*
* MIT License
*
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*************************************************************************************************/
#include "basedefs.h"
IW_EXTERN_C_START
struct _IWTP;
typedef struct _IWTP*IWTP;
/**
* @brief Task to execute
*/
typedef void (*iwtp_task_f)(void *arg);
/**
* @brief Creates a new thread pool instance.
* @param num_threads Number of threads in the pool, accepted values in range `[1-1024]`
* @param queue_limit Maximum number of tasks in queue. Zero for unlimited queue.
* @param [out] out_tp Holder for thread pool instance.
*/
IW_EXPORT iwrc iwtp_start(const char *thread_name_prefix, int num_threads, int queue_limit, IWTP *out_tp);
/**
* @brief Submits new task into thread pool.
* @note `IW_ERROR_INVALID_STATE` if called after `iwtp_shutdown()`.
* @note `IW_ERROR_OVERFLOW` if size of tasks queue reached `queue_limit`.
* @param tp Pool instance
* @param task Task function
* @param task_arg Argument for task function
*/
IW_EXPORT iwrc iwtp_schedule(IWTP tp, iwtp_task_f task, void *task_arg);
/**
* @brief Shutdowns thread pool and disposes all nresources.
* @note Function will wait until current task completes or
* wait for all enqueued tasks if `wait_for_all` is set to `true`.
* No new tasks will be accepted during `iwstw_shutdown` call.
* @param tpp Pointer to pool which should be disposed.
* @param wait_for_all If true worker will wait for completion of all enqueued tasks before shutdown.
*/
IW_EXPORT iwrc iwtp_shutdown(IWTP *tpp, bool wait_for_all);
/**
* @brief Returns size of tasks queue.
*/
IW_EXPORT int iwtp_queue_size(IWTP tp);
IW_EXTERN_C_END
#endif
+37 -26
View File
@@ -4,7 +4,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -38,6 +38,10 @@
#include <string.h>
#include "mt19937ar.h"
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif
#define IWU_RAND_MAX 0xffffffff
iwrc iwu_init(void) {
@@ -55,8 +59,8 @@ uint32_t iwu_rand_u32(void) {
double_t iwu_rand_dnorm(double_t avg, double_t sd) {
assert(sd >= 0.0);
return sqrt(-2.0 * log((genrand_int31() / (double_t) INT_MAX))) *
cos(2 * 3.141592653589793 * (genrand_int31() / (double_t) INT_MAX)) * sd + avg;
return sqrt(-2.0 * log((genrand_int31() / (double_t) INT_MAX)))
* cos(2 * 3.141592653589793 * (genrand_int31() / (double_t) INT_MAX)) * sd + avg;
}
uint32_t iwu_rand_range(uint32_t range) {
@@ -70,10 +74,10 @@ uint32_t iwu_rand_inorm(int range) {
int iwlog2_32(uint32_t val) {
static const int tab32[32] = {
0, 9, 1, 10, 13, 21, 2, 29,
11, 14, 16, 18, 22, 25, 3, 30,
8, 12, 20, 28, 15, 17, 24, 7,
19, 27, 23, 6, 26, 5, 4, 31
0, 9, 1, 10, 13, 21, 2, 29,
11, 14, 16, 18, 22, 25, 3, 30,
8, 12, 20, 28, 15, 17, 24, 7,
19, 27, 23, 6, 26, 5, 4, 31
};
val |= val >> 1;
val |= val >> 2;
@@ -85,10 +89,10 @@ int iwlog2_32(uint32_t val) {
int iwlog2_64(uint64_t val) {
static const int table[64] = {
0, 58, 1, 59, 47, 53, 2, 60, 39, 48, 27, 54, 33, 42, 3, 61,
51, 37, 40, 49, 18, 28, 20, 55, 30, 34, 11, 43, 14, 22, 4, 62,
0, 58, 1, 59, 47, 53, 2, 60, 39, 48, 27, 54, 33, 42, 3, 61,
51, 37, 40, 49, 18, 28, 20, 55, 30, 34, 11, 43, 14, 22, 4, 62,
57, 46, 52, 38, 26, 32, 41, 50, 36, 17, 19, 29, 10, 13, 21, 56,
45, 25, 31, 35, 16, 9, 12, 44, 24, 15, 8, 23, 7, 6, 5, 63
45, 25, 31, 35, 16, 9, 12, 44, 24, 15, 8, 23, 7, 6, 5, 63
};
val |= val >> 1;
val |= val >> 2;
@@ -176,7 +180,7 @@ uint32_t iwu_crc32(const uint8_t *buf, int len, uint32_t init) {
return crc;
}
char *iwu_replace_char(char *data, char sch, char rch) {
char* iwu_replace_char(char *data, char sch, char rch) {
for (int i = 0; data[i]; ++i) {
if (data[i] == sch) {
data[i] = rch;
@@ -202,7 +206,7 @@ int iwu_cmp_files(FILE *f1, FILE *f2, bool verbose) {
int pos = 0, line = 1;
while (c1 != EOF && c2 != EOF) {
pos++;
if (c1 == '\n' && c2 == '\n') {
if ((c1 == '\n') && (c2 == '\n')) {
line++;
pos = 0;
} else if (c1 != c2) {
@@ -220,13 +224,15 @@ int iwu_cmp_files(FILE *f1, FILE *f2, bool verbose) {
return (c1 - c2);
}
char *iwu_file_read_as_buf(const char *path) {
char* iwu_file_read_as_buf(const char *path) {
struct stat st;
if (stat(path, &st) == -1) {
return 0;
}
int fd = open(path, O_RDONLY);
if (fd == -1) return 0;
int fd = open(path, O_RDONLY | O_CLOEXEC);
if (fd == -1) {
return 0;
}
char *data = malloc(st.st_size + 1);
if (!data) {
@@ -243,29 +249,34 @@ char *iwu_file_read_as_buf(const char *path) {
}
uint32_t iwu_x31_u32_hash(const char *s) {
uint32_t h = (uint32_t) * s;
uint32_t h = (uint32_t) *s;
if (h) {
for (++s; *s; ++s) {
h = (h << 5) - h + (uint32_t) * s;
h = (h << 5) - h + (uint32_t) *s;
}
}
return h;
}
iwrc iwu_replace(IWXSTR **result,
const char *data,
int datalen,
const char *keys[],
int keysz,
iwu_replace_mapper mapper,
void *mapper_op) {
iwrc iwu_replace(
IWXSTR **result,
const char *data,
int datalen,
const char *keys[],
int keysz,
iwu_replace_mapper mapper,
void *mapper_op) {
if (!result || !data || !keys || !mapper) {
return IW_ERROR_INVALID_ARGS;
}
if (keysz < 0) {
for (keysz = 0; keys[keysz] != 0; ++keysz);
}
iwrc rc = 0;
if (datalen < 1 || keysz < 1) {
if ((datalen < 1) || (keysz < 1)) {
*result = iwxstr_new2(datalen < 1 ? 1 : datalen);
if (datalen > 0) {
rc = iwxstr_cat(*result, data, datalen);
@@ -319,7 +330,7 @@ finish:
if (bbuf) {
iwxstr_destroy(bbuf);
}
if (!rc && start == data) {
if (!rc && (start == data)) {
rc = iwxstr_cat(inter, data, datalen);
}
if (rc) {
+61 -194
View File
@@ -7,7 +7,7 @@
*
* MIT License
*
* Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
* Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -41,145 +41,10 @@
IW_EXTERN_C_START
/* Align x_ with v_. v_ must be simple power for 2 value. */
#define IW_ROUNDUP(x_, v_) (((x_) + (v_) - 1) & ~((v_) - 1))
/* Round down align x_ with v_. v_ must be simple power for 2 value. */
#define IW_ROUNDOWN(x_, v_) ((x_) - ((x_) & ((v_) - 1)))
#if defined(NDEBUG)
#define IW_DODEBUG(IW_expr_) \
do { \
} while (0)
#else
#define IW_DODEBUG(IW_expr_) \
{ IW_expr_; }
#endif
#if __GNUC__ >= 5
#define IW_SWAB16(num_) __builtin_bswap16(num_)
#else
#define IW_SWAB16(num_) \
((((num_) & 0x00ffU) << 8) | (((num_) & 0xff00U) >> 8))
#endif
#if __GNUC__ >= 4
#define IW_SWAB32(num_) __builtin_bswap32(num_)
#else
#define IW_SWAB32(num_) \
((((num_) & 0x000000ffUL) << 24) | (((num_) & 0x0000ff00UL) << 8) | \
(((num_) & 0x00ff0000UL) >> 8) | (((num_) & 0xff000000UL) >> 24))
#endif
#if __GNUC__ >= 4
#define IW_SWAB64(num_) __builtin_bswap64(num_)
#else
#define IW_SWAB64(num_) \
((((num_) & 0x00000000000000ffULL) << 56) | \
(((num_) & 0x000000000000ff00ULL) << 40) | \
(((num_) & 0x0000000000ff0000ULL) << 24) | \
(((num_) & 0x00000000ff000000ULL) << 8) | \
(((num_) & 0x000000ff00000000ULL) >> 8) | \
(((num_) & 0x0000ff0000000000ULL) >> 24) | \
(((num_) & 0x00ff000000000000ULL) >> 40) | \
(((num_) & 0xff00000000000000ULL) >> 56))
#endif
#ifdef IW_BIGENDIAN
#define IW_HTOIS(num_) IW_SWAB16(num_)
#define IW_HTOIL(num_) IW_SWAB32(num_)
#define IW_HTOILL(num_) IW_SWAB64(num_)
#define IW_ITOHS(num_) IW_SWAB16(num_)
#define IW_ITOHL(num_) IW_SWAB32(num_)
#define IW_ITOHLL(num_) IW_SWAB64(num_)
#else
#define IW_HTOIS(num_) (num_)
#define IW_HTOIL(num_) (num_)
#define IW_HTOILL(num_) (num_)
#define IW_ITOHS(num_) (num_)
#define IW_ITOHL(num_) (num_)
#define IW_ITOHLL(num_) (num_)
#endif
#define IW_WRITEBV(ptr_, v_, m_) \
static_assert(sizeof(v_) == 1, "Mismatch v_ size"); \
(v_) = (m_); \
memcpy(ptr_, &(v_), 1); \
(ptr_) += 1
#define IW_WRITESV(ptr_, v_, m_) \
static_assert(sizeof(v_) == 2, "Mismatch v_ size"); \
(v_) = (m_); \
(v_) = IW_HTOIS(v_); \
memcpy(ptr_, &(v_), 2); \
(ptr_) += 2
#define IW_WRITELV(ptr_, v_, m_) \
static_assert(sizeof(v_) == 4, "Mismatch v_ size"); \
(v_) = (m_); \
(v_) = IW_HTOIL(v_); \
memcpy(ptr_, &(v_), 4); \
(ptr_) += 4
#define IW_WRITELLV(ptr_, v_, m_) \
static_assert(sizeof(v_) == 8, "Mismatch v_ size"); \
(v_) = (m_); \
(v_) = IW_HTOILL(v_); \
memcpy((ptr_), &(v_), 8); \
(ptr_) += 8
#define IW_READBV(ptr_, t_, m_) \
static_assert(sizeof(t_) == 1, "Mismatch t_ size"); \
(t_) = 0; \
memcpy(&(t_), ptr_, 1); \
(m_) = (t_); \
(ptr_) += 1
#define IW_READSV(ptr_, t_, m_) \
static_assert(sizeof(t_) == 2, "Mismatch t_ size"); \
(t_) = 0; \
memcpy(&(t_), ptr_, 2); \
(m_) = IW_ITOHS(t_); \
(ptr_) += 2
#define IW_READLV(ptr_, t_, m_) \
static_assert(sizeof(t_) == 4, "Mismatch t_ size"); \
(t_) = 0; \
memcpy(&(t_), ptr_, 4); \
(m_) = IW_ITOHL(t_); \
(ptr_) += 4
#define IW_READLLV(ptr_, t_, m_) \
static_assert(sizeof(t_) == 8, "Mismatch t_ size"); \
(t_) = 0; \
memcpy(&(t_), ptr_, 8); \
(m_) = IW_ITOHLL(t_); \
(ptr_) += 8
#ifndef SIZE_T_MAX
#define SIZE_T_MAX ((size_t)-1)
#endif
#ifndef OFF_T_MIN
#define OFF_T_MIN ((off_t)(((uint64_t)1) << (8 * sizeof(off_t) - 1)))
#endif
#ifndef OFF_T_MAX
#define OFF_T_MAX ((off_t) ~(((uint64_t)1) << (8 * sizeof(off_t) - 1)))
#endif
#ifdef __GNUC__
#define IW_LIKELY(x_) __builtin_expect(!!(x_), 1)
#define IW_UNLIKELY(x_) __builtin_expect(!!(x_), 0)
#else
#define IW_LIKELY(x_)
#define IW_UNLIKELY(x_)
#endif
#define IW_RANGES_OVERLAP(IW_s1_, IW_e1_, IW_s2_, IW_e2_) \
(((IW_e1_) > (IW_s2_) && (IW_e1_) <= (IW_e2_)) || \
((IW_s1_) >= (IW_s2_) && (IW_s1_) < (IW_e2_)) || \
((IW_s1_) <= (IW_s2_) && (IW_e1_) >= (IW_e2_)))
( ((IW_e1_) > (IW_s2_) && (IW_e1_) <= (IW_e2_)) \
|| ((IW_s1_) >= (IW_s2_) && (IW_s1_) < (IW_e2_)) \
|| ((IW_s1_) <= (IW_s2_) && (IW_e1_) >= (IW_e2_)))
///////////////////////////////////////////////////////////////////////////
// Variable length number encoding //
@@ -189,45 +54,45 @@ IW_EXTERN_C_START
#define IW_SETVNUMBUF(len_, buf_, num_) \
do { \
int32_t _num_ = (num_); \
if (_num_ == 0){ \
((signed char *)(buf_))[0] = 0; \
if (_num_ == 0) { \
((signed char*) (buf_))[0] = 0; \
(len_) = 1; \
} else { \
(len_) = 0; \
while(_num_ > 0) { \
while (_num_ > 0) { \
int _rem_ = _num_ & 0x7f; \
_num_ >>= 7; \
if(_num_ > 0){ \
((signed char *)(buf_))[(len_)] = ~(_rem_); \
if (_num_ > 0) { \
((signed char*) (buf_))[(len_)] = ~(_rem_); \
} else { \
((signed char *)(buf_))[(len_)] = _rem_; \
((signed char*) (buf_))[(len_)] = _rem_; \
} \
(len_)++; \
} \
} \
} while(0)
} while (0)
/* set a buffer for a variable length 64 number */
#define IW_SETVNUMBUF64(len_, buf_, num_) \
do { \
int64_t _num_ = (num_); \
if (_num_ == 0){ \
((signed char *)(buf_))[0] = 0; \
if (_num_ == 0) { \
((signed char*) (buf_))[0] = 0; \
(len_) = 1; \
} else { \
(len_) = 0; \
while(_num_ > 0) { \
while (_num_ > 0) { \
int _rem_ = _num_ & 0x7f; \
_num_ >>= 7; \
if(_num_ > 0){ \
((signed char *)(buf_))[(len_)] = ~(_rem_); \
if (_num_ > 0) { \
((signed char*) (buf_))[(len_)] = ~(_rem_); \
} else { \
((signed char *)(buf_))[(len_)] = _rem_; \
((signed char*) (buf_))[(len_)] = _rem_; \
} \
(len_)++; \
} \
} \
} while(0)
} while (0)
/* read a 32 bit variable length buffer */
@@ -236,17 +101,17 @@ IW_EXTERN_C_START
(num_) = 0; \
int32_t _base_ = 1; \
int _i_ = 0; \
while(1){ \
if (((const signed char *)(buf_))[_i_] >= 0){ \
(num_) += _base_ * ((const signed char *)(buf_))[_i_]; \
while (1) { \
if (((const signed char*) (buf_))[_i_] >= 0) { \
(num_) += _base_ * ((const signed char*) (buf_))[_i_]; \
break; \
} \
(num_) += _base_ * ~(((const signed char *)(buf_))[_i_]); \
(num_) += _base_ * ~(((const signed char*) (buf_))[_i_]); \
_base_ <<= 7; \
_i_++; \
} \
(step_) = _i_ + 1; \
} while(0)
} while (0)
/* read a 64 bit variable length buffer */
#define IW_READVNUMBUF64(buf_, num_, step_) \
@@ -254,17 +119,17 @@ IW_EXTERN_C_START
(num_) = 0; \
int64_t _base_ = 1; \
int _i_ = 0; \
while(1){ \
if (((const signed char *)(buf_))[_i_] >= 0){ \
(num_) += _base_ * ((const signed char *)(buf_))[_i_]; \
while (1) { \
if (((const signed char*) (buf_))[_i_] >= 0) { \
(num_) += _base_ * ((const signed char*) (buf_))[_i_]; \
break; \
} \
(num_) += _base_ * ~(((const signed char *)(buf_))[_i_]); \
(num_) += _base_ * ~(((const signed char*) (buf_))[_i_]); \
_base_ <<= 7; \
_i_++; \
} \
(step_) = _i_ + 1; \
} while(0)
} while (0)
/* read a 64 bit variable length buffer */
@@ -273,40 +138,40 @@ IW_EXTERN_C_START
(num_) = 0; \
int64_t _base_ = 1; \
int _i_ = 0; \
while(1){ \
if (((const signed char *)(buf_))[_i_] >= 0){ \
(num_) += _base_ * ((const signed char *)(buf_))[_i_]; \
while (1) { \
if (((const signed char*) (buf_))[_i_] >= 0) { \
(num_) += _base_ * ((const signed char*) (buf_))[_i_]; \
break; \
} \
(num_) += _base_ * ~(((const signed char *)(buf_))[_i_]); \
(num_) += _base_ * ~(((const signed char*) (buf_))[_i_]); \
_base_ <<= 7; \
_i_++; \
} \
} while(0)
} while (0)
#define IW_VNUMBUFSZ 10
#define IW_VNUMSIZE32(num_) \
((num_) < 0x80ULL ? 1 : \
(num_) < 0x4000ULL ? 2 : \
(num_) < 0x200000ULL ? 3 : \
(num_) < 0x10000000ULL ? 4 : 5)
((num_) < 0x80ULL ? 1 \
: (num_) < 0x4000ULL ? 2 \
: (num_) < 0x200000ULL ? 3 \
: (num_) < 0x10000000ULL ? 4 : 5)
/* Size of variable number in bytes */
#ifdef IW_32
#define IW_VNUMSIZE IW_VNUMSIZE32
#else
#define IW_VNUMSIZE(num_) \
((num_) < 0x80ULL ? 1 : \
(num_) < 0x4000ULL ? 2 : \
(num_) < 0x200000ULL ? 3 : \
(num_) < 0x10000000ULL ? 4 : \
(num_) < 0x800000000ULL ? 5 : \
(num_) < 0x40000000000ULL ? 6 : \
(num_) < 0x2000000000000ULL ? 7 : \
(num_) < 0x100000000000000ULL ? 8 : \
(num_) < 0x8000000000000000ULL ? 9 : 10)
((num_) < 0x80ULL ? 1 \
: (num_) < 0x4000ULL ? 2 \
: (num_) < 0x200000ULL ? 3 \
: (num_) < 0x10000000ULL ? 4 \
: (num_) < 0x800000000ULL ? 5 \
: (num_) < 0x40000000000ULL ? 6 \
: (num_) < 0x2000000000000ULL ? 7 \
: (num_) < 0x100000000000000ULL ? 8 \
: (num_) < 0x8000000000000000ULL ? 9 : 10)
#endif
/* Lexicographic comparison of values */
@@ -315,13 +180,13 @@ IW_EXTERN_C_START
(rv_) = 0; \
int min_ = (vp1sz_) < (vp2sz_) ? (vp1sz_) : (vp2sz_); \
for (int i = 0; i < min_; i++) { \
(rv_) = (int) (((const uint8_t *)(vp1_))[i] - ((const uint8_t *)(vp2_))[i]); \
(rv_) = (int) (((const uint8_t*) (vp1_))[i] - ((const uint8_t*) (vp2_))[i]); \
if (rv_) { \
break; \
} \
} \
if ((rv_) == 0) (rv_) = (vp1sz_) - (vp2sz_); \
} while(0)
} while (0)
/* Lexicographic comparison common prefix of values */
@@ -330,12 +195,12 @@ IW_EXTERN_C_START
(rv_) = 0; \
int min_ = (vp1sz_) < (vp2sz_) ? (vp1sz_) : (vp2sz_); \
for (int i = 0; i < min_; i++) { \
(rv_) = (int) (((const uint8_t *)(vp1_))[i] - ((const uint8_t *)(vp2_))[i]); \
(rv_) = (int) (((const uint8_t*) (vp1_))[i] - ((const uint8_t*) (vp2_))[i]); \
if (rv_) { \
break; \
} \
} \
} while(0)
} while (0)
IW_EXPORT iwrc iwu_init(void);
@@ -381,7 +246,7 @@ IW_EXPORT char *iwu_replace_char(char *data, char sch, char rch);
* @brief Returns `\0` terminated string as replacement
* of given `key`.
*/
typedef const char *(*iwu_replace_mapper)(const char *key, void *op);
typedef const char* (*iwu_replace_mapper)(const char *key, void *op);
/**
* @brief Replaces all occurriences of `keys`
@@ -391,17 +256,19 @@ typedef const char *(*iwu_replace_mapper)(const char *key, void *op);
* @param data Data to search
* @param datalen Length of data buffer
* @param keys Array of keys to search
* @param keysz Number of elements in keys array
* @param keysz Number of elements in keys array.
* Negative for NULL terminated arrays.
* @param mapper Replacement mapper
* @param mapper_op Replacement mapper opaque data
*/
IW_EXPORT iwrc iwu_replace(IWXSTR **result,
const char *data,
int datalen,
const char *keys[],
int keysz,
iwu_replace_mapper mapper,
void *mapper_op);
IW_EXPORT iwrc iwu_replace(
IWXSTR **result,
const char *data,
int datalen,
const char *keys[],
int keysz,
iwu_replace_mapper mapper,
void *mapper_op);
IW_EXPORT int iwu_cmp_files(FILE *f1, FILE *f2, bool verbose);
+3 -3
View File
@@ -3,8 +3,8 @@
#include <string.h>
union _uuid {
uint8_t byte[16];
uint32_t rnd[4];
uint8_t byte[16];
uint32_t rnd[4];
};
// [a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}
@@ -14,7 +14,7 @@ IW_INLINE bool _is_uuid_char(char ch) {
}
bool iwu_uuid_valid(const char *uuid) {
if (!uuid || strlen(uuid) != IW_UUID_STR_LEN) {
if (!uuid || (strlen(uuid) != IW_UUID_STR_LEN)) {
return false;
}
for (int i = 0; i < 8; ++i) {
+111 -82
View File
@@ -5,6 +5,7 @@
#include <string.h>
#include <assert.h>
#include <stdarg.h>
#include <errno.h>
// Default IWXSTR initial size
#ifndef IWXSTR_AUNIT
@@ -12,39 +13,75 @@
#endif
struct _IWXSTR {
char *ptr; /**< Data buffer */
char *ptr; /**< Data buffer */
size_t size; /**< Actual data size */
size_t asize; /**< Allocated buffer size */
void (*user_data_free_fn)(void*);
void *user_data;
};
IWXSTR *iwxstr_new2(size_t siz) {
if (!siz) siz = IWXSTR_AUNIT;
IWXSTR* iwxstr_new2(size_t siz) {
if (!siz) {
siz = IWXSTR_AUNIT;
}
IWXSTR *xstr = malloc(sizeof(*xstr));
if (!xstr) return 0;
if (!xstr) {
return 0;
}
xstr->ptr = malloc(siz);
if (!xstr->ptr) {
free(xstr);
return 0;
}
xstr->user_data = 0;
xstr->user_data_free_fn = 0;
xstr->size = 0;
xstr->asize = siz;
xstr->ptr[0] = '\0';
return xstr;
}
IWXSTR *iwxstr_new(void) {
IWXSTR* iwxstr_new(void) {
return iwxstr_new2(IWXSTR_AUNIT);
}
IWXSTR* iwxstr_wrap(const char *buf, size_t size) {
IWXSTR *xstr = iwxstr_new2(size + 1);
if (!xstr) {
return 0;
}
if (iwxstr_cat(xstr, buf, size)) {
iwxstr_destroy(xstr);
return 0;
}
return xstr;
}
void iwxstr_destroy(IWXSTR *xstr) {
if (!xstr) return;
if (!xstr) {
return;
}
if (xstr->user_data_free_fn) {
xstr->user_data_free_fn(xstr->user_data);
}
free(xstr->ptr);
free(xstr);
}
void iwxstr_destroy_keep_ptr(IWXSTR *xstr) {
if (!xstr) {
return;
}
if (xstr->user_data_free_fn) {
xstr->user_data_free_fn(xstr->user_data);
}
free(xstr);
}
void iwxstr_clear(IWXSTR *xstr) {
assert(xstr);
xstr->size = 0;
xstr->ptr[0] = '\0';
}
iwrc iwxstr_cat(IWXSTR *xstr, const void *buf, size_t size) {
@@ -68,6 +105,25 @@ iwrc iwxstr_cat(IWXSTR *xstr, const void *buf, size_t size) {
return IW_OK;
}
iwrc iwxstr_set_size(IWXSTR *xstr, size_t size) {
size_t nsize = size + 1;
if (xstr->asize < nsize) {
while (xstr->asize < nsize) {
xstr->asize <<= 1;
if (xstr->asize < nsize) {
xstr->asize = nsize;
}
}
char *ptr = realloc(xstr->ptr, xstr->asize);
if (!ptr) {
return IW_ERROR_ERRNO;
}
xstr->ptr = ptr;
}
xstr->size = size;
return IW_OK;
}
iwrc iwxstr_cat2(IWXSTR *xstr, const char *buf) {
return buf ? iwxstr_cat(xstr, buf, strlen(buf)) : 0;
}
@@ -111,81 +167,34 @@ void iwxstr_shift(IWXSTR *xstr, size_t shift_size) {
xstr->ptr[xstr->size] = '\0';
}
static iwrc iwxstr_vaprintf(IWXSTR *xstr, const char *format, va_list ap) {
void iwxstr_pop(IWXSTR *xstr, size_t pop_size) {
if (pop_size == 0) {
return;
}
if (pop_size > xstr->size) {
pop_size = xstr->size;
}
xstr->size -= pop_size;
xstr->ptr[xstr->size] = '\0';
}
static iwrc iwxstr_vaprintf(IWXSTR *xstr, const char *format, va_list va) {
iwrc rc = 0;
while (*format) {
if (*format == '%') {
char cbuf[32];
cbuf[0] = '%';
size_t cblen = 1;
int lnum = 0;
++format;
while (strchr("0123456789 .+-hlLzI", *format) && *format && cblen < sizeof(cbuf) - 1) {
if (*format == 'l' || *format == 'L') {
lnum++;
}
cbuf[cblen++] = *(format++);
}
cbuf[cblen++] = *format;
cbuf[cblen] = '\0';
int tlen;
char *tmp, tbuf[128];
switch (*format) {
case 's':
tmp = va_arg(ap, char *);
if (!tmp) tmp = "(null)";
rc = iwxstr_cat(xstr, tmp, strlen(tmp));
break;
case 'd':
if (lnum >= 2) { // -V1037
tlen = sprintf(tbuf, cbuf, va_arg(ap, long long));
} else if (lnum >= 1) {
tlen = sprintf(tbuf, cbuf, va_arg(ap, long));
} else {
tlen = sprintf(tbuf, cbuf, va_arg(ap, int));
}
rc = iwxstr_cat(xstr, tbuf, (size_t) tlen);
break;
case 'o':
case 'u':
case 'x':
case 'X':
case 'c':
if (lnum >= 2) {
tlen = sprintf(tbuf, cbuf, va_arg(ap, unsigned long long));
} else if (lnum >= 1) {
tlen = sprintf(tbuf, cbuf, va_arg(ap, unsigned long));
} else {
tlen = sprintf(tbuf, cbuf, va_arg(ap, unsigned int));
}
rc = iwxstr_cat(xstr, tbuf, (size_t) tlen);
break;
case 'e':
case 'E':
case 'f':
case 'g':
case 'G':
if (lnum > 1) {
tlen = snprintf(tbuf, sizeof(tbuf), cbuf, va_arg(ap, long double));
} else {
tlen = snprintf(tbuf, sizeof(tbuf), cbuf, va_arg(ap, double));
}
if (tlen < 0 || tlen >= sizeof(tbuf)) {
tbuf[sizeof(tbuf) - 1] = '*';
tlen = sizeof(tbuf);
}
rc = iwxstr_cat(xstr, tbuf, (size_t) tlen);
break;
case '%':
rc = iwxstr_cat(xstr, "%", 1);
break;
}
RCBREAK(rc);
} else {
rc = iwxstr_cat(xstr, format, 1);
RCRET(rc);
}
format++;
char buf[1024];
va_list cva;
va_copy(cva, va);
char *wp = buf;
int len = vsnprintf(wp, sizeof(buf), format, va);
if (len >= sizeof(buf)) {
RCA(wp = malloc(len + 1), finish);
len = vsnprintf(wp, len + 1, format, cva);
}
rc = iwxstr_cat(xstr, wp, len);
finish:
va_end(cva);
if (wp != buf) {
free(wp);
}
return rc;
}
@@ -193,12 +202,12 @@ static iwrc iwxstr_vaprintf(IWXSTR *xstr, const char *format, va_list ap) {
iwrc iwxstr_printf(IWXSTR *xstr, const char *format, ...) {
va_list ap;
va_start(ap, format);
iwrc rc = iwxstr_vaprintf(xstr, format, ap);
iwrc rc = iwxstr_vaprintf(xstr, format, ap);
va_end(ap);
return rc;
}
char *iwxstr_ptr(IWXSTR *xstr) {
char* iwxstr_ptr(IWXSTR *xstr) {
return xstr->ptr;
}
@@ -206,3 +215,23 @@ size_t iwxstr_size(IWXSTR *xstr) {
return xstr->size;
}
size_t iwxstr_asize(IWXSTR *xstr) {
return xstr->asize;
}
void iwxstr_user_data_set(IWXSTR *xstr, void *data, void (*free_fn)(void*)) {
if (xstr->user_data_free_fn) {
xstr->user_data_free_fn(xstr->user_data);
}
xstr->user_data = data;
xstr->user_data_free_fn = free_fn;
}
void* iwxstr_user_data_get(IWXSTR *xstr) {
return xstr->user_data;
}
void* iwxstr_user_data_detach(IWXSTR *xstr) {
xstr->user_data_free_fn = 0;
return xstr->user_data;
}

Some files were not shown because too many files have changed in this diff Show More