mirror of
https://github.com/openharmony/third_party_iowow.git
synced 2026-07-01 14:23:51 -04:00
update from v1.4.10 to v1.4.15
Signed-off-by: zhouhaifeng <kutcher.zhou@huawei.com>
This commit is contained in:
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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>
|
||||
@@ -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
@@ -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}")
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -66,6 +66,7 @@ Note:If the text contains special characters, please escape them according to th
|
||||
<filefilter name="defaultPolicyFilter" desc="Filters for compatibility,license 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 > 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
|
||||
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 > 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."
|
||||
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 >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."
|
||||
desc=""/>
|
||||
</licensematcher>
|
||||
</licensematcherlist>
|
||||
</oatconfig>
|
||||
</configuration>
|
||||
+1
-1
@@ -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,10 +1,9 @@
|
||||
IOWOW - The C11 persistent key/value database engine based on [skip list](https://en.wikipedia.org/wiki/Skip_list)
|
||||
==================================================================================================================
|
||||
|
||||

|
||||
[](https://t.me/ejdb2)
|
||||
[](https://github.com/Softmotions/iowow/blob/master/LICENSE)
|
||||

|
||||

|
||||
|
||||
Website http://iowow.io
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#include <stdlib.h>
|
||||
int main(int argc, char **argv) {
|
||||
qsort_r(0, 0, 0, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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)) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,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;
|
||||
|
||||
@@ -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,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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+55
-40
@@ -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
@@ -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
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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__, ""); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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@
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user