diff --git a/deps/mio/AUTHORS b/deps/mio/AUTHORS new file mode 100644 index 0000000000000000000000000000000000000000..d79ec35741251a426b1a2b0d6e33ca2eeb19a625 --- /dev/null +++ b/deps/mio/AUTHORS @@ -0,0 +1 @@ +Sining Wu <sining.wu@seagate.com> diff --git a/deps/mio/COPYING b/deps/mio/COPYING new file mode 100644 index 0000000000000000000000000000000000000000..d758885ee9f86ad03f3422cacf8d1384086bc821 --- /dev/null +++ b/deps/mio/COPYING @@ -0,0 +1,2 @@ +Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, All Rights Reserved +License: MPL v2.0 (see License) diff --git a/deps/mio/ChangeLog b/deps/mio/ChangeLog new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/deps/mio/LICENSE b/deps/mio/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..a1913aae5702eb9403dfb8fd17c3949ecc969ab4 --- /dev/null +++ b/deps/mio/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at https://urldefense.proofpoint.com/v2/url?u=http-3A__mozilla.org_MPL_2.0_&d=DwIGAg&c=IGDlg0lD0b-nebmJJ0Kp8A&r=hP9i0a2dylNof_BddtBQSPyJc_9TlHHZ-xqQ6WnSg58&m=KIzUSoG_oqOVYCLgZ-9FvofAcLFZl_5qNlYFiLJ6gEs&s=v9pYlPD3qxkg_6dfQJATPzJY_RCImCaMbHeQUQ21bZk&e= . + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/deps/mio/Makefile.am b/deps/mio/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..38126b65eee8b817afe6ac2858607f10b1fbb2af --- /dev/null +++ b/deps/mio/Makefile.am @@ -0,0 +1,151 @@ +# Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, +# All Rights Reserved +# +# This software is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#------------------------------------------------------------------------------- +# Quick Start # +#------------------------------------------------------------------------------- + +#------------------------------------------------------------------------------- +# Automake configuration # +#------------------------------------------------------------------------------- + +# control verbosity level of make depending on 'V' command-line argument and +# --enable-silent-rules option of configure script +make_verbose = $(make_verbose_$(V)) +make_verbose_ = $(make_verbose_$(AM_DEFAULT_VERBOSITY)) +make_verbose_0 = --no-print-directory + +MAKEFLAGS = $(make_verbose) + +# in order to suppress annoying automake warning "CFLAGS: non-POSIX variable name" +# -Wno-portability automake option should be set for this makefile, this is +# required for xcode generation +AUTOMAKE_OPTIONS = -Wno-portability + +# required to properly rebuild aclocal.m4 macros on configure.ac or Makefile.am +# updates +ACLOCAL_AMFLAGS = -I m4 + +# default XXXFLAGS, used for preprocessing, compiling and linking for all +# user-space targets + +AM_CPPFLAGS = @MIO_CPPFLAGS@ +AM_CFLAGS = @MIO_CFLAGS@ +AM_LDFLAGS = @MIO_LDFLAGS@ + +#------------------------------------------------------------------------------- +# Global variables # +#------------------------------------------------------------------------------- + +# initialize variables, so values can be appended later with += if needed + +# everything that needs to be installed/packaged goes here +bin_PROGRAMS = +lib_LTLIBRARIES = + +# non-installable/packageable stuff: build helpers, local tests, etc. +noinst_PROGRAMS = +noinst_LTLIBRARIES = + +# documentation +man_MANS = + +# Extra files with distribution +EXTRA_DIST = + +# Files to clean +CLEANFILES = + +#------------------------------------------------------------------------------- +# MIO Libraries # +#------------------------------------------------------------------------------- + +lib_LTLIBRARIES += lib/libmio.la +lib_libmio_la_CPPFLAGS = -DM0_TARGET='libmero' $(AM_CPPFLAGS) +lib_libmio_la_LDFLAGS = -version-info @LT_VERSION@ $(AM_LDFLAGS) +#lib_libmio_la_LIBADD = @MERO_LIBS@ @YAML_LIBS@ +lib_libmio_la_LIBADD = -lmero -lyaml + +lib_libmio_la_SOURCES = + +# install directory for public libmio headers +mio_includedir = $(includedir)/mio + +nobase_mio_include_HEADERS = config.h + +include $(top_srcdir)/src/Makefile.sub + + +#------------------------------------------------------------------------------- +# Unit Tests # +#------------------------------------------------------------------------------- + + +#------------------------------------------------------------------------------- +# MIO Examples # +#------------------------------------------------------------------------------- + +noinst_PROGRAMS += examples/mio_cat +noinst_PROGRAMS += examples/mio_copy +noinst_PROGRAMS += examples/mio_touch +noinst_PROGRAMS += examples/mio_unlink +noinst_PROGRAMS += examples/mio_hint_set +noinst_PROGRAMS += examples/mio_hint_stat +noinst_PROGRAMS += examples/mio_kvs_create_set +noinst_PROGRAMS += examples/mio_kvs_del_set +noinst_PROGRAMS += examples/mio_kvs_insert +noinst_PROGRAMS += examples/mio_kvs_retrieve +noinst_PROGRAMS += examples/mio_kvs_del_pairs +noinst_PROGRAMS += examples/mio_comp_obj_example +noinst_PROGRAMS += examples/mio_rw_threads + +examples_mio_cat_CPPFLAGS = -DMIO_TARGET='mio_cat' $(AM_CPPFLAGS) +examples_mio_cat_LDADD = $(top_builddir)/lib/libmio.la + +examples_mio_copy_CPPFLAGS = -DMIO_TARGET='mio_copy' $(AM_CPPFLAGS) +examples_mio_copy_LDADD = $(top_builddir)/lib/libmio.la + +examples_mio_touch_CPPFLAGS = -DMIO_TARGET='mio_touch' $(AM_CPPFLAGS) +examples_mio_touch_LDADD = $(top_builddir)/lib/libmio.la + +examples_mio_unlink_CPPFLAGS = -DMIO_TARGET='mio_unlink' $(AM_CPPFLAGS) +examples_mio_unlink_LDADD = $(top_builddir)/lib/libmio.la + +examples_mio_hint_set_CPPFLAGS = -DMIO_TARGET='mio_hint_set' $(AM_CPPFLAGS) +examples_mio_hint_set_LDADD = $(top_builddir)/lib/libmio.la + +examples_mio_hint_stat_CPPFLAGS = -DMIO_TARGET='mio_hint_stat' $(AM_CPPFLAGS) +examples_mio_hint_stat_LDADD = $(top_builddir)/lib/libmio.la + +examples_mio_kvs_create_set_CPPFLAGS = -DMIO_TARGET='mio_kvs_create_set' $(AM_CPPFLAGS) +examples_mio_kvs_create_set_LDADD = $(top_builddir)/lib/libmio.la + +examples_mio_kvs_del_set_CPPFLAGS = -DMIO_TARGET='mio_kvs_del_set' $(AM_CPPFLAGS) +examples_mio_kvs_del_set_LDADD = $(top_builddir)/lib/libmio.la + +examples_mio_kvs_insert_CPPFLAGS = -DMIO_TARGET='mio_kvs_insert' $(AM_CPPFLAGS) +examples_mio_kvs_insert_LDADD = $(top_builddir)/lib/libmio.la + +examples_mio_kvs_retrieve_CPPFLAGS = -DMIO_TARGET='mio_kvs_retrieve' $(AM_CPPFLAGS) +examples_mio_kvs_retrieve_LDADD = $(top_builddir)/lib/libmio.la + +examples_mio_kvs_del_pairs_CPPFLAGS = -DMIO_TARGET='mio_kvs_del_pairs' $(AM_CPPFLAGS) +examples_mio_kvs_del_pairs_LDADD = $(top_builddir)/lib/libmio.la + +examples_mio_comp_obj_example_CPPFLAGS = -DMIO_TARGET='mio_comp_obj_example' $(AM_CPPFLAGS) +examples_mio_comp_obj_example_LDADD = $(top_builddir)/lib/libmio.la + +examples_mio_rw_threads_CPPFLAGS = -DMIO_TARGET='mio_comp_obj_example' $(AM_CPPFLAGS) +examples_mio_rw_threads_LDADD = $(top_builddir)/lib/libmio.la -lpthread -lcrypto -lssl + +include $(top_srcdir)/examples/Makefile.sub + +#------------------------------------------------------------------------------- +# Build rules # +#------------------------------------------------------------------------------- + +# vim: textwidth=80 nowrap foldmethod=marker diff --git a/deps/mio/NEWS b/deps/mio/NEWS new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/deps/mio/README b/deps/mio/README new file mode 100644 index 0000000000000000000000000000000000000000..5b7f343700dfbf87e91e136b9f3de0e07b30712c --- /dev/null +++ b/deps/mio/README @@ -0,0 +1,60 @@ + +Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, +All Rights Reserved + +This software is subject to the terms of the Mozilla Public License, v. 2.0. +If a copy of the MPL was not distributed with this file, You can obtain +one at http://mozilla.org/MPL/2.0/. + + +1. Build MIO library + +Uncompress the source code package. + +Run the following steps to build MIO library and examples. +(1) ./autogen.sh +(2) ./configure + if you install Mero rpms in a customized directory such as your home + directory or build Mero from source, run configure like this + + ./configure --with-libmero=libmero_directory --with-mero-headers=mero_headers_directory + +(3) make + +2. Run MIO examples + +MIO source code is shipped with varied examples. + +mio_rw_threads starts specified number of READ/WRITE threads. WRITE threads +create MIO objects and write data to them, and then inform the READ trheads +to read the written objects. READ threads will verify the data fetched from +objects. + +Run mio_rw_threads following the steps below: +(1) Start Mero (follow the Mero instruction) + +(2) cd tests +MIO provides a sample configuration file mio_config.yaml in this directory. +Edit mio_config.yaml to reflect Mero configurations in your system: (a) replace +the clovis local address, MERO_CLOVIS_INST_ADDR, to yours. (b) replace MERO_HA_ADDR +with your HA address. (c) MERO_PROFILE and MERO_PROCESS_FID (usually no need to +change these 2 parameters) + +Methods to get the above parameters: +(a) hctl mero status +(b) checkout /etc/mero/conf.xc to search strings for M0_CST_HA +(c) if your system is shipped with clovis sample apps, run + clovis-sample-app-dir/scripts/c0appzrcgen + +(3) sudo ../examples/mio_rw_threads -s 4096 -c 1 -n 10 -t 1 -y ./mio_config.yaml -o 1:12346800 + +Usage of mio_rw_thread + -o, --object FID Starting object ID + -n, --nr_objs INT The number of objects + -s, --block-size INT block size in bytes or with suffix b/k/m/g/K/M/G + -c, --block-count INT number of blocks written to an object with suffix b/k/m/g/K/M/G + -t, --threads Number of threads + -y, --mio_conf MIO YAML configuration file + -h, --help shows this help text and exit + +All MIO examples use 2 uint64_t to represent an object ID. diff --git a/deps/mio/autogen.sh b/deps/mio/autogen.sh new file mode 100755 index 0000000000000000000000000000000000000000..8eecac56c809038b29f41d17bb504d4fb6d1b197 --- /dev/null +++ b/deps/mio/autogen.sh @@ -0,0 +1,8 @@ +# Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, +# All Rights Reserved +# +# This software is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +autoreconf --install --force diff --git a/deps/mio/configure.ac b/deps/mio/configure.ac new file mode 100644 index 0000000000000000000000000000000000000000..d6eb403bd5fe7f4d60ad92b098b737eb9058cf89 --- /dev/null +++ b/deps/mio/configure.ac @@ -0,0 +1,328 @@ +# Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, +# All Rights Reserved +# +# This software is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# MIO version +m4_define([MIO_VERSION_MAJOR],[0]) +m4_define([MIO_VERSION_MINOR],[1]) +m4_define([MIO_VERSION_PATCH],[0]) +m4_define([MIO_VERSION],[MIO_VERSION_MAJOR.MIO_VERSION_MINOR.MIO_VERSION_PATCH]) + +# +# Autoconf/Automake/Libtool configuration +# + +AC_PREREQ(2.63) +AC_INIT([mio],[MIO_VERSION],[mio@seagate.com]) + +# The AC_PROG_CC macro sets CFLAGS to '-g -O2' by default if CFLAGS is not +# initialized by the user, we don't need this because we use a separate +# MIO_CFLAGS variable to control compiler's options while allowing user to +# override it via CFLAGS from command-line. +CFLAGS=${CFLAGS:=""} + +AM_INIT_AUTOMAKE([-Wall -Werror nostdinc foreign subdir-objects silent-rules]) +AM_SILENT_RULES([yes]) + +LT_INIT([disable-static]) + +AC_CONFIG_SRCDIR([src/mio.c]) +AC_CONFIG_MACRO_DIR([m4]) + +AC_CONFIG_HEADERS([config.h]) + +# +# Global variables +# + +# PACKAGE_VERSION is a default autoconf variable, generated by AC_INIT from +# it's "version" argument +AC_SUBST([LT_RELEASE], [$PACKAGE_VERSION]) + +# The value passed to libtool's `-version-info` parameter. +# +# [https://autotools.io/libtool/version.html#idm46422828083360] +# | +# | To set the version of the library, libtool provides the `-version-info` +# | parameter, which accepts three numbers, separated by colons, that are +# | called respectively, _current_, _revision_ and _age_. Both their name +# | and their behaviour, nowadays, have to be considered fully arbitrary, +# | as the explanation provided in the official documentation is confusing +# | to say the least, and can be, in some cases, considered completely wrong. +# | +# | *Warning* +# | +# | A common mistake is to assume that the three values passed to +# | `-version-info` map directly into the three numbers at the end of +# | the library name. This is not the case, and indeed, current, +# | revision and age are applied differently depending on the operating +# | system that one is using. +# +# E.g., LT_VERSION=1:1:0 results in mero/.libs/libmero.so.1.0.1 file. +# +# See also +# https://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning +AC_SUBST([LT_VERSION], [MIO_VERSION_MAJOR:MIO_VERSION_MINOR:MIO_VERSION_PATCH]) + +# the following variables are only for internal use within this configure script +# external scripts should use collection of variables, which is automatically +# provided by autoconf: +# +# @srcdir@ +# @top_srcdir@ +# @abs_top_srcdir@ +# @builddir@ +# @top_builddir@ +# @abs_top_builddir@ +# +SRCDIR="$srcdir" +ABS_SRCDIR="$(cd $srcdir; pwd)" +ABS_BUILDDIR="$(pwd)" +AC_SUBST([ABS_BUILDDIR]) + +AC_SUBST([MIO_VERSION_CODE], + ["$(( (MIO_VERSION_MAJOR << 24) + (MIO_VERSION_MINOR << 16) + (MIO_VERSION_PATCH << 8) ))U"] +) + +BUILD_HOST=$(hostname) +AC_SUBST([BUILD_HOST]) +AC_SUBST([BUILD_USER],["$(whoami)"]) +AC_SUBST([BUILD_TIME],["$(date -u)"]) +AC_SUBST([BUILD_GCC],["$(gcc -v 2>&1 | grep '^gcc version' | sed -e 's/(GCC)//')"]) + +#------------------------------------------------------------------------------- +# Checking for OS support +#------------------------------------------------------------------------------- + +AC_MSG_CHECKING([for operating system]) +AC_MSG_RESULT([$host_os]) + +AS_CASE([$host_os], + # supported operating systems: + [linux*], [], + # default action for unsupported OS is to abort with error + [AC_MSG_ERROR([Unsupported platform detected!])] +) + +#------------------------------------------------------------------------------# +# Configuration options # +#------------------------------------------------------------------------------# + +# define macros +AH_TEMPLATE([ENABLE_DEBUG], [Enable debug info and disable optimizations.]) +AH_TEMPLATE([MERO_LIB], [Mero library directory]) +AH_TEMPLATE([MERO_INCLUDE], [Directory for Mero development header files]) + +# enable/disable options +AC_ARG_ENABLE([debug], + [AS_HELP_STRING([--enable-debug], + [enable debug information and disable optimizations])], + [], [enable_debug=no] +) +AM_CONDITIONAL([ENABLE_DEBUG], + [test "x$enable_debug" = xyes]) + +# Set directories for default or customized libmero and Mero headers. +AC_ARG_WITH([libmero], + [AS_HELP_STRING([--with-libmero=path], + [set path to Mero library libmero, default is /usr/lib64])], + [LIBMERO=$with_libmero], + [LIBMERO=/usr/lib64] +) +AS_IF([test -z "$LIBMERO" || ! test -d "$LIBMERO/"], + [AC_MSG_ERROR([libmero not found! Please, install Mero package or \ +provide the path to a directory using --with-lustre option.])] +) +AC_SUBST([LIBMERO]) + +AC_ARG_WITH([mero-headers], + [AS_HELP_STRING([--with-mero-headers=path], + [set path to Mero headers, default is /usr/include/mero])], + [MERO_HEADERS=$with_mero_headers], + [MERO_HEADERS=/usr/include/mero] +) +AS_IF([test -z "$MERO_HEADERS" || ! test -d "$MERO_HEADERS/"], + [AC_MSG_ERROR([Mero headers not found! Please, install Mero headers or \ +provide the path to a directory using --with-mero-headers option.])] +) +AC_SUBST([MERO_HEADERS]) + +# +#------------------------------------------------------------------------------# +# Check required programs # +#------------------------------------------------------------------------------# + +AC_PROG_CC +AM_PROG_CC_C_O +AC_PROG_CPP +AC_PROG_AWK +AC_PROG_SED +AC_PROG_LN_S + +#------------------------------------------------------------------------------# +# Check required libraries # +#------------------------------------------------------------------------------# + +# pthread library is required for a subset of pthread_XXX funcs +AC_SEARCH_LIBS([pthread_create], [c pthread], [], + [pthread_create cannot be found! Try to install libc-devel or libpthread-devel.] +) + +#------------------------------------------------------------------------------# +# Check for required header files # +#------------------------------------------------------------------------------# + +AC_CHECK_HEADERS([fcntl.h malloc.h stdint.h stdlib.h string.h sys/time.h unistd.h]) + +AC_CHECK_HEADERS([pthread.h], [], [AC_MSG_ERROR([pthread.h cannot be found!])]) + +AC_HEADER_STDBOOL + +#------------------------------------------------------------------------------# +# Check required types # +#------------------------------------------------------------------------------# + +AC_TYPE_INT32_T +AC_TYPE_INT64_T +AC_TYPE_MODE_T +AC_TYPE_OFF_T +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_TYPE_SSIZE_T +AC_TYPE_UID_T +AC_TYPE_UINT16_T +AC_TYPE_UINT32_T +AC_TYPE_UINT64_T +AC_TYPE_UINT8_T + +AC_CHECK_TYPES([pthread_barrier_t], [], [], [[#include <pthread.h>]]) + +#------------------------------------------------------------------------------# +# Checking compiler characteristics # +#------------------------------------------------------------------------------# + +AC_CHECK_SIZEOF([long]) + +AC_MSG_CHECKING([whether target platform is a 64-bit one]) +AS_IF([test $ac_cv_sizeof_long -eq 8], + [AC_MSG_RESULT([yes])], + [ + AC_MSG_RESULT([no]) + AC_MSG_ERROR([Only 64bit platforms are supported!]) + ] +) + +AC_C_INLINE + +#------------------------------------------------------------------------------# +# Check required library functions # +#------------------------------------------------------------------------------# + +AC_FUNC_MALLOC +AC_CHECK_FUNCS([gettimeofday memset strchr strdup strstr strtoull]) + +# Check libyaml +AC_SEARCH_LIBS([yaml_parser_initialize], [yaml], [], + [yaml_parser_initialize cannot be found! Try install yaml package]) +AC_CHECK_HEADERS([yaml.h], [], + AC_MSG_ERROR([yaml.h is not found. Try to install libyaml-devel package])) + +# Check libmero +#AC_SEARCH_LIBS([m0_clovis_init], [mero], [], +# [m0_clovis_init cannot be found! Try install libmero package]) +#AC_CHECK_HEADERS([clovis/clovis.h], [], +# AC_MSG_ERROR([clovis.h is not found. Try to install libmero package])) + +#------------------------------------------------------------------------------# +# Handle configuration options # +#------------------------------------------------------------------------------# + +AS_IF([test x$enable_debug = xyes], + [ + MIO_CPPFLAGS="-DDEBUG $MIO_CPPFLAGS" + MIO_CFLAGS="-g -O0 $MIO_CFLAGS" + AC_DEFINE([ENABLE_DEBUG]) + ],[ + MIO_CFLAGS="-g -O2 $MIO_CFLAGS" + ] +) + +#------------------------------------------------------------------------------# +# Set up build variables # +#------------------------------------------------------------------------------# + +MIO_CPPFLAGS="-D_REENTRANT -D_GNU_SOURCE -DM0_INTERNAL='' -DM0_EXTERN=extern \ + -iquote'$ABS_BUILDDIR' -iquote'$SRCDIR' -include'config.h' \ + -I$MERO_HEADERS $MIO_CPPFLAGS" + +MIO_CPPFLAGS_DIST=$(echo "$MIO_CPPFLAGS" | grep -Po -e '-D\S+|-I/usr\S+' | xargs echo) + +# -Wno-attributes is required to suppress warnings about unrecognized +# __attribute__, such as __attribute__((gccxml(...))). It's important because we +# use -Werror, which turns warnings into errors, but we still need to be able to +# use gccxml attributes. +MIO_CFLAGS="-pipe -Wall -Werror -Wno-attributes -fno-strict-aliasing $MIO_CFLAGS" + +# Prevents gcc from introducing common symbols in object files. These symbols +# are avoided because they break the compilation toolchain that Parallel +# Scientific is using. +MIO_CFLAGS="-fno-common $MIO_CFLAGS" + +MIO_LDFLAGS="-rdynamic -L$LIBMERO $MIO_LDFLAGS" + +# trim spaces at the end of flags +MIO_CPPFLAGS=$(echo $MIO_CPPFLAGS | sed 's/[[[:blank:]]]*$//') +MIO_CFLAGS=$(echo $MIO_CFLAGS | sed 's/[[[:blank:]]]*$//') +MIO_LDFLAGS=$(echo $MIO_LDFLAGS | sed 's/[[[:blank:]]]*$//') + +AC_SUBST([MIO_CPPFLAGS]) +AC_SUBST([MIO_CPPFLAGS_DIST]) +AC_SUBST([MIO_CFLAGS]) +AC_SUBST([MIO_LDFLAGS]) + +AC_SUBST([BUILD_CONFIGURE_OPTS],["$ac_configure_args"]) +AC_SUBST([BUILD_CFLAGS],["$MIO_CPPFLAGS $MIO_CFLAGS $CPPFLAGS $CFLAGS"]) +AC_SUBST([BUILD_LDFLAGS],["$MIO_LDFLAGS"]) + +# +# Setup output files +# + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT + +# +# Display resulting values of some important build variables +# + +echo "" + +AS_IF([test "x$CFLAGS" != x], + [echo "CFLAGS : \"$CFLAGS\""]) +AS_IF([test "x$CPPFLAGS" != x], + [echo "CPPFLAGS : \"$CPPFLAGS\""]) +AS_IF([test "x$LDFLAGS" != x], + [echo "LDFLAGS : \"$LDFLAGS\""]) +AS_IF([test "x$LIBS" != x], + [echo "LIBS : \"$LIBS\""]) + +echo "" +echo "MIO version : $PACKAGE_VERSION" +echo "" +echo "CONFIGURE_OPTS: $BUILD_CONFIGURE_OPTS" +echo "" +echo "LIBMERO : \"$LIBMERO\"" +echo "MERO_HEADERS : \"$MERO_HEADERS\"" +echo "" +echo "MIO_CPPFLAGS : \"$MIO_CPPFLAGS\"" +echo "MIO_CFLAGS : \"$MIO_CFLAGS\"" +echo "MIO_LDFLAGS : \"$MIO_LDFLAGS\"" +echo "" +echo "Gcc : \"$BUILD_GCC\"" +echo "" +echo 'Run `make` to build MIO or `make help` for other options' + +# vim: tabstop=4 shiftwidth=4 expandtab textwidth=80 nowrap foldmethod=marker diff --git a/deps/mio/examples/Makefile.sub b/deps/mio/examples/Makefile.sub new file mode 100644 index 0000000000000000000000000000000000000000..28d6e283e4b1bba33e307abc079a55991060dc45 --- /dev/null +++ b/deps/mio/examples/Makefile.sub @@ -0,0 +1,50 @@ +# Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, +# All Rights Reserved +# +# This software is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +examples_mio_cat_SOURCES = examples/mio_cat.c examples/obj.c \ + examples/obj_io_poll.c examples/obj_io_cbs.c \ + examples/helpers.c + +examples_mio_copy_SOURCES = examples/mio_copy.c examples/obj.c \ + examples/obj_io_poll.c examples/obj_io_cbs.c \ + examples/helpers.c + +examples_mio_rw_threads_SOURCES = examples/mio_rw_threads.c \ + examples/obj.c examples/obj_io_poll.c \ + examples/helpers.c + +examples_mio_touch_SOURCES = examples/mio_touch.c examples/obj.c \ + examples/helpers.c + +examples_mio_unlink_SOURCES = examples/mio_unlink.c examples/obj.c \ + examples/helpers.c + +examples_mio_hint_set_SOURCES = examples/mio_hint_set.c examples/obj.c \ + examples/helpers.c + +examples_mio_hint_stat_SOURCES = examples/mio_hint_stat.c examples/obj.c \ + examples/helpers.c + +examples_mio_comp_obj_example_SOURCES = examples/mio_comp_obj.c examples/obj.c \ + examples/helpers.c + +examples_mio_kvs_create_set_SOURCES = examples/mio_kvs_create_set.c examples/kvs.c \ + examples/helpers.c + +examples_mio_kvs_del_set_SOURCES = examples/mio_kvs_del_set.c examples/kvs.c \ + examples/helpers.c + +examples_mio_kvs_insert_SOURCES = examples/mio_kvs_insert.c examples/kvs.c \ + examples/helpers.c + +examples_mio_kvs_retrieve_SOURCES = examples/mio_kvs_retrieve.c examples/kvs.c \ + examples/helpers.c + +examples_mio_kvs_del_pairs_SOURCES = examples/mio_kvs_del_pairs.c examples/kvs.c \ + examples/helpers.c + diff --git a/deps/mio/examples/helpers.c b/deps/mio/examples/helpers.c new file mode 100644 index 0000000000000000000000000000000000000000..105df9945668cb2c6112679e0bf8f47ddae1a14b --- /dev/null +++ b/deps/mio/examples/helpers.c @@ -0,0 +1,76 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <errno.h> + +#include "src/mio.h" + +int mio_cmd_strtou64(const char *arg, uint64_t *out) +{ + char *end = NULL; + char *pos; + static const char suffix[] = "bkmgKMG"; + int rc = 0; + + static const uint64_t multiplier[] = { + 1 << 9, + 1 << 10, + 1 << 20, + 1 << 30, + 1000, + 1000 * 1000, + 1000 * 1000 * 1000 + }; + + *out = strtoull(arg, &end, 0); + + if (*end != 0 && rc == 0) { + pos = strchr(suffix, *end); + if (pos != NULL) { + if (*out <= UINT64_MAX / multiplier[pos - suffix]) + *out *= multiplier[pos - suffix]; + else + rc = -EOVERFLOW; + } else + rc = -EINVAL; + } + return rc; +} + +int mio_cmd_wait_on_op(struct mio_op *op) +{ + struct mio_pollop pop; + + memset(&pop, 0, sizeof pop); + pop.mp_op = op; + mio_op_poll(&pop, 1, MIO_TIME_NEVER); + return op->mop_rc; +} + +uint32_t mio_cmd_random(uint32_t max) +{ + return (uint32_t)random() % max; +} + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/examples/helpers.h b/deps/mio/examples/helpers.h new file mode 100644 index 0000000000000000000000000000000000000000..7db3bcef34758a41fcd7f0af6626e697cc371402 --- /dev/null +++ b/deps/mio/examples/helpers.h @@ -0,0 +1,33 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#ifndef __HELPERS_H__ +#define __HELPERS_H__ + +int mio_cmd_strtou64(const char *arg, uint64_t *out); +int mio_cmd_wait_on_op(struct mio_op *op); +uint32_t mio_cmd_random(uint32_t max); + +#endif /* __HELPERS_H__ */ + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/examples/kvs.c b/deps/mio/examples/kvs.c new file mode 100644 index 0000000000000000000000000000000000000000..9719b914a7c6c34a094d60b6d330ab15d7eaf651 --- /dev/null +++ b/deps/mio/examples/kvs.c @@ -0,0 +1,454 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <getopt.h> +#include <asm/byteorder.h> + +#include "kvs.h" +#include "helpers.h" + +struct kvs_id_uint128 { + uint64_t k_hi; + uint64_t k_lo; +}; + +enum { + KVS_MAX_KEY_LEN = 64, + KVS_MAX_VAL_LEN = 64, + KVS_MAX_NR_PAIRS_PER_OP = 1024 +}; + +#define KVS_VAL_STRING ("Hidden Gnome") + +static int kvs_id_sscanf(char *idstr, struct mio_kvs_id *kid) +{ + int rc; + int n; + uint64_t u1; + uint64_t u2; + + rc = sscanf(idstr, "%"SCNx64" : %"SCNx64" %n", &u1, &u2, &n); + if (rc < 0) + return rc; + u1 = __cpu_to_be64(u1); + u2 = __cpu_to_be64(u2); + + memcpy(kid->mki_bytes, &u1, sizeof u1); + memcpy(kid->mki_bytes + sizeof u1, &u2, sizeof u2); + return 0; +} + +static void kvs_id_to_uint128(struct kvs_id_uint128 *kid128, + struct mio_kvs_id *kid) +{ + uint8_t *ptr; + uint64_t u1; + uint64_t u2; + + ptr = kid->mki_bytes; + memcpy(&u1, ptr, sizeof u1); + ptr += sizeof u1; + memcpy(&u2, ptr, sizeof u2); + + u1 = __be64_to_cpu(u1); + u2 = __be64_to_cpu(u2); + kid128->k_hi = u1; + kid128->k_lo = u2; +} + +static void kvs_free_pairs(struct mio_kv_pair *pairs) +{ + if (pairs != NULL) + free(pairs); +} + +static struct mio_kv_pair* kvs_alloc_pairs(int nr) +{ + struct mio_kv_pair *pairs; + + pairs = malloc(nr * sizeof(struct mio_kv_pair)); + return pairs; +} + +static +int kvs_fill_pairs(struct mio_kvs_id *kid, struct mio_kv_pair *pairs, + int start_kno, int nr_pairs, bool set_vals) +{ + int i; + int rc; + int klen = 0; + int vlen = 0; + char *prefix = NULL; + char *tmp_str = NULL; + char *key_str = NULL; + char *val_str = NULL; + struct kvs_id_uint128 id128; + + if (pairs == NULL) + return -EINVAL; + + rc = -ENOMEM; + prefix = malloc(KVS_MAX_KEY_LEN); + if (prefix == NULL) + goto error; + + tmp_str = malloc(KVS_MAX_KEY_LEN); + if (tmp_str == NULL) + goto error; + + /* + * Keys are flled with this format (index fid:key's serial number). + */ + kvs_id_to_uint128(&id128, kid); + for (i = 0; i < nr_pairs; i++) { + sprintf(tmp_str, + "%"PRIx64":%"PRIx64":%d", + id128.k_hi, id128.k_lo, start_kno + i); + klen = strlen(tmp_str) + 1; + key_str = malloc(klen); + if (key_str == NULL) + goto error; + strncpy(key_str, tmp_str, klen); + pairs[i].mkp_klen = klen; + pairs[i].mkp_key = key_str; + + if (set_vals) { + memset(tmp_str, 0, KVS_MAX_KEY_LEN); + sprintf(tmp_str, "%s %d", + KVS_VAL_STRING, (int)mio_cmd_random(nr_pairs)); + vlen = strlen(tmp_str) + 1; + val_str = malloc(vlen); + if (val_str == NULL) + goto error; + strncpy(val_str, tmp_str, vlen); + pairs[i].mkp_vlen = vlen; + pairs[i].mkp_val = val_str; + } + } + + return 0; + +error: + if (prefix) + free(prefix); + if (tmp_str) + free(tmp_str); + if (key_str) + free(key_str); + if (val_str) + free(val_str); + + for (i = 0; i < nr_pairs; ++i) { + if (pairs[i].mkp_key) + free(pairs[i].mkp_key); + if (pairs[i].mkp_val) + free(pairs[i].mkp_val); + pairs[i].mkp_klen = 0; + pairs[i].mkp_vlen = 0; + } + + return rc; +} + +static void +kvs_print_pairs(struct mio_kv_pair *pairs, int nr_pairs, FILE *log) +{ + int i; + + for (i = 0; i < nr_pairs; i++) { + fprintf(log, "%s\t\t%s\n", + (char *)pairs[i].mkp_key, (char *)pairs[i].mkp_val); + } +} + +static int kvs_create_set(struct mio_kvs_id *kid) +{ + int rc; + struct mio_op op; + + rc = mio_kvs_create_set(kid, &op); + if (rc != 0) + return rc; + + rc = mio_cmd_wait_on_op(&op); + if (rc < 0) + fprintf(stderr, "Failed in creating an KVS set!\n"); + + return rc; +} + +static int kvs_delete_set(struct mio_kvs_id *kid) +{ + int rc; + struct mio_op op; + + rc = mio_kvs_del_set(kid, &op); + if (rc != 0) + return rc; + + rc = mio_cmd_wait_on_op(&op); + if (rc < 0) + fprintf(stderr, "Failed in creating an KVS set!\n"); + + return rc; +} + +static int +kvs_query_put(struct mio_kvs_id *kid, int start_kno, int nr_kvp, FILE *log) +{ + int rc; + int *rcs; + struct mio_op op; + struct mio_kv_pair *pairs; + + rcs = malloc(nr_kvp * sizeof(int)); + if (rcs == NULL) + return -ENOMEM; + + pairs = kvs_alloc_pairs(nr_kvp); + if (pairs == NULL) { + free(rcs); + return -ENOMEM; + } + kvs_fill_pairs(kid, pairs, start_kno, nr_kvp, true); + if (log) + kvs_print_pairs(pairs, nr_kvp, log); + + rc = mio_kvs_pair_put(kid, nr_kvp, pairs, rcs, &op); + if (rc != 0) + return rc; + + rc = mio_cmd_wait_on_op(&op); + if (rc < 0) + fprintf(stderr, "Failed in inserting kv pairs to aset!\n"); + + kvs_free_pairs(pairs); + return rc; +} + +static int +kvs_query_get(struct mio_kvs_id *kid, int start_kno, int nr_kvp, FILE *log) +{ + int rc; + int *rcs; + struct mio_op op; + struct mio_kv_pair *pairs; + + rcs = malloc(nr_kvp * sizeof(int)); + if (rcs == NULL) + return -ENOMEM; + pairs = kvs_alloc_pairs(nr_kvp); + if (pairs == NULL) { + free(rcs); + return -ENOMEM; + } + kvs_fill_pairs(kid, pairs, start_kno, nr_kvp, false); + + rc = mio_kvs_pair_get(kid, nr_kvp, pairs, rcs, &op); + if (rc != 0) + return rc; + + rc = mio_cmd_wait_on_op(&op); + if (rc < 0) + fprintf(stderr, "Failed in retrieving kv pairs to aset!\n"); + + if (rc == 0 && log != NULL) + kvs_print_pairs(pairs, nr_kvp, log); + + kvs_free_pairs(pairs); + return rc; +} + +static int +kvs_query_del(struct mio_kvs_id *kid, int start_kno, int nr_kvp, FILE *log) +{ + int rc; + int *rcs; + struct mio_op op; + struct mio_kv_pair *pairs; + + rcs = malloc(nr_kvp * sizeof(int)); + if (rcs == NULL) + return -ENOMEM; + pairs = kvs_alloc_pairs(nr_kvp); + if (pairs == NULL) { + free(rcs); + return -ENOMEM; + } + kvs_fill_pairs(kid, pairs, start_kno, nr_kvp, false); + if (log != NULL) + kvs_print_pairs(pairs, nr_kvp,log); + + rc = mio_kvs_pair_del(kid, nr_kvp, pairs, rcs, &op); + if (rc != 0) + return rc; + + rc = mio_cmd_wait_on_op(&op); + if (rc < 0) + fprintf(stderr, "Failed in retrieving kv pairs to aset!\n"); + + kvs_free_pairs(pairs); + return rc; +} + +int mio_cmd_kvs_create_set(struct mio_kvs_id *kid) +{ + return kvs_create_set(kid); +} + +int mio_cmd_kvs_delete_set(struct mio_kvs_id *kid) +{ + return kvs_delete_set(kid); +} + +int mio_cmd_kvs_insert_pairs(struct mio_kvs_id *kid, + int start_kno, int nr_pairs, FILE *log) +{ + int rc = 0; + int nr_pairs_op; + + while(nr_pairs > 0) { + nr_pairs_op = nr_pairs > KVS_MAX_NR_PAIRS_PER_OP? + KVS_MAX_NR_PAIRS_PER_OP : nr_pairs; + rc = kvs_query_put(kid, start_kno, nr_pairs_op, log); + if (rc != 0) + break; + nr_pairs -= nr_pairs_op; + start_kno += nr_pairs_op; + } + + return rc; +} + +int mio_cmd_kvs_retrieve_pairs(struct mio_kvs_id *kid, + int start_kno, int nr_pairs, FILE *log) +{ + int rc = 0; + int nr_pairs_op; + + while(nr_pairs > 0) { + nr_pairs_op = nr_pairs > KVS_MAX_NR_PAIRS_PER_OP? + KVS_MAX_NR_PAIRS_PER_OP : nr_pairs; + + rc = kvs_query_get(kid, start_kno, nr_pairs_op, log); + if (rc != 0) + break; + nr_pairs -= nr_pairs_op; + start_kno += nr_pairs_op; + } + + return rc; +} + +int mio_cmd_kvs_del_pairs(struct mio_kvs_id *kid, + int start_kno, int nr_pairs, FILE *log) +{ + int rc = 0; + int nr_pairs_op; + + while(nr_pairs > 0) { + nr_pairs_op = nr_pairs > KVS_MAX_NR_PAIRS_PER_OP? + KVS_MAX_NR_PAIRS_PER_OP : nr_pairs; + + rc = kvs_query_del(kid, start_kno, nr_pairs_op, log); + if (rc != 0) + break; + nr_pairs -= nr_pairs_op; + start_kno += nr_pairs_op; + } + + return rc; +} + +int mio_cmd_kvs_args_init(int argc, char **argv, + struct mio_cmd_kvs_params *params, + void (*usage)(FILE *, char *)) +{ + int v; + int option_index = 0; + static struct option l_opts[] = { + {"kvs", required_argument, NULL, 'k'}, + {"start_key", required_argument, NULL, 's'}, + {"nr_pairs", required_argument, NULL, 'n'}, + {"mio_conf", required_argument, NULL, 'y'}, + {"log_file", required_argument, NULL, 'l'}, + {"help", no_argument, NULL, 'h'}, + {0, 0, 0, 0 }}; + + memset(params, 0, sizeof *params); + params->ckp_nr_pairs = 1; + + while ((v = getopt_long(argc, argv, ":k:s:n:y:l:h", l_opts, + &option_index)) != -1) + { + switch (v) { + case 'k': + kvs_id_sscanf(optarg, ¶ms->ckp_kid); + continue; + case 's': + params->ckp_start_kno = atoi(optarg); + continue; + case 'n': + params->ckp_nr_pairs = atoi(optarg); + continue; + case 'y': + params->ckp_conf_fname = strdup(optarg); + if (params->ckp_conf_fname == NULL) + exit(EXIT_FAILURE); + continue; + case 'l': + params->ckp_log = strdup(optarg); + if (params->ckp_log == NULL) + exit(EXIT_FAILURE); + continue; + case 'h': + usage(stderr, basename(argv[0])); + exit(EXIT_FAILURE); + case '?': + fprintf(stderr, "Unsupported option '%c'\n", + optopt); + usage(stderr, basename(argv[0])); + exit(EXIT_FAILURE); + case ':': + fprintf(stderr, "No argument given for '%c'\n", + optopt); + usage(stderr, basename(argv[0])); + exit(EXIT_FAILURE); + default: + fprintf(stderr, "Unsupported option '%c'\n", v); + } + } + + return 0; +} + +void mio_cmd_kvs_args_fini(struct mio_cmd_kvs_params *params) +{ + if(params->ckp_conf_fname) + free(params->ckp_conf_fname); + if (params->ckp_log) + free(params->ckp_log); +} +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/examples/kvs.h b/deps/mio/examples/kvs.h new file mode 100644 index 0000000000000000000000000000000000000000..2ab33542fe21fd1c458081779eb85fb882f84455 --- /dev/null +++ b/deps/mio/examples/kvs.h @@ -0,0 +1,63 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#ifndef __KVS_H__ +#define __KVS_H__ + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/time.h> + +#include "src/mio.h" + +struct mio_cmd_kvs_params { + char *ckp_conf_fname; + + struct mio_kvs_id ckp_kid; + int ckp_nr_pairs; + int ckp_start_kno; + + char *ckp_log; +}; + +int mio_cmd_kvs_args_init(int argc, char **argv, + struct mio_cmd_kvs_params *params, + void (*usage)(FILE *, char *)); +void mio_cmd_kvs_args_fini(struct mio_cmd_kvs_params *params); + +int mio_cmd_kvs_create_set(struct mio_kvs_id *kid); +int mio_cmd_kvs_delete_set(struct mio_kvs_id *kid); + +int mio_cmd_kvs_insert_pairs(struct mio_kvs_id *kid, + int start_kno, int nr_pairs, FILE *log); +int mio_cmd_kvs_retrieve_pairs(struct mio_kvs_id *kid, + int start_kno, int nr_pairs, FILE *log); +int mio_cmd_kvs_del_pairs(struct mio_kvs_id *kid, + int start_kno, int nr_pairs, FILE *log); + +#endif /* __KVS_H__ */ + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/examples/mio_cat.c b/deps/mio/examples/mio_cat.c new file mode 100644 index 0000000000000000000000000000000000000000..ef29cf024ce33d241ab971b90f173bbd9bb1e378 --- /dev/null +++ b/deps/mio/examples/mio_cat.c @@ -0,0 +1,82 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "obj.h" + +static void cat_usage(FILE *file, char *prog_name) +{ + fprintf(file, "Usage: %s [OPTION]... OUTPUT_FILE\n" +"DISPLAY an MIO object's content to OUTPUT_FILE.\n" +"\n" +"Mandatory arguments to long options are mandatory for short options too.\n" +" -o, --object OID ID of the mero object\n" +" -s, --block-size INT block size in bytes or with " \ + "suffix b/k/m/g/K/M/G (see --block-count)\n" +" -c, --block-count INT number of blocks for IO, can give with " \ + "suffix b/k/m/g/K/M/G (see --block-size)\n" +" -a, --async_mode Set to async IO mode\n" +" -y, --mio_conf_file MIO YAML configuration file\n" +" -h, --help shows this help text and exit\n" +, prog_name); +} + +int main(int argc, char **argv) +{ + int rc; + struct mio_cmd_obj_params cat_params; + char *dst_fname = NULL; + + mio_cmd_obj_args_init(argc, argv, &cat_params, &cat_usage); + if (argv[optind] != NULL) + dst_fname = strdup(argv[optind]); + if (cat_params.cop_async_mode && dst_fname == NULL) { + fprintf(stderr, "Missed source file to write to !\n"); + cat_usage(stderr, basename(argv[0])); + exit(-1); + } + + rc = mio_init(cat_params.cop_conf_fname); + if (rc < 0) { + fprintf(stderr, "mio_init failed! rc = %d\n", rc); + exit(EXIT_FAILURE); + } + + rc = cat_params.cop_async_mode? + mio_cmd_obj_read_async(&cat_params.cop_oid, dst_fname, + cat_params.cop_block_size, + cat_params.cop_block_count) : + mio_cmd_obj_read(&cat_params.cop_oid, dst_fname, + cat_params.cop_block_size, + cat_params.cop_block_count); + if (rc < 0) + fprintf(stderr, "mio_cmd_obj_read failed! rc = %d\n", rc); + + mio_fini(); + if (dst_fname) + free(dst_fname); + mio_cmd_obj_args_fini(&cat_params); + return rc; +} + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/examples/mio_comp_obj.c b/deps/mio/examples/mio_comp_obj.c new file mode 100644 index 0000000000000000000000000000000000000000..c2cf66e76d89a8f145e609dfa17ea1c2c5c34e68 --- /dev/null +++ b/deps/mio/examples/mio_comp_obj.c @@ -0,0 +1,400 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <asm/byteorder.h> + +#include "obj.h" +#include "helpers.h" + +static void comp_obj_usage(FILE *file, char *prog_name) +{ + fprintf(file, "Usage: %s [OPTION]...\n" +"Examples for composite object APIs.\n" +"\n" +"Mandatory arguments to long options are mandatory for short options too.\n" +" -o, --object OID ID of the mero object\n" +" -y, --mio_conf_file MIO YAML configuration file\n" +" -h, --help shows this help text and exit\n" +, prog_name); +} + +/** + * Calculate the layer's ids from composite object id. Here we + * naviely assume a simple relation between composite object id + * and layers'. + */ +static void layer_ids_get(struct mio_obj_id *oid, int nr_layers, + struct mio_obj_id *layer_ids) +{ + int i; + uint64_t u1; + uint64_t u2; + uint64_t n1; + uint64_t n2; + struct mio_obj_id *layer_id; + + memcpy(&u1, oid->moi_bytes, sizeof u1); + memcpy(&u2, oid->moi_bytes + sizeof u1, sizeof u2); + u1 = __be64_to_cpu(u1); + u2 = __be64_to_cpu(u2); + + for (i = 0; i < nr_layers; i++) { + layer_id = layer_ids + i; + n1 = u1 + i + 1; + n2 = u2; + n1 = __cpu_to_be64(n1); + n2 = __cpu_to_be64(n2); + memcpy(layer_id->moi_bytes, &n1, sizeof n1); + memcpy(layer_id->moi_bytes + sizeof n1, &n2, sizeof n2); + } +} + +static int +comp_obj_add_extents(struct mio_obj *obj, int nr_layers, int nr_exts) +{ + int i; + int j; + int rc = 0; + struct mio_obj_id *layer_ids; + struct mio_obj_ext *exts; + struct mio_op op; + + layer_ids = malloc(nr_layers * sizeof(*layer_ids)); + exts = malloc(nr_exts * sizeof(*exts)); + if (layer_ids == NULL || exts == NULL) { + rc = -ENOMEM; + goto exit; + } + layer_ids_get(&obj->mo_id, nr_layers, layer_ids); + + for (i = 0; i < nr_layers; i++) { + for (j = 0; j < nr_exts; j++) { + exts[j].moe_off = (i * nr_exts + j) * 4096 * 4096; + exts[j].moe_size = 4096 * 4096; + } + + mio_op_init(&op); + rc = mio_composite_obj_add_extents( + obj, layer_ids + i, nr_exts, exts, &op) ? : + mio_cmd_wait_on_op(&op); + mio_op_fini(&op); + if (rc < 0) + break; + } + + /* + * Note: the example here doesn't clean-up the extents + * that have been added if there is an error. + */ + +exit: + free(layer_ids); + free(exts); + return rc; +} + +static int +comp_obj_del_extents(struct mio_obj *obj, int nr_layers, int nr_exts) +{ + int i; + int j; + int rc = 0; + struct mio_obj_id *layer_ids; + struct mio_obj_ext *exts; + struct mio_op op; + + layer_ids = malloc(nr_layers * sizeof(*layer_ids)); + exts = malloc(nr_exts * sizeof(*exts)); + if (layer_ids == NULL || exts == NULL) { + rc = -ENOMEM; + goto exit; + } + layer_ids_get(&obj->mo_id, nr_layers, layer_ids); + + for (i = 0; i < nr_layers; i++) { + for (j = 0; j < nr_exts; j++) { + exts[j].moe_off = (i * nr_exts + j) * 4096 * 4096; + exts[j].moe_size = 4096 * 4096; + } + + mio_op_init(&op); + rc = mio_composite_obj_del_extents( + obj, layer_ids + i, nr_exts, exts, &op)? : + mio_cmd_wait_on_op(&op); + mio_op_fini(&op); + if (rc < 0) + break; + } + +exit: + free(layer_ids); + free(exts); + return rc; +} + +static int +comp_obj_list_extents(struct mio_obj *obj, int nr_layers, int nr_exts) +{ + int i; + int j; + int rc = 0; + int nr_ret_exts; + off_t offset; + struct mio_obj_id *layer_ids; + struct mio_obj_ext *exts; + struct mio_op op; + + layer_ids = malloc(nr_layers * sizeof(*layer_ids)); + exts = malloc(nr_exts * sizeof(*exts)); + if (layer_ids == NULL || exts == NULL) { + rc = -ENOMEM; + goto exit; + } + layer_ids_get(&obj->mo_id, nr_layers, layer_ids); + + for (i = 0; i < nr_layers; i++) { + offset = 0; //i * nr_exts * 4096 * 4096; + + mio_op_init(&op); + rc = mio_composite_obj_get_extents( + obj, layer_ids + i, offset, nr_exts, exts, + &nr_ret_exts, &op)? : + mio_cmd_wait_on_op(&op); + mio_op_fini(&op); + if (rc < 0) + continue; + + for (j = 0; j < nr_ret_exts; j++) { + fprintf(stderr, "layer %d: (%ld, %ld)\n", + i, exts[j].moe_off, exts[j].moe_size); + } + } + +exit: + free(layer_ids); + free(exts); + return rc; +} + + +static int comp_obj_add_layers(struct mio_obj *obj, int nr_layers) +{ + int i; + int rc = 0; + struct mio_comp_obj_layer *layers; + struct mio_obj_id *layer_ids; + struct mio_op op; + + layers = malloc(nr_layers * sizeof(*layers)); + layer_ids = malloc(nr_layers * sizeof(*layer_ids)); + if (layers == NULL || layer_ids == NULL) { + rc = -ENOMEM; + goto exit; + } + layer_ids_get(&obj->mo_id, nr_layers, layer_ids); + + /* Create objects for each layer. */ + for (i = 0; i < nr_layers; i++) { + rc = mio_cmd_obj_touch(layer_ids + i); + if (rc < 0) + goto exit; + } + + /* Add layers to the composite object. */ + for (i = 0; i < nr_layers; i++) { + layers[i].mcol_priority = 0; + memcpy(&layers[i].mcol_oid, layer_ids + i, + sizeof(struct mio_obj_id)); + } + + mio_op_init(&op); + rc = mio_composite_obj_add_layers(obj, nr_layers, layers, &op)? : + mio_cmd_wait_on_op(&op); + mio_op_fini(&op); + +exit: + if (layers != NULL) + free(layers); + if (layer_ids != NULL) + free(layer_ids); + return rc; +} + +static int comp_obj_del_layers(struct mio_obj *obj, int nr_layers) +{ + int i; + int rc = 0; + struct mio_comp_obj_layer *layers; + struct mio_obj_id *layer_ids; + struct mio_op op; + + layers = malloc(nr_layers * sizeof(*layers)); + layer_ids = malloc(nr_layers * sizeof(*layer_ids)); + if (layers == NULL || layer_ids == NULL) + return -ENOMEM; + layer_ids_get(&obj->mo_id, nr_layers, layer_ids); + + for (i = 0; i < nr_layers; i++) + /* No need to set priority for deleting layers. */ + memcpy(&layers[i].mcol_oid, layer_ids + i, + sizeof(struct mio_obj_id)); + + mio_op_init(&op); + rc = mio_composite_obj_del_layers(obj, nr_layers, layers, &op)? : + mio_cmd_wait_on_op(&op); + mio_op_fini(&op); + + free(layer_ids); + return rc; +} + +static int comp_obj_list_layers(struct mio_obj *obj) +{ + int i; + int rc = 0; + struct mio_comp_obj_layout layout; + struct mio_op op; + + mio_op_init(&op); + rc = mio_composite_obj_list_layers(obj, &layout, &op)? : + mio_cmd_wait_on_op(&op); + mio_op_fini(&op); + if (rc < 0) + return rc; + + for (i = 0; i < layout.mlo_nr_layers; i++) { + fprintf(stderr, "Layer %d -- ", i); + obj_id_printf(&layout.mlo_layers[i].mcol_oid); + fprintf(stderr, "\n"); + } + return 0; +} + +static int comp_obj_create(struct mio_obj_id *oid, struct mio_obj *obj) +{ + int rc; + struct mio_op op; + + memset(&op, 0, sizeof op); + rc = obj_open(oid, obj); + if (rc == 0) { + fprintf(stderr, "Object exists!\n"); + return -EEXIST; + } else if (rc == -ENOENT) + goto step_1; + else + return rc; + +step_1: + memset(&op, 0, sizeof op); + rc = mio_obj_create(oid, NULL, obj, &op)? : + mio_cmd_wait_on_op(&op); + if (rc < 0) + return rc; + + /* step_2: */ + memset(&op, 0, sizeof op); + rc = mio_composite_obj_create(oid, obj, &op)? : + mio_cmd_wait_on_op(&op); + if (rc < 0) { + mio_obj_close(obj); + return rc; + } + + return rc; +} + +int main(int argc, char **argv) +{ + int rc; + struct mio_cmd_obj_params comp_obj_params; + struct mio_obj obj; + + mio_cmd_obj_args_init(argc, argv, &comp_obj_params, &comp_obj_usage); + + rc = mio_init(comp_obj_params.cop_conf_fname); + if (rc < 0) { + fprintf(stderr, "mio_init failed! rc = %d\n", rc); + exit(EXIT_FAILURE); + } + + fprintf(stderr, "MIO composite example ...\n"); + + fprintf(stderr, "1. Create a composite object ..."); + rc = comp_obj_create(&comp_obj_params.cop_oid, &obj); + if (rc < 0) { + fprintf(stderr, "failed!\n"); + goto exit; + } else + fprintf(stderr, "success!\n"); + + fprintf(stderr, "2. Add layers ..."); + rc = comp_obj_add_layers(&obj, 3); + if (rc < 0) { + fprintf(stderr, "failed!\n"); + goto exit; + } else + fprintf(stderr, "success!\n"); + + rc = comp_obj_list_layers(&obj); + if (rc < 0) + goto exit; + + fprintf(stderr, "3. Add extents to layers ..."); + rc = comp_obj_add_extents(&obj, 3, 1); + if (rc < 0) { + fprintf(stderr, "failed!\n"); + goto exit; + } else + fprintf(stderr, "success!\n"); + + fprintf(stderr, "4. List extents of layers ...\n"); + rc = comp_obj_list_extents(&obj, 3, 1); + if (rc < 0) + goto exit; + + fprintf(stderr, "5. Del extents of layers ..."); + rc = comp_obj_del_extents(&obj, 1, 1); + if (rc < 0) { + fprintf(stderr, "failed!\n"); + goto exit; + } else + fprintf(stderr, "success!\n"); + + fprintf(stderr, "6. Del layers ..."); + rc = comp_obj_del_layers(&obj, 1); + if (rc < 0) { + fprintf(stderr, "failed!\n"); + goto exit; + } else + fprintf(stderr, "success!\n"); + + mio_obj_close(&obj); + +exit: + mio_fini(); + mio_cmd_obj_args_fini(&comp_obj_params); + return rc; +} + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/examples/mio_copy.c b/deps/mio/examples/mio_copy.c new file mode 100644 index 0000000000000000000000000000000000000000..2f8e641deb9ca2dd3f4e793470f976a9a6331ae2 --- /dev/null +++ b/deps/mio/examples/mio_copy.c @@ -0,0 +1,81 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "obj.h" + +static void copy_usage(FILE *file, char *prog_name) +{ + fprintf(file, "Usage: %s [OPTION]... SOURCE\n" +"Copy SOURCE to MIO.\n" +"\n" +"Mandatory arguments to long options are mandatory for short options too.\n" +" -o, --object OID ID of the mero object\n" +" -s, --block-size INT block size in bytes or with " \ + "suffix b/k/m/g/K/M/G (see --block-count)\n" +" -c, --block-count INT number of blocks to copy, can give with " \ + "suffix b/k/m/g/K/M/G (see --block-size)\n" +" -a, --async_mode Set to async IO mode\n" +" -y, --mio_conf_file MIO YAML configuration file\n" +" -h, --help shows this help text and exit\n" +, prog_name); +} + +int main(int argc, char **argv) +{ + int rc; + struct mio_cmd_obj_params copy_params; + char *src_fname = NULL; + + mio_cmd_obj_args_init(argc, argv, ©_params, ©_usage); + if (argv[optind] != NULL) + src_fname = strdup(argv[optind]); + if (src_fname == NULL) { + fprintf(stderr, "Missed source file to copy !\n"); + copy_usage(stderr, basename(argv[0])); + exit(-1); + } + + rc = mio_init(copy_params.cop_conf_fname); + if (rc < 0) { + fprintf(stderr, "mio_init failed! rc = %d\n", rc); + exit(EXIT_FAILURE); + } + + rc = copy_params.cop_async_mode? + mio_cmd_obj_write_async(src_fname, ©_params.cop_oid, + copy_params.cop_block_size, + copy_params.cop_block_count) : + mio_cmd_obj_write(src_fname, ©_params.cop_oid, + copy_params.cop_block_size, + copy_params.cop_block_count); + if (rc < 0) + fprintf(stderr, "mio_cmd_obj_write failed! rc = %d\n", rc); + + mio_fini(); + free(src_fname); + mio_cmd_obj_args_fini(©_params); + return rc; +} + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/examples/mio_hint_set.c b/deps/mio/examples/mio_hint_set.c new file mode 100644 index 0000000000000000000000000000000000000000..47cbe70b375b878abca699e89443a0804c4f28fd --- /dev/null +++ b/deps/mio/examples/mio_hint_set.c @@ -0,0 +1,89 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "obj.h" + +static void hset_usage(FILE *file, char *prog_name) +{ + fprintf(file, "Usage: %s [OPTION]...\n" +"Create an object.\n" +"\n" +"Mandatory arguments to long options are mandatory for short options too.\n" +" -o, --object OID ID of the mero object\n" +" -y, --mio_conf_file MIO YAML configuration file\n" +" -h, --help shows this help text and exit\n" +, prog_name); +} + +static int obj_hint_set(struct mio_obj_id *oid) +{ + int i; + int rc; + struct mio_obj obj; + struct mio_hints hints; + + memset(&obj, 0, sizeof obj); + rc = mio_cmd_obj_open(oid, &obj); + if (rc < 0) + return rc; + mio_hints_init(&hints); + + for (i = 0; i < MIO_HINT_KEY_NUM; i++) { + rc = mio_hint_add(&hints, i, i); + if (rc < 0) { + fprintf(stderr, "Failed to set hint %s\n", + mio_hint_name(i)); + break; + } + } + mio_obj_hints_set(&obj, &hints); + + mio_hints_fini(&hints); + mio_cmd_obj_close(&obj); + return 0; +} + +int main(int argc, char **argv) +{ + int rc; + struct mio_cmd_obj_params hset_params; + + mio_cmd_obj_args_init(argc, argv, &hset_params, &hset_usage); + + rc = mio_init(hset_params.cop_conf_fname); + if (rc < 0) { + fprintf(stderr, "mio_init failed! rc = %d\n", rc); + exit(EXIT_FAILURE); + } + + rc = obj_hint_set(&hset_params.cop_oid); + if (rc < 0) + fprintf(stderr, "mio_cmd_obj_hset failed! rc = %d\n", rc); + + mio_fini(); + mio_cmd_obj_args_fini(&hset_params); + return rc; +} + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/examples/mio_hint_stat.c b/deps/mio/examples/mio_hint_stat.c new file mode 100644 index 0000000000000000000000000000000000000000..1fc617c30dc71d03f032284362daca2884723577 --- /dev/null +++ b/deps/mio/examples/mio_hint_stat.c @@ -0,0 +1,96 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <asm/byteorder.h> + +#include "obj.h" + +static void hstat_usage(FILE *file, char *prog_name) +{ + fprintf(file, "Usage: %s [OPTION]...\n" +"Create an object.\n" +"\n" +"Mandatory arguments to long options are mandatory for short options too.\n" +" -o, --object OID ID of the mero object\n" +" -y, --mio_conf_file MIO YAML configuration file\n" +" -h, --help shows this help text and exit\n" +, prog_name); +} + +static int obj_hint_stat(struct mio_obj_id *oid) +{ + int i; + int rc; + char *hname; + uint64_t hvalue; + struct mio_obj obj; + struct mio_hints hints; + + memset(&obj, 0, sizeof obj); + rc = mio_cmd_obj_open(oid, &obj); + if (rc < 0) + return rc; + + memset(&hints, 0, sizeof hints); + rc = mio_obj_hints_get(&obj, &hints); + if (rc < 0) + return rc; + + for (i = 0; i < MIO_HINT_KEY_NUM; i++) { + hname = mio_hint_name(i); + rc = mio_hint_lookup(&hints, i, &hvalue); + if (rc < 0) + continue; + + obj_id_printf(oid); + fprintf(stderr, "\t%s\t%"PRIu64"\n", hname, hvalue); + } + + mio_cmd_obj_close(&obj); + return 0; +} + +int main(int argc, char **argv) +{ + int rc; + struct mio_cmd_obj_params hstat_params; + + mio_cmd_obj_args_init(argc, argv, &hstat_params, &hstat_usage); + + rc = mio_init(hstat_params.cop_conf_fname); + if (rc < 0) { + fprintf(stderr, "mio_init failed! rc = %d\n", rc); + exit(EXIT_FAILURE); + } + + rc = obj_hint_stat(&hstat_params.cop_oid); + if (rc < 0) + fprintf(stderr, "mio_cmd_obj_hstat failed! rc = %d\n", rc); + + mio_fini(); + mio_cmd_obj_args_fini(&hstat_params); + return rc; +} + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/examples/mio_kvs_create_set.c b/deps/mio/examples/mio_kvs_create_set.c new file mode 100644 index 0000000000000000000000000000000000000000..5b42ac8d8638aa79d8079962e7ce1c55c01eafa6 --- /dev/null +++ b/deps/mio/examples/mio_kvs_create_set.c @@ -0,0 +1,61 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "kvs.h" + +static void create_set_usage(FILE *file, char *prog_name) +{ + fprintf(file, "Usage: %s [OPTION]...\n" +"Create a key/value set.\n" +"\n" +"Mandatory arguments to long options are mandatory for short options too.\n" +" -k, --kvset ID ID of the MIO key/value set \n" +" -y, --mio_conf_file MIO YAML configuration file\n" +" -h, --help shows this help text and exit\n" +, prog_name); +} + +int main(int argc, char **argv) +{ + int rc; + struct mio_cmd_kvs_params create_set_params; + + mio_cmd_kvs_args_init(argc, argv, &create_set_params, &create_set_usage); + + rc = mio_init(create_set_params.ckp_conf_fname); + if (rc < 0) { + fprintf(stderr, "mio_init failed! rc = %d\n", rc); + exit(EXIT_FAILURE); + } + + rc = mio_cmd_kvs_create_set(&create_set_params.ckp_kid); + if (rc < 0) + fprintf(stderr, "mio_cmd_kvs_create_set failed! rc = %d\n", rc); + + mio_fini(); + mio_cmd_kvs_args_fini(&create_set_params); + return rc; +} + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/examples/mio_kvs_del_pairs.c b/deps/mio/examples/mio_kvs_del_pairs.c new file mode 100644 index 0000000000000000000000000000000000000000..c599dc4e693b2acfa5a6c588018ce65cff7a1819 --- /dev/null +++ b/deps/mio/examples/mio_kvs_del_pairs.c @@ -0,0 +1,73 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "kvs.h" + +static void del_usage(FILE *file, char *prog_name) +{ + fprintf(file, "Usage: %s [OPTION]...\n" +"Insert pairs to a key/value set.\n" +"\n" +"Mandatory arguments to long options are mandatory for short options too.\n" +" -k, --kvset ID ID of the mero object\n" +" -s, --startkey No. The first serial number of keys\n" +" -n, --pairs nr_pairs The number of key/value pairs to insert\n" +" -y, --mio_conf_file MIO YAML configuration file\n" +" -h, --help shows this help text and exit\n" +, prog_name); +} + +int main(int argc, char **argv) +{ + int rc; + struct mio_cmd_kvs_params del_params; + FILE *log = NULL; + + mio_cmd_kvs_args_init(argc, argv, &del_params, &del_usage); + if (del_params.ckp_log != NULL) { + log = fopen(del_params.ckp_log, "w"); + if (log == NULL) + exit(EXIT_FAILURE); + } + + rc = mio_init(del_params.ckp_conf_fname); + if (rc < 0) { + fprintf(stderr, "mio_init failed! rc = %d\n", rc); + exit(EXIT_FAILURE); + } + + rc = mio_cmd_kvs_del_pairs(&del_params.ckp_kid, + del_params.ckp_start_kno, + del_params.ckp_nr_pairs, log); + if (rc < 0) + fprintf(stderr, "mio_cmd_kvs_put failed! rc = %d\n", rc); + + mio_fini(); + if (log != NULL) + fclose(log); + mio_cmd_kvs_args_fini(&del_params); + return rc; +} + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/examples/mio_kvs_del_set.c b/deps/mio/examples/mio_kvs_del_set.c new file mode 100644 index 0000000000000000000000000000000000000000..5cbf9baa8e319b5b3eda72f7f22095a6458af659 --- /dev/null +++ b/deps/mio/examples/mio_kvs_del_set.c @@ -0,0 +1,61 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "kvs.h" + +static void del_set_usage(FILE *file, char *prog_name) +{ + fprintf(file, "Usage: %s [OPTION]...\n" +"Create a key/value set.\n" +"\n" +"Mandatory arguments to long options are mandatory for short options too.\n" +" -k, --kvset ID ID of the mero object\n" +" -y, --mio_conf_file MIO YAML configuration file\n" +" -h, --help shows this help text and exit\n" +, prog_name); +} + +int main(int argc, char **argv) +{ + int rc; + struct mio_cmd_kvs_params del_set_params; + + mio_cmd_kvs_args_init(argc, argv, &del_set_params, &del_set_usage); + + rc = mio_init(del_set_params.ckp_conf_fname); + if (rc < 0) { + fprintf(stderr, "mio_init failed! rc = %d\n", rc); + exit(EXIT_FAILURE); + } + + rc = mio_cmd_kvs_delete_set(&del_set_params.ckp_kid); + if (rc < 0) + fprintf(stderr, "mio_cmd_kvs_create_set failed! rc = %d\n", rc); + + mio_fini(); + mio_cmd_kvs_args_fini(&del_set_params); + return rc; +} + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/examples/mio_kvs_insert.c b/deps/mio/examples/mio_kvs_insert.c new file mode 100644 index 0000000000000000000000000000000000000000..29ffde2226a15685d8d2d727e096171231357e33 --- /dev/null +++ b/deps/mio/examples/mio_kvs_insert.c @@ -0,0 +1,73 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "kvs.h" + +static void put_usage(FILE *file, char *prog_name) +{ + fprintf(file, "Usage: %s [OPTION]...\n" +"Insert pairs to a key/value set.\n" +"\n" +"Mandatory arguments to long options are mandatory for short options too.\n" +" -k, --kvset ID ID of the mero object\n" +" -s, --startkey No. The first serial number of keys\n" +" -n, --pairs nr_pairs The number of key/value pairs to insert\n" +" -y, --mio_conf_file MIO YAML configuration file\n" +" -h, --help shows this help text and exit\n" +, prog_name); +} + +int main(int argc, char **argv) +{ + int rc; + struct mio_cmd_kvs_params put_params; + FILE *log = NULL; + + mio_cmd_kvs_args_init(argc, argv, &put_params, &put_usage); + if (put_params.ckp_log != NULL) { + log = fopen(put_params.ckp_log, "w"); + if (log == NULL) + exit(EXIT_FAILURE); + } + + rc = mio_init(put_params.ckp_conf_fname); + if (rc < 0) { + fprintf(stderr, "mio_init failed! rc = %d\n", rc); + exit(EXIT_FAILURE); + } + + rc = mio_cmd_kvs_insert_pairs(&put_params.ckp_kid, + put_params.ckp_start_kno, + put_params.ckp_nr_pairs, log); + if (rc < 0) + fprintf(stderr, "mio_cmd_kvs_put failed! rc = %d\n", rc); + + mio_fini(); + if (log != NULL) + fclose(log); + mio_cmd_kvs_args_fini(&put_params); + return rc; +} + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/examples/mio_kvs_retrieve.c b/deps/mio/examples/mio_kvs_retrieve.c new file mode 100644 index 0000000000000000000000000000000000000000..d55c88a55f8ece44d1d93f32b6abffdf1ddc33ed --- /dev/null +++ b/deps/mio/examples/mio_kvs_retrieve.c @@ -0,0 +1,74 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "kvs.h" + +static void get_usage(FILE *file, char *prog_name) +{ + fprintf(file, "Usage: %s [OPTION]...\n" +"Insert pairs to a key/value set.\n" +"\n" +"Mandatory arguments to long options are mandatory for short options too.\n" +" -k, --kvset ID ID of the mero object\n" +" -s, --startkey No. The first serial number of keys\n" +" -n, --pairs nr_pairs The number of key/value pairs to insert\n" +" -y, --mio_conf_file conf MIO YAML configuration file\n" +" -l, --log log Log file to record key/value pairs\n" +" -h, --help shows this help text and exit\n" +, prog_name); +} + +int main(int argc, char **argv) +{ + int rc; + struct mio_cmd_kvs_params get_params; + FILE *log = NULL; + + mio_cmd_kvs_args_init(argc, argv, &get_params, &get_usage); + if (get_params.ckp_log != NULL) { + log = fopen(get_params.ckp_log, "w"); + if (log == NULL) + exit(EXIT_FAILURE); + } + + rc = mio_init(get_params.ckp_conf_fname); + if (rc < 0) { + fprintf(stderr, "mio_init failed! rc = %d\n", rc); + exit(EXIT_FAILURE); + } + + rc = mio_cmd_kvs_retrieve_pairs(&get_params.ckp_kid, + get_params.ckp_start_kno, + get_params.ckp_nr_pairs, log); + if (rc < 0) + fprintf(stderr, "mio_cmd_kvs_put failed! rc = %d\n", rc); + + mio_fini(); + if(log != NULL) + fclose(log); + mio_cmd_kvs_args_fini(&get_params); + return rc; +} + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/examples/mio_rw_threads.c b/deps/mio/examples/mio_rw_threads.c new file mode 100644 index 0000000000000000000000000000000000000000..af8ce42b61878c5f80f8fb214037d0b997c876a1 --- /dev/null +++ b/deps/mio/examples/mio_rw_threads.c @@ -0,0 +1,604 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <errno.h> +#include <assert.h> +#include <asm/byteorder.h> +#include <pthread.h> +#include <openssl/md5.h> + +#include "obj.h" +#include "helpers.h" + +struct rwt_obj_todo { + struct mio_obj_id ot_oid; + uint32_t ot_block_size; + uint32_t ot_block_count; + + unsigned char ot_md5sum_write[MD5_DIGEST_LENGTH]; + unsigned char ot_md5sum_read[MD5_DIGEST_LENGTH]; + struct rwt_obj_todo *ot_next; +}; + +struct rwt_obj_todo_list { + pthread_cond_t otl_cond; + pthread_mutex_t otl_mutex; + + int otl_nr_in_list; + int otl_nr_todo; + int otl_nr_done; + int otl_nr_failed; + int otl_nr_matched; + struct rwt_obj_todo otl_head; +}; + +static struct rwt_obj_todo_list obj_to_write_list; +static struct rwt_obj_todo_list obj_to_read_list; + +enum { + RWT_MAX_RAND_NUM = 1024 +}; + +static pthread_t **read_threads = NULL; +static pthread_t **write_threads = NULL; +static int *read_tids = NULL; +static int *write_tids = NULL; + +/** + * rwt - Read Write Threads + */ +static void rw_threads_usage(FILE *file, char *prog_name) +{ + fprintf(file, "Usage: %s [OPTION]\n" +"Example for current Read/Write threads.\n" +"\n" +" -o, --object OID Starting object ID\n" +" -n, --nr_objs INT The number of objects\n" +" -s, --block-size INT block size in bytes or with " \ + "suffix b/k/m/g/K/M/G (see --block-count)\n" +" -c, --block-count INT number of blocks written to an object with "\ + "suffix b/k/m/g/K/M/G (see --block-size)\n" +" -t, --threads Number of threads\n" +" -y, --mio_conf MIO YAML configuration file\n" +" -h, --help shows this help text and exit\n" +, prog_name); +} + +static int +rwt_thread_init(pthread_t **ret_th, void* (*func)(void *), void *args) +{ + int rc; + pthread_t *th; + + th = (pthread_t *) malloc(sizeof(*th)); + if (th == NULL) + return -ENOMEM; + + rc = pthread_create(th, NULL, func, args); + if (rc == 0) + *ret_th = th; + + return -rc; +} + +static int rwt_thread_join(pthread_t *th) +{ + int rc = 0; + void *result; + + if (pthread_join(*th, &result) == 0) { + if (result) { + rc = *((int *)result); + free(result); + } + return rc; + } else + return -1; +} + +static void rwt_thread_fini(pthread_t *th) +{ + free(th); + return; +} + +static void +rwt_generate_data(uint32_t bcount, uint32_t bsize, + struct mio_iovec *data, MD5_CTX *md5_ctx) +{ + int i; + int j; + uint32_t rand; + char *ptr; + + for (i = 0; i < bcount; i++) { + rand = mio_cmd_random(RWT_MAX_RAND_NUM); + ptr = data[i].miov_base; + for (j = 0; j < bsize/sizeof(rand); j++) { + memcpy(ptr, &rand, sizeof(rand)); + ptr += sizeof(rand); + }; + MD5_Update(md5_ctx, data[i].miov_base, bsize); + } +} + +static bool rwt_obj_verify_md5sums(struct rwt_obj_todo *todo) +{ + int i; + int rc; + + obj_id_printf(&todo->ot_oid); + printf("\t"); + for (i = 0; i < MD5_DIGEST_LENGTH; i++) + printf("%02x", todo->ot_md5sum_write[i]); + printf("\t"); + for (i = 0; i < MD5_DIGEST_LENGTH; i++) + printf("%02x", todo->ot_md5sum_read[i]); + printf("\n"); + + rc = memcmp(todo->ot_md5sum_write, + todo->ot_md5sum_read, + MD5_DIGEST_LENGTH); + + return rc == 0? true : false; +} + +static int rwt_obj_write(struct rwt_obj_todo *todo) +{ + int rc = 0; + uint32_t bcount; + uint32_t block_size; + uint32_t block_count; + uint64_t last_index; + struct mio_iovec *data; + struct mio_obj obj; + struct mio_obj_id *oid = &todo->ot_oid; + MD5_CTX md5_ctx; + + block_size = todo->ot_block_size; + block_count = todo->ot_block_count; + + /* Create the target object if it doesn't exist. */ + memset(&obj, 0, sizeof obj); + rc = obj_create(oid, &obj); + if (rc < 0) + return rc; + + last_index = 0; + MD5_Init(&md5_ctx); + while (block_count > 0) { + bcount = (block_count > MIO_CMD_MAX_BLOCK_COUNT)? + MIO_CMD_MAX_BLOCK_COUNT:block_count; + rc = obj_alloc_iovecs(&data, bcount, block_size, last_index); + if (rc != 0) + break; + rwt_generate_data(bcount, block_size, data, &md5_ctx); + + rc = obj_write(&obj, bcount, data); + if (rc != 0) { + fprintf(stderr, "Writing to object failed!\n"); + obj_cleanup_iovecs(data); + break; + } + + obj_cleanup_iovecs(data); + block_count -= bcount; + last_index += bcount * block_size; + } + MD5_Final(todo->ot_md5sum_write, &md5_ctx); + + mio_obj_close(&obj); + return rc; +} + +static int rwt_obj_read(struct rwt_obj_todo *todo) +{ + int i; + int rc = 0; + uint32_t bcount; + uint32_t block_size; + uint32_t block_count; + uint64_t last_index; + struct mio_iovec *data; + struct mio_obj obj; + struct mio_obj_id *oid = &todo->ot_oid; + MD5_CTX md5_ctx; + + block_size = todo->ot_block_size; + block_count = todo->ot_block_count; + + memset(&obj, 0, sizeof obj); + rc = obj_open(oid, &obj); + if (rc < 0) + goto dest_close; + + last_index = 0; + MD5_Init(&md5_ctx); + while (block_count > 0) { + bcount = (block_count > MIO_CMD_MAX_BLOCK_COUNT)? + MIO_CMD_MAX_BLOCK_COUNT:block_count; + rc = obj_alloc_iovecs(&data, bcount, block_size, last_index); + if (rc != 0) + break; + + /* Read data from obj. */ + rc = obj_read(&obj, bcount, data); + if (rc != 0) { + fprintf(stderr, "Failed in reading from file!\n"); + obj_cleanup_iovecs(data); + break; + } + + /* Calculate md5sum from data. */ + for (i = 0; i < bcount; i++) + MD5_Update(&md5_ctx, data[i].miov_base, block_size); + + obj_cleanup_iovecs(data); + block_count -= bcount; + last_index += bcount * block_size; + } + MD5_Final(todo->ot_md5sum_read, &md5_ctx); + + mio_obj_close(&obj); + +dest_close: + return rc; +} + + +static void* rwt_writer(void *in) +{ + int rc; + struct rwt_obj_todo *todo; + struct mio_thread thread; + + mio_thread_init(&thread); + + /* main loop */ + while(1) { + pthread_mutex_lock(&obj_to_write_list.otl_mutex); + if (obj_to_write_list.otl_nr_in_list == 0) { + pthread_mutex_unlock(&obj_to_write_list.otl_mutex); + break; + } + todo = obj_to_write_list.otl_head.ot_next; + assert(todo != NULL); + obj_to_write_list.otl_head.ot_next = todo->ot_next; + todo->ot_next = NULL; + obj_to_write_list.otl_nr_in_list--; + pthread_mutex_unlock(&obj_to_write_list.otl_mutex); + + rc = rwt_obj_write(todo); + + /* WRITE complete, add to the READ todo list. */ + pthread_mutex_lock(&obj_to_read_list.otl_mutex); + if (rc == 0) { + todo->ot_next = obj_to_read_list.otl_head.ot_next; + obj_to_read_list.otl_head.ot_next = todo; + obj_to_read_list.otl_nr_in_list++; + } else if (rc < 0) { + fprintf(stderr, "Failed to write to object! \n"); + obj_to_read_list.otl_nr_failed++; + } + pthread_cond_broadcast(&obj_to_read_list.otl_cond); + pthread_mutex_unlock(&obj_to_read_list.otl_mutex); + } + + mio_thread_fini(&thread); + + pthread_mutex_lock(&obj_to_read_list.otl_mutex); + pthread_cond_broadcast(&obj_to_read_list.otl_cond); + pthread_mutex_unlock(&obj_to_read_list.otl_mutex); + + return NULL; +} + +static void* rwt_reader(void *in) +{ + int rc = 0; + bool matched = false; + struct rwt_obj_todo *todo; + struct mio_thread thread; + int tid = *((int *)in); + bool read_all_done = false; + + mio_thread_init(&thread); + + if (tid == 1) + fprintf(stderr, "%10s\t%32s\t%32s\n", + "Object ID", "WRITE MD5", "READ MD5"); + + /* main loop */ + while(1) { + pthread_mutex_lock(&obj_to_read_list.otl_mutex); + while (obj_to_read_list.otl_nr_in_list == 0) { + if ((obj_to_read_list.otl_nr_done + + obj_to_read_list.otl_nr_failed) == + obj_to_read_list.otl_nr_todo) { + read_all_done = true; + pthread_mutex_unlock( + &obj_to_read_list.otl_mutex); + goto exit; + } + + pthread_cond_wait(&obj_to_read_list.otl_cond, + &obj_to_read_list.otl_mutex); + } + todo = obj_to_read_list.otl_head.ot_next; + obj_to_read_list.otl_head.ot_next = todo->ot_next; + todo->ot_next = NULL; + obj_to_read_list.otl_nr_in_list--; + pthread_mutex_unlock(&obj_to_read_list.otl_mutex); + + rc = rwt_obj_read(todo); + + pthread_mutex_lock(&obj_to_read_list.otl_mutex); + if (rc < 0) { + fprintf(stderr, "Failed to write to object! \n"); + obj_to_read_list.otl_nr_failed++; + } else { + matched = rwt_obj_verify_md5sums(todo); + if (matched) + obj_to_read_list.otl_nr_matched++; + obj_to_read_list.otl_nr_done++; + if ((obj_to_read_list.otl_nr_done + + obj_to_read_list.otl_nr_failed) == + obj_to_read_list.otl_nr_todo) + read_all_done = true; + } + pthread_mutex_unlock(&obj_to_read_list.otl_mutex); + + obj_rm(&todo->ot_oid); + free(todo); + +exit: + if (read_all_done) + break; + } + + mio_thread_fini(&thread); + + pthread_mutex_lock(&obj_to_read_list.otl_mutex); + pthread_cond_broadcast(&obj_to_read_list.otl_cond); + pthread_mutex_unlock(&obj_to_read_list.otl_mutex); + + return NULL; +} + +static void +rwt_set_obj_id(struct rwt_obj_todo *todo, struct mio_obj_id *st_oid, int idx) +{ + uint64_t u1; + uint64_t u2; + uint64_t n1; + uint64_t n2; + + memcpy(&u1, st_oid->moi_bytes, sizeof u1); + memcpy(&u2, st_oid->moi_bytes + sizeof u1, sizeof u2); + u1 = __be64_to_cpu(u1); + u2 = __be64_to_cpu(u2); + + n1 = u1 + idx; + n2 = u2; + n1 = __cpu_to_be64(n1); + n2 = __cpu_to_be64(n2); + memcpy(todo->ot_oid.moi_bytes, &n1, sizeof n1); + memcpy(todo->ot_oid.moi_bytes + sizeof n1, &n2, sizeof n2); +} + +static void rwt_todo_lists_fini() +{ + int i; + struct rwt_obj_todo *todo; + + pthread_mutex_destroy(&obj_to_read_list.otl_mutex); + pthread_cond_destroy(&obj_to_read_list.otl_cond); + pthread_mutex_destroy(&obj_to_write_list.otl_mutex); + pthread_cond_destroy(&obj_to_write_list.otl_cond); + + for (i = 0; i < obj_to_read_list.otl_nr_in_list; i++) { + todo = obj_to_read_list.otl_head.ot_next; + if (todo == NULL) + break; + obj_to_read_list.otl_head.ot_next = todo->ot_next; + free(todo); + } + + for (i = 0; i < obj_to_write_list.otl_nr_in_list; i++) { + todo = obj_to_write_list.otl_head.ot_next; + if (todo == NULL) + break; + obj_to_write_list.otl_head.ot_next = todo->ot_next; + + free(todo); + } +} + +static int rwt_todo_lists_init(struct mio_obj_id *st_oid, int nr_objs, + uint32_t block_size, uint32_t block_count) +{ + int i; + int rc = 0; + struct rwt_obj_todo *todo; + + memset(&obj_to_read_list, 0, sizeof(obj_to_read_list)); + pthread_cond_init(&obj_to_read_list.otl_cond, NULL); + pthread_mutex_init(&obj_to_read_list.otl_mutex, NULL); + obj_to_read_list.otl_nr_todo = nr_objs; + + memset(&obj_to_write_list, 0, sizeof(obj_to_write_list)); + pthread_cond_init(&obj_to_write_list.otl_cond, NULL); + pthread_mutex_init(&obj_to_write_list.otl_mutex, NULL); + obj_to_write_list.otl_nr_todo = nr_objs; + + /* + * Insert all objects into the WRITE todo list. + */ + for (i = 0; i < nr_objs; i++) { + todo = malloc(sizeof(struct rwt_obj_todo)); + if (todo == NULL) { + rc = -ENOMEM; + break; + } + + rwt_set_obj_id(todo, st_oid, i); + todo->ot_block_size = block_size; + todo->ot_block_count = block_count; + todo->ot_next = obj_to_write_list.otl_head.ot_next; + obj_to_write_list.otl_head.ot_next = todo; + obj_to_write_list.otl_nr_in_list++; + } + if (rc < 0) + rwt_todo_lists_fini(); + + return rc; +} +static void rwt_report() +{ + fprintf(stderr, "[Final Report] \t"); + fprintf(stderr, "Objects TODO: %d\t", obj_to_read_list.otl_nr_todo); + fprintf(stderr, "Completed: %d\t", obj_to_read_list.otl_nr_done); + fprintf(stderr, "Failed: %d\t", obj_to_read_list.otl_nr_failed); + fprintf(stderr, "Matched: %d\t", obj_to_read_list.otl_nr_matched); + fprintf(stderr, "\n"); +} + +static int +mio_rwt_start(int nr_threads, struct mio_obj_id *st_oid, int nr_objs, + uint32_t block_size, uint32_t block_count) +{ + int i; + int rc = 0; + + rwt_todo_lists_init(st_oid, nr_objs, block_size, block_count); + + /* + * For simplicity, the same number of READ and WRITE threads + * are created. + */ + read_threads = malloc(nr_threads * sizeof(*read_threads)); + write_threads = malloc(nr_threads * sizeof(*write_threads)); + read_tids = malloc(nr_threads * sizeof(*read_tids)); + write_tids = malloc(nr_threads * sizeof(*write_tids)); + if (read_threads == NULL || write_threads == NULL || + read_tids == NULL || write_tids == NULL) { + rc = -ENOMEM; + goto error; + } + + for (i = 0; i < nr_threads; i++) { + write_tids[i] = i; + rc = rwt_thread_init( + write_threads + i, &rwt_writer, write_tids + i); + if (rc < 0) + goto error; + } + + for (i = 0; i < nr_threads; i++) { + read_tids[i] = i; + rc = rwt_thread_init( + read_threads + i, &rwt_reader, read_tids + i); + if (rc < 0) + goto error; + } + + return 0; + +error: + if (read_threads) + free(read_threads); + if (write_threads) + free(write_threads); + if (read_tids) + free(read_tids); + if (write_tids) + free(write_tids); + return rc; +} + +static void mio_rwt_stop(int nr_threads) +{ + int i; + + for (i = 0; i < nr_threads; i++) { + if (write_threads[i] == NULL) + break; + + rwt_thread_join(write_threads[i]); + rwt_thread_fini(write_threads[i]); + write_threads[i] = NULL; + } + + for (i = 0; i < nr_threads; i++) { + if (read_threads[i] == NULL) + break; + + rwt_thread_join(read_threads[i]); + rwt_thread_fini(read_threads[i]); + read_threads[i] = NULL; + + } + free(read_threads); + free(write_threads); + free(read_tids); + free(write_tids); + + rwt_report(); + + rwt_todo_lists_fini(); + + return; +} + +int main(int argc, char **argv) +{ + int rc; + struct mio_cmd_obj_params rwt_params; + + mio_cmd_obj_args_init(argc, argv, &rwt_params, &rw_threads_usage); + + rc = mio_init(rwt_params.cop_conf_fname); + if (rc < 0) { + fprintf(stderr, "mio_init failed! errno = %d\n", rc); + goto exit; + } + + rc = mio_rwt_start(rwt_params.cop_nr_threads, &rwt_params.cop_oid, + rwt_params.cop_nr_objs, + rwt_params.cop_block_size, + rwt_params.cop_block_count); + if (rc < 0) { + fprintf(stderr, "Failed to start threads! errno = %d\n", rc); + goto exit; + } + + mio_rwt_stop(rwt_params.cop_nr_threads); + +exit: + mio_fini(); + mio_cmd_obj_args_fini(&rwt_params); + return rc; +} + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/examples/mio_touch.c b/deps/mio/examples/mio_touch.c new file mode 100644 index 0000000000000000000000000000000000000000..3dfded320795a3bbb0c99370cb2c597217a4ee09 --- /dev/null +++ b/deps/mio/examples/mio_touch.c @@ -0,0 +1,61 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "obj.h" + +static void touch_usage(FILE *file, char *prog_name) +{ + fprintf(file, "Usage: %s [OPTION]...\n" +"Create an object.\n" +"\n" +"Mandatory arguments to long options are mandatory for short options too.\n" +" -o, --object OID ID of the mero object\n" +" -y, --mio_conf_file MIO YAML configuration file\n" +" -h, --help shows this help text and exit\n" +, prog_name); +} + +int main(int argc, char **argv) +{ + int rc; + struct mio_cmd_obj_params touch_params; + + mio_cmd_obj_args_init(argc, argv, &touch_params, &touch_usage); + + rc = mio_init(touch_params.cop_conf_fname); + if (rc < 0) { + fprintf(stderr, "mio_init failed! rc = %d\n", rc); + exit(EXIT_FAILURE); + } + + rc = mio_cmd_obj_touch(&touch_params.cop_oid); + if (rc < 0) + fprintf(stderr, "mio_cmd_obj_touch failed! rc = %d\n", rc); + + mio_fini(); + mio_cmd_obj_args_fini(&touch_params); + return rc; +} + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/examples/mio_unlink.c b/deps/mio/examples/mio_unlink.c new file mode 100644 index 0000000000000000000000000000000000000000..98693161308ec318bec7aeb299b6434358d56a62 --- /dev/null +++ b/deps/mio/examples/mio_unlink.c @@ -0,0 +1,61 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "obj.h" + +static void unlink_usage(FILE *file, char *prog_name) +{ + fprintf(file, "Usage: %s [OPTION]...\n" +"Remove an object.\n" +"\n" +"Mandatory arguments to long options are mandatory for short options too.\n" +" -o, --object OID ID of the mero object\n" +" -y, --mio_conf_file MIO YAML configuration file\n" +" -h, --help shows this help text and exit\n" +, prog_name); +} + +int main(int argc, char **argv) +{ + int rc; + struct mio_cmd_obj_params unlink_params; + + mio_cmd_obj_args_init(argc, argv, &unlink_params, &unlink_usage); + + rc = mio_init(unlink_params.cop_conf_fname); + if (rc < 0) { + fprintf(stderr, "mio_init failed! rc = %d\n", rc); + exit(EXIT_FAILURE); + } + + rc = mio_cmd_obj_unlink(&unlink_params.cop_oid); + if (rc < 0) + fprintf(stderr, "mio_cmd_obj_unlink failed! rc = %d\n", rc); + + mio_fini(); + mio_cmd_obj_args_fini(&unlink_params); + return rc; +} + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/examples/obj.c b/deps/mio/examples/obj.c new file mode 100644 index 0000000000000000000000000000000000000000..9f0892fb10b2f923763c82c03223b4b0f6e139a8 --- /dev/null +++ b/deps/mio/examples/obj.c @@ -0,0 +1,303 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <string.h> +#include <unistd.h> +#include <getopt.h> +#include <asm/byteorder.h> +#include <pthread.h> + +#include "obj.h" +#include "helpers.h" + +int obj_alloc_iovecs(struct mio_iovec **data, uint32_t bcount, + uint32_t bsize, uint64_t offset) +{ + int i; + int rc; + struct mio_iovec *iovecs; + char *base; + + iovecs = mio_mem_alloc(bcount * sizeof(*iovecs)); + base = mio_mem_alloc(bcount * bsize); + if (iovecs == NULL || base == NULL) { + fprintf(stderr, "Can't allocate memory!\n"); + rc = -ENOMEM; + goto error_exit; + } + + for(i = 0; i < bcount; i++) { + iovecs[i].miov_base = base + i * bsize; + iovecs[i].miov_off = offset + i * bsize; + iovecs[i].miov_len = bsize; + } + *data = iovecs; + return 0; + +error_exit: + mio_mem_free(base); + mio_mem_free(iovecs); + return rc; +} + +void obj_cleanup_iovecs(struct mio_iovec *data) +{ + mio_mem_free(data[0].miov_base); + mio_mem_free(data); +} + +int obj_read_data_from_file(FILE *fp, uint32_t bcount, uint32_t bsize, + struct mio_iovec *data) +{ + int i; + int rc; + + for (i = 0; i < bcount; i++) { + rc = fread(data[i].miov_base, bsize, 1, fp); + if (rc != 1) + break; + } + return i; +} + +int obj_write_data_to_file(FILE *fp, bool console, + uint32_t bcount, struct mio_iovec *data) +{ + int i = 0; + int j; + int rc; + + if (fp != NULL) { + fseek(fp, data[0].miov_off, SEEK_SET); + for(i = 0; i < bcount; i++) { + rc = fwrite(data[i].miov_base, data[i].miov_len, 1, fp); + if (rc != 1) { + fprintf(stderr, "Writing to object failed!\n"); + break; + } + } + } + + if (console) { + /* putchar the output */ + for (i = 0; i < bcount; ++i) { + for (j = 0; j < data[i].miov_len; ++j) + putchar(data[i].miov_base[j]); + } + + } + + return i; +} + +static int obj_id_sscanf(char *idstr, struct mio_obj_id *oid) +{ + int rc; + int n; + uint64_t u1; + uint64_t u2; + + rc = sscanf(idstr, "%"SCNx64" : %"SCNx64" %n", &u1, &u2, &n); + if (rc < 0) + return rc; + u1 = __cpu_to_be64(u1); + u2 = __cpu_to_be64(u2); + + memcpy(oid->moi_bytes, &u1, sizeof u1); + memcpy(oid->moi_bytes + sizeof u1, &u2, sizeof u2); + return 0; +} + +void obj_id_printf(struct mio_obj_id *oid) +{ + uint64_t u1; + uint64_t u2; + + memcpy(&u1, oid->moi_bytes,sizeof u1); + memcpy(&u2, oid->moi_bytes + sizeof u1, sizeof u2); + u1 = __be64_to_cpu(u1); + u2 = __be64_to_cpu(u2); + fprintf(stderr, "%"PRIx64":%"PRIx64"", u1, u2); +} + +int obj_open(struct mio_obj_id *oid, struct mio_obj *obj) +{ + int rc; + struct mio_op op; + + memset(&op, 0, sizeof op); + rc = mio_obj_open(oid, obj, &op); + if (rc != 0) + return rc; + + /* If the object doesn't exist, -ENOENT will be returned? */ + rc = mio_cmd_wait_on_op(&op); + return rc; +} + +void obj_close(struct mio_obj *obj) +{ + mio_obj_close(obj); +} + +int obj_create(struct mio_obj_id *oid, struct mio_obj *obj) +{ + int rc; + struct mio_op op; + + memset(&op, 0, sizeof op); + rc = obj_open(oid, obj); + if (rc == 0) { + fprintf(stderr, "Object exists!\n"); + return -EEXIST; + } else if (rc == -ENOENT) + goto create; + else + return rc; + +create: + memset(&op, 0, sizeof op); + rc = mio_obj_create(oid, NULL, obj, &op); + if (rc != 0) + return rc; + + rc = mio_cmd_wait_on_op(&op); + return rc; +} + +int obj_rm(struct mio_obj_id *oid) +{ + int rc; + struct mio_op op; + + memset(&op, 0, sizeof op); + rc = mio_obj_delete(oid, &op); + if (rc != 0) + return rc; + + rc = mio_cmd_wait_on_op(&op); + return rc; +} + +int mio_cmd_obj_touch(struct mio_obj_id *oid) +{ + struct mio_obj obj; + + memset(&obj, 0, sizeof obj); + return obj_create(oid, &obj); +} + +int mio_cmd_obj_unlink(struct mio_obj_id *oid) +{ + return obj_rm(oid); +} + +int mio_cmd_obj_open(struct mio_obj_id *oid, struct mio_obj *obj) +{ + return obj_open(oid, obj); +} + +void mio_cmd_obj_close(struct mio_obj *obj) +{ + obj_close(obj); +} + +int mio_cmd_obj_args_init(int argc, char **argv, + struct mio_cmd_obj_params *params, + void (*usage)(FILE *, char *)) +{ + int v; + int rc; + int option_index = 0; + static struct option l_opts[] = { + {"object", required_argument, NULL, 'o'}, + {"block-size", required_argument, NULL, 's'}, + {"block-count", required_argument, NULL, 'c'}, + {"nr_objs", required_argument, NULL, 'n'}, + {"async_mod", no_argument, NULL, 'a'}, + {"mio_conf", required_argument, NULL, 'y'}, + {"help", no_argument, NULL, 'h'}, + {0, 0, 0, 0 }}; + + memset(params, 0, sizeof *params); + params->cop_nr_objs = 1; + params->cop_async_mode = false; + + while ((v = getopt_long(argc, argv, ":o:s:c:n:y:t:ah", l_opts, + &option_index)) != -1) + { + switch (v) { + case 'o': + obj_id_sscanf(optarg, ¶ms->cop_oid); + continue; + + case 's': + rc = mio_cmd_strtou64(optarg, ¶ms->cop_block_size); + if (rc < 0) + exit(EXIT_FAILURE); + continue; + case 'c': + rc = mio_cmd_strtou64(optarg, ¶ms->cop_block_count); + if (rc < 0) + exit(EXIT_FAILURE); + continue; + case 'n': + params->cop_nr_objs = atoi(optarg); + continue; + case 't': + params->cop_nr_threads = atoi(optarg); + continue; + case 'y': + params->cop_conf_fname = strdup(optarg); + if (params->cop_conf_fname == NULL) + exit(EXIT_FAILURE); + continue; + case 'a': + params->cop_async_mode = true; + continue; + case 'h': + usage(stderr, basename(argv[0])); + exit(EXIT_FAILURE); + case '?': + fprintf(stderr, "Unsupported option '%c'\n", + optopt); + usage(stderr, basename(argv[0])); + exit(EXIT_FAILURE); + case ':': + fprintf(stderr, "No argument given for '%c'\n", + optopt); + usage(stderr, basename(argv[0])); + exit(EXIT_FAILURE); + default: + fprintf(stderr, "Unsupported option '%c'\n", v); + } + } + + return 0; +} + +void mio_cmd_obj_args_fini(struct mio_cmd_obj_params *params) +{ + if (params->cop_conf_fname) + free(params->cop_conf_fname); +} + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/examples/obj.h b/deps/mio/examples/obj.h new file mode 100644 index 0000000000000000000000000000000000000000..985128fc085019d13cdd5c65b00acc01cfdc72b3 --- /dev/null +++ b/deps/mio/examples/obj.h @@ -0,0 +1,96 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#ifndef __OBJ_H__ +#define __OBJ_H__ + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/time.h> + +#include "src/mio.h" + +enum { + MIO_CMD_MAX_BLOCK_COUNT = 100 +}; + +struct mio_cmd_obj_params { + char *cop_conf_fname; + + struct mio_obj_id cop_oid; + int cop_nr_objs; + uint64_t cop_block_size; + uint64_t cop_block_count; + + bool cop_async_mode; + + int cop_nr_threads; +}; + +int mio_cmd_obj_args_init(int argc, char **argv, + struct mio_cmd_obj_params *params, + void (*usage)(FILE *, char *)); +void mio_cmd_obj_args_fini(struct mio_cmd_obj_params *params); + +int mio_cmd_obj_write(char *src, struct mio_obj_id *oid, + uint32_t block_size, uint32_t block_count); + +int mio_cmd_obj_write_async(char *src, struct mio_obj_id *oid, + uint32_t block_size, uint32_t block_count); + +int mio_cmd_obj_read(struct mio_obj_id *oid, char *dest, + uint32_t block_size, uint32_t block_count); +int mio_cmd_obj_read_async(struct mio_obj_id *oid, char *dest, + uint32_t block_size, uint32_t block_count); + +int mio_cmd_obj_touch(struct mio_obj_id *oid); +int mio_cmd_obj_unlink(struct mio_obj_id *id); + +int mio_cmd_obj_open(struct mio_obj_id *oid,struct mio_obj *obj); +void mio_cmd_obj_close(struct mio_obj *obj); + +/** Helper functions. */ +int obj_alloc_iovecs(struct mio_iovec **data, uint32_t bcount, + uint32_t bsize, uint64_t offset); +void obj_cleanup_iovecs(struct mio_iovec *data); +int obj_read_data_from_file(FILE *fp, uint32_t bcount, uint32_t bsize, + struct mio_iovec *data); +int obj_write_data_to_file(FILE *fp, bool console, + uint32_t bcount, struct mio_iovec *data); + +int obj_open(struct mio_obj_id *oid, struct mio_obj *obj); +void obj_close(struct mio_obj *obj); +int obj_create(struct mio_obj_id *oid, struct mio_obj *obj); +int obj_rm(struct mio_obj_id *oid); + +int obj_write(struct mio_obj *obj, uint32_t bcount, struct mio_iovec *data); +int obj_read(struct mio_obj *obj, uint32_t bcount, struct mio_iovec *data); + +void obj_id_printf(struct mio_obj_id *oid); + +#endif /* __OBJ_H__ */ + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/examples/obj_io_cbs.c b/deps/mio/examples/obj_io_cbs.c new file mode 100644 index 0000000000000000000000000000000000000000..ffb3570ac149883b1440cc596705fb201d97ca27 --- /dev/null +++ b/deps/mio/examples/obj_io_cbs.c @@ -0,0 +1,343 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <string.h> +#include <unistd.h> +#include <getopt.h> +#include <asm/byteorder.h> +#include <pthread.h> + +#include "obj.h" +#include "helpers.h" + +/** + * obj_io_cbs.c gives examples on how to use MIO callback functions + * for object READ/WRITE. + */ + +struct obj_io_cb_args { + int ica_bcount; + struct mio_iovec *ica_iovecs; + FILE *ica_fp; +}; + +pthread_cond_t obj_io_cond; +pthread_mutex_t obj_io_mutex; +static int obj_io_nr_ops_on_fly = 0; +static int obj_io_nr_ops_todo = 0; +static struct mio_op **obj_io_ops; + +void obj_wait_on_all_ops() +{ + pthread_mutex_lock(&obj_io_mutex); + while(obj_io_nr_ops_on_fly != 0) + pthread_cond_wait(&obj_io_cond, &obj_io_mutex); + pthread_mutex_unlock(&obj_io_mutex); + +} + +void obj_write_cb(struct mio_op *op) +{ + int i; + struct obj_io_cb_args *args; + struct mio_iovec *iov; + + args = (struct obj_io_cb_args *)op->mop_app_cbs.moc_cb_data; + for (i = 0; i < args->ica_bcount; i++) { + iov = args->ica_iovecs + i; + fprintf(stderr, "IO from %d to %d %s!\n", + (int)iov[0].miov_off, + (int)(iov[0].miov_off + iov[0].miov_len), + op->mop_rc == 0? "succeed" : "failed"); + } + + obj_cleanup_iovecs(args->ica_iovecs); + free(args); + + pthread_mutex_lock(&obj_io_mutex); + obj_io_nr_ops_on_fly--; + pthread_cond_signal(&obj_io_cond); + pthread_mutex_unlock(&obj_io_mutex); +} + +static int obj_write_async(struct mio_obj *obj, int op_idx, + uint32_t bcount, struct mio_iovec *data) +{ + int rc; + struct mio_op *op; + struct obj_io_cb_args *args; + + args = malloc(sizeof *args); + if (args == NULL) + return -ENOMEM; + + /* + * Allocate memory for op as the op's memory must keep + * alive after exiting this function. + */ + op = mio_op_alloc_init(); + if (op == NULL) { + free(args); + return -ENOMEM; + } + + /* + * Callbacks must be set before calling mio_obj_writev() as + * the op will be launched in this function. Same to other + * MIO APIs if one wants to set callbacks. + */ + args->ica_bcount = bcount; + args->ica_iovecs = data; + mio_op_callbacks_set(op, obj_write_cb, obj_write_cb, args); + rc = mio_obj_writev(obj, data, bcount, op); + if (rc < 0) { + mio_op_fini_free(op); + free(args); + } else + obj_io_ops[op_idx] = op; + return rc; +} + +void obj_read_cb(struct mio_op *op) +{ + int i; + struct obj_io_cb_args *args; + struct mio_iovec *iov; + + args = (struct obj_io_cb_args *)op->mop_app_cbs.moc_cb_data; + for (i = 0; i < args->ica_bcount; i++) { + iov = args->ica_iovecs + i; + fprintf(stderr, "Read from %d to %d %s!\n", + (int)iov[0].miov_off, + (int)(iov[0].miov_off + iov[0].miov_len), + op->mop_rc == 0? "succeed" : "failed"); + } + obj_write_data_to_file( + args->ica_fp, false, args->ica_bcount, args->ica_iovecs); + + obj_cleanup_iovecs(args->ica_iovecs); + free(args); + + pthread_mutex_lock(&obj_io_mutex); + obj_io_nr_ops_on_fly--; + pthread_cond_signal(&obj_io_cond); + pthread_mutex_unlock(&obj_io_mutex); +} + + +static int +obj_read_async(struct mio_obj *obj, FILE *write_to_fp, + int op_idx, uint32_t bcount, struct mio_iovec *data) +{ + int rc; + struct mio_op *op; + struct obj_io_cb_args *args; + + args = malloc(sizeof *args); + if (args == NULL) + return -ENOMEM; + + op = mio_op_alloc_init(); + if (op == NULL) { + free(args); + return -ENOMEM; + } + + args->ica_bcount = bcount; + args->ica_iovecs = data; + args->ica_fp = write_to_fp; + mio_op_callbacks_set(op, obj_read_cb, obj_read_cb, args); + rc = mio_obj_readv(obj, data, bcount, op); + if (rc < 0) { + mio_op_fini_free(op); + free(args); + } else + obj_io_ops[op_idx] = op; + return rc; +} + +static int obj_io_async_init(int bcount) +{ + obj_io_nr_ops_todo = + (bcount + MIO_CMD_MAX_BLOCK_COUNT - 1) / + MIO_CMD_MAX_BLOCK_COUNT; + obj_io_ops = malloc(obj_io_nr_ops_todo * sizeof(struct mio_op *)); + if (obj_io_ops == NULL) + return -ENOMEM; + memset(obj_io_ops, 0, obj_io_nr_ops_todo * sizeof(struct mio_op *)); + + pthread_cond_init(&obj_io_cond, NULL); + pthread_mutex_init(&obj_io_mutex, NULL); + + return 0; +} + +static void obj_io_async_fini() +{ + int i; + + pthread_mutex_destroy(&obj_io_mutex); + pthread_cond_destroy(&obj_io_cond); + + for (i = 0; i < obj_io_nr_ops_todo; i++) { + if (obj_io_ops[i] != NULL) { + mio_op_fini(obj_io_ops[i]); + free(obj_io_ops[i]); + } + } + + free(obj_io_ops); +} + +int mio_cmd_obj_write_async(char *src, struct mio_obj_id *oid, + uint32_t block_size, uint32_t block_count) +{ + int rc = 0; + uint32_t bcount; + uint64_t last_index; + struct mio_iovec *data; + struct mio_obj obj; + FILE *fp; + + fp = fopen(src, "r"); + if (fp == NULL) + return -errno; + + memset(&obj, 0, sizeof obj); + rc = obj_create(oid, &obj); + if (rc < 0) + goto src_close; + + rc = obj_io_async_init(block_count); + if (rc < 0) + goto obj_close; + + pthread_mutex_lock(&obj_io_mutex); + last_index = 0; + while (block_count > 0) { + bcount = (block_count > MIO_CMD_MAX_BLOCK_COUNT)? + MIO_CMD_MAX_BLOCK_COUNT:block_count; + rc = obj_alloc_iovecs(&data, bcount, block_size, last_index); + if (rc != 0) + break; + + /* Read data from source file. */ + rc = obj_read_data_from_file(fp, bcount, block_size, data); + if (rc != bcount) { + fprintf(stderr, "Failed in reading from file!\n"); + obj_cleanup_iovecs(data); + break; + } + + /* Copy data to the object*/ + rc = obj_write_async(&obj, obj_io_nr_ops_on_fly, bcount, data); + if (rc != 0) { + fprintf(stderr, "Writing to object failed!\n"); + obj_cleanup_iovecs(data); + break; + } + block_count -= bcount; + last_index += bcount * block_size; + + ++obj_io_nr_ops_on_fly; + } + pthread_mutex_unlock(&obj_io_mutex); + + obj_wait_on_all_ops(); + + obj_io_async_fini(); + +obj_close: + mio_obj_close(&obj); +src_close: + fclose(fp); + return rc; +} + +int mio_cmd_obj_read_async(struct mio_obj_id *oid, char *dest, + uint32_t block_size, uint32_t block_count) +{ + int rc = 0; + uint32_t bcount; + uint64_t last_index; + struct mio_iovec *data; + struct mio_obj obj; + FILE *fp = NULL; + + if (dest == NULL) + return -EINVAL; + + fp = fopen(dest, "w"); + if (fp == NULL) + return -errno; + /* + * As 'obj' keeps alive in the scope of this function till + * all operation are done, so it is ok not to allocate memory + * for 'obj' here. Make sure that 'obj' is kept alive until + * all the ops which are doing IO on it are done. + */ + memset(&obj, 0, sizeof obj); + rc = obj_open(oid, &obj); + if (rc < 0) + goto dest_close; + + rc = obj_io_async_init(block_count); + if (rc < 0) + goto obj_close; + + pthread_mutex_lock(&obj_io_mutex); + last_index = 0; + while (block_count > 0) { + bcount = (block_count > MIO_CMD_MAX_BLOCK_COUNT)? + MIO_CMD_MAX_BLOCK_COUNT:block_count; + rc = obj_alloc_iovecs(&data, bcount, + block_size, last_index); + if (rc != 0) + break; + + /* Read data from obj. */ + rc = obj_read_async(&obj, fp, obj_io_nr_ops_on_fly, + bcount, data); + if (rc != 0) { + fprintf(stderr, "Failed in reading from file!\n"); + obj_cleanup_iovecs(data); + break; + } + + block_count -= bcount; + last_index += bcount * block_size; + + ++obj_io_nr_ops_on_fly; + } + pthread_mutex_unlock(&obj_io_mutex); + + obj_wait_on_all_ops(); + + obj_io_async_fini(); + +obj_close: + mio_obj_close(&obj); +dest_close: + fclose(fp); + return rc; +} + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/examples/obj_io_poll.c b/deps/mio/examples/obj_io_poll.c new file mode 100644 index 0000000000000000000000000000000000000000..b2ac8283ddb1afee076b09a2f09b265be1b0eec4 --- /dev/null +++ b/deps/mio/examples/obj_io_poll.c @@ -0,0 +1,190 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <string.h> +#include <unistd.h> +#include <getopt.h> +#include <asm/byteorder.h> +#include <pthread.h> + +#include "obj.h" +#include "helpers.h" + +/** + * The object IO examples in this file show how to use MIO APIs + * in a blocking fashion. After an operation is created, we wait until + * an operation completed or failed by using mio_op_poll(). + * + * Of course, applications can also create (and launch internally + * in MIO) operations and poll the operations in a dedicated thread. + */ + +int obj_write(struct mio_obj *obj, uint32_t bcount, struct mio_iovec *data) +{ + int rc; + struct mio_op op; + + mio_op_init(&op); + rc = mio_obj_writev(obj, data, bcount, &op); + if (rc < 0) + return rc; + + rc = mio_cmd_wait_on_op(&op); + if (rc < 0) + fprintf(stderr, "Failed in writing to object!\n"); + mio_op_fini(&op); + return rc; +} + +int obj_read(struct mio_obj *obj, uint32_t bcount, struct mio_iovec *data) +{ + int rc; + struct mio_op op; + + mio_op_init(&op); + rc = mio_obj_readv(obj, data, bcount, &op); + if (rc < 0) + return rc; + + rc = mio_cmd_wait_on_op(&op); + if (rc < 0) + fprintf(stderr, "Failed in reading from object!\n"); + mio_op_fini(&op); + return rc; +} + +int mio_cmd_obj_write(char *src, struct mio_obj_id *oid, + uint32_t block_size, uint32_t block_count) +{ + int rc = 0; + uint32_t bcount; + uint64_t last_index; + struct mio_iovec *data; + struct mio_obj obj; + FILE *fp; + + /* Open source file */ + fp = fopen(src, "r"); + if (fp == NULL) + return -errno; + + /* Create the target object if it doesn't exist. */ + memset(&obj, 0, sizeof obj); + rc = obj_create(oid, &obj); + if (rc < 0) + goto src_close; + + last_index = 0; + while (block_count > 0) { + bcount = (block_count > MIO_CMD_MAX_BLOCK_COUNT)? + MIO_CMD_MAX_BLOCK_COUNT:block_count; + rc = obj_alloc_iovecs(&data, bcount, + block_size, last_index); + if (rc != 0) + break; + + /* Read data from source file. */ + rc = obj_read_data_from_file(fp, bcount, block_size, data); + if (rc != bcount) { + fprintf(stderr, "Failed in reading from file!\n"); + obj_cleanup_iovecs(data); + break; + } + + /* Copy data to the object*/ + rc = obj_write(&obj, bcount, data); + if (rc != 0) { + fprintf(stderr, "Writing to object failed!\n"); + obj_cleanup_iovecs(data); + break; + } + obj_cleanup_iovecs(data); + block_count -= bcount; + last_index += bcount * block_size; + } + + mio_obj_close(&obj); + +src_close: + fclose(fp); + return rc; +} + +int mio_cmd_obj_read(struct mio_obj_id *oid, char *dest, + uint32_t block_size, uint32_t block_count) +{ + int rc = 0; + uint32_t bcount; + uint64_t last_index; + struct mio_iovec *data; + struct mio_obj obj; + FILE *fp = NULL; + + if (dest != NULL) { + fp = fopen(dest, "w"); + if (fp == NULL) + return -errno; + + } + + memset(&obj, 0, sizeof obj); + rc = obj_open(oid, &obj); + if (rc < 0) + goto dest_close; + + last_index = 0; + while (block_count > 0) { + bcount = (block_count > MIO_CMD_MAX_BLOCK_COUNT)? + MIO_CMD_MAX_BLOCK_COUNT:block_count; + rc = obj_alloc_iovecs(&data, bcount, block_size, last_index); + if (rc != 0) + break; + + /* Read data from obj. */ + rc = obj_read(&obj, bcount, data); + if (rc != 0) { + fprintf(stderr, "Failed in reading from file!\n"); + obj_cleanup_iovecs(data); + break; + } + + /* Copy data to the file. */ + rc = obj_write_data_to_file(fp, true, bcount, data); + if (rc != bcount) { + fprintf(stderr, "Writing to file failed!\n"); + obj_cleanup_iovecs(data); + break; + } + + obj_cleanup_iovecs(data); + block_count -= bcount; + last_index += bcount * block_size; + } + + mio_obj_close(&obj); + +dest_close: + if(fp != NULL) + fclose(fp); + return rc; +} + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/src/Makefile.sub b/deps/mio/src/Makefile.sub new file mode 100644 index 0000000000000000000000000000000000000000..3390aaa84739641f878d38e17453c30894e396a7 --- /dev/null +++ b/deps/mio/src/Makefile.sub @@ -0,0 +1,16 @@ +# Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, +# All Rights Reserved +# +# This software is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +nobase_mio_include_HEADERS += src/mio.h \ + src/mio_internal.h \ + src/driver_clovis.h \ + src/logger.h + +lib_libmio_la_SOURCES += src/parser.c src/logger.c \ + src/utils.c src/mio.c src/mio_driver.c \ + src/hints.c src/driver_clovis.c \ + src/driver_clovis_comp_obj.c diff --git a/deps/mio/src/driver_clovis.c b/deps/mio/src/driver_clovis.c new file mode 100644 index 0000000000000000000000000000000000000000..12bb04c3c14f672ce6b702a23817998aa9a6036f --- /dev/null +++ b/deps/mio/src/driver_clovis.c @@ -0,0 +1,1370 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <errno.h> +#include <assert.h> + +#include "logger.h" +#include "mio.h" +#include "mio_internal.h" +#include "driver_clovis.h" + +struct m0_clovis *mio_clovis_instance; +struct m0_clovis_container mio_clovis_container; +struct m0_clovis_config mio_clovis_conf; +struct mio_mero_config *mio_clovis_inst_confs; + +struct m0_uint128 mio_clovis_obj_md_kvs_id; +struct m0_fid mio_clovis_obj_md_kvs_fid = M0_FID_TINIT('x', 0, 0x10); + +#define MIO_CLOVIS_OP(op) \ + ((struct m0_clovis_op *)op->mop_drv_op_chain.mdoc_head->mdo_op) + +/** + * pp is short for Post-Process to avoid confusion of cb (callback). + */ +static int clovis_obj_attrs_query_free_pp(struct mio_op *op); +static int clovis_obj_attrs_get_pp(struct mio_op *op); +static int clovis_obj_attrs_query(int opcode, struct mio_obj *obj, + mio_driver_op_postprocess op_pp, + struct mio_op *op); + +/** + * Some helper functions. + */ +static void clovis_bufvec_free(struct m0_bufvec *bv) +{ + if (bv == NULL) + return; + + m0_free(bv->ov_buf); + m0_free(bv->ov_vec.v_count); + m0_free(bv); +} + +struct m0_bufvec* mio__clovis_bufvec_alloc(int nr) +{ + struct m0_bufvec *bv; + + bv = m0_alloc(sizeof *bv); + if (bv == NULL) + return NULL; + + bv->ov_vec.v_nr = nr; + M0_ALLOC_ARR(bv->ov_vec.v_count, nr); + if (bv->ov_vec.v_count == NULL) + goto error; + + M0_ALLOC_ARR(bv->ov_buf, nr); + if (bv->ov_buf == NULL) + goto error; + + return bv; + +error: + m0_bufvec_free(bv); + return NULL; +} + +static int clovis_create_obj_attrs_kvs() +{ + int rc; + struct m0_clovis_op *cops[1] = {NULL}; + struct m0_clovis_idx *idx; + + idx = mio_mem_alloc(sizeof *idx); + if (idx == NULL) + return -ENOMEM; + + mio_clovis_obj_md_kvs_id.u_hi = mio_clovis_obj_md_kvs_fid.f_container; + mio_clovis_obj_md_kvs_id.u_lo = mio_clovis_obj_md_kvs_fid.f_key; + m0_clovis_idx_init(idx, &mio_clovis_container.co_realm, + &mio_clovis_obj_md_kvs_id); + + /* Check if object's attrs key-value store exists. */ + m0_clovis_idx_op(idx, M0_CLOVIS_IC_LOOKUP, + NULL, NULL, NULL, 0, &cops[0]); + m0_clovis_op_launch(cops, 1); + rc = m0_clovis_op_wait(cops[0], + M0_BITS(M0_CLOVIS_OS_FAILED, + M0_CLOVIS_OS_STABLE), + M0_TIME_NEVER); + rc = rc? : m0_clovis_rc(cops[0]); + m0_clovis_op_fini(cops[0]); + m0_clovis_op_free(cops[0]); + + /* + * Check returned value (rc): + * - 0: LOOKUP successes and the index has already existed. + * - -ENOENT: the index doesn't exist yet. + * - other error code: LOOKUP op failed for some reason. + */ + if (rc != -ENOENT) + goto exit; + + /* Create the attrs kvs. */ + cops[0] = NULL; + rc = m0_clovis_entity_create(NULL, &idx->in_entity, &cops[0]); + if (rc < 0) + goto exit; + m0_clovis_op_launch(cops, 1); + rc = m0_clovis_op_wait(cops[0], + M0_BITS(M0_CLOVIS_OS_FAILED, + M0_CLOVIS_OS_STABLE), + M0_TIME_NEVER); + rc = rc? : m0_clovis_rc(cops[0]); + m0_clovis_op_fini(cops[0]); + m0_clovis_op_free(cops[0]); + +exit: + if (rc == 0) + mio_obj_attrs_kvs.mk_drv_kvs = idx; + else { + m0_clovis_idx_fini(idx); + mio_mem_free(idx); + } + return rc; +} + +/** + * Initialise and finalise clovis instance. + */ +int mio_clovis_init(struct mio *mio_inst) +{ + int rc; + struct mio_mero_config *drv; + struct m0_idx_dix_config dix_conf; + + drv = (struct mio_mero_config *)mio_inst->m_driver_confs; + mio_clovis_inst_confs = drv; + + /* Set clovis configuration parameters. */ + mio_clovis_conf.cc_is_oostore = drv->mc_is_oostore; + mio_clovis_conf.cc_is_read_verify = drv->mc_is_read_verify; + mio_clovis_conf.cc_local_addr = drv->mc_clovis_local_addr; + mio_clovis_conf.cc_ha_addr = drv->mc_ha_addr; + mio_clovis_conf.cc_profile = drv->mc_profile; + mio_clovis_conf.cc_process_fid = drv->mc_process_fid; + mio_clovis_conf.cc_tm_recv_queue_min_len = drv->mc_tm_recv_queue_min_len; + mio_clovis_conf.cc_max_rpc_msg_size = drv->mc_max_rpc_msg_size; + + mio_clovis_conf.cc_layout_id = + m0_clovis_obj_unit_size_to_layout_id(drv->mc_unit_size); + + mio_clovis_conf.cc_idx_service_id = M0_CLOVIS_IDX_DIX; + dix_conf.kc_create_meta = false; + mio_clovis_conf.cc_idx_service_conf = &dix_conf; + + /* Initial clovis instance. */ + rc = m0_clovis_init(&mio_clovis_instance, &mio_clovis_conf, true); + if (rc != 0) + return rc; + + /* Initial a container. */ + m0_clovis_container_init(&mio_clovis_container, NULL, + &M0_CLOVIS_UBER_REALM, + mio_clovis_instance); + rc = mio_clovis_container.co_realm.re_entity.en_sm.sm_rc; + if (rc != 0) { + mio_log(MIO_ERROR, "Failed to open Clovis's uber realm!\n"); + goto error; + } + + /* Create object attrs kvs if it doesn't exist. */ + rc = clovis_create_obj_attrs_kvs(); + if (rc != 0) { + mio_log(MIO_ERROR, "Failed to create attrs key-value set!\n"); + goto error; + } + return 0; + +error: + m0_clovis_fini(mio_clovis_instance, true); + return rc; +} + +static void mio_clovis_fini() +{ + m0_clovis_idx_fini( + (struct m0_clovis_idx *)mio_obj_attrs_kvs.mk_drv_kvs); + m0_clovis_fini(mio_clovis_instance, true); +} + +static int mio_clovis_thread_init(struct mio_thread *thread) +{ + struct m0_thread *mthread; + + mthread = mio_mem_alloc(sizeof(*mthread)); + if (mthread == NULL) + return -ENOMEM; + memset(mthread, 0, sizeof(struct m0_thread)); + m0_thread_adopt(mthread, mio_clovis_instance->m0c_mero); + thread->mt_drv_thread = mthread; + return 0; +} + +static void mio_clovis_thread_fini(struct mio_thread *thread) +{ + m0_thread_shun(); + mio_mem_free(thread->mt_drv_thread); +} + +static struct mio_driver_sys_ops mio_clovis_sys_ops = { + .mdo_init = mio_clovis_init, + .mdo_fini = mio_clovis_fini, + .mdo_thread_init = mio_clovis_thread_init, + .mdo_thread_fini = mio_clovis_thread_fini +}; + +static void mio_clovis_op_fini(struct mio_op *mop) +{ + struct m0_clovis_op *cop; + struct mio_driver_op *dop; + + dop = mop->mop_drv_op_chain.mdoc_head; + while(dop != NULL) { + mop->mop_drv_op_chain.mdoc_head = dop->mdo_next; + dop->mdo_next = NULL; + + cop = (struct m0_clovis_op *)dop->mdo_op; + m0_clovis_op_fini(cop); + m0_clovis_op_free(cop); + mio_mem_free(dop); + + dop = mop->mop_drv_op_chain.mdoc_head; + } +} + +static int +mio_clovis_op_wait(struct mio_op *mop, uint64_t timeout, int *retstate) +{ + int rc; + struct m0_clovis_op *cop; + + cop = MIO_CLOVIS_OP(mop); + rc = m0_clovis_op_wait(cop, M0_BITS(M0_CLOVIS_OS_STABLE, + M0_CLOVIS_OS_FAILED), + timeout); + /* + * Check returned value (rc) from m0_clovis_op_wait: + * - errors (rc < 0), treat timeout error differently. + * - rc == 0, the operation is completed, then check the + * operation's rc value to see if the op is successful or failed. + */ + if (rc == 0) { + if (m0_clovis_rc(cop) < 0) { + *retstate = MIO_OP_FAILED; + rc = m0_clovis_rc(cop); + } else + *retstate = MIO_OP_COMPLETED; + } else if (rc == -ETIMEDOUT) + *retstate = MIO_OP_ONFLY; + else + *retstate = MIO_OP_FAILED; + return rc; +} + +/** + * The callback functions defined for MIO operation have different + * arguments with the ones of drivers', such as Clovis. A jumper + * function here is used to call the callback functions set by MIO + * applications. + * + * The callback functions shown below give examples on how to relay + * control to callbacks set by apps. + * + * This looks a bit ugly, is there any better solution? + */ +static void clovis_op_cb_complete(struct m0_clovis_op *cop) +{ + int rc; + struct mio_op *mop; + + mop = (struct mio_op *)cop->op_datum; + if (!mop->mop_drv_op_chain.mdoc_head->mdo_post_proc) + goto app_cb; + + rc = mop->mop_drv_op_chain.mdoc_head->mdo_post_proc(mop); + if (rc == MIO_DRV_OP_NEXT) + return; + +app_cb: + mio_driver_op_invoke_real_cb(mop, 0); +} + +static void clovis_op_cb_failed(struct m0_clovis_op *cop) +{ + struct mio_op *mop; + + mop = (struct mio_op *)cop->op_datum; + mio_driver_op_invoke_real_cb(mop, m0_clovis_rc(cop)); +} + +static struct m0_clovis_op_ops clovis_op_cbs; +static int +mio_clovis_op_set_cbs(struct mio_op *mop) + +{ + struct m0_clovis_op *cop; + + assert(mop != NULL); + + clovis_op_cbs.oop_executed = NULL; + clovis_op_cbs.oop_stable = clovis_op_cb_complete; + clovis_op_cbs.oop_failed = clovis_op_cb_failed; + cop = MIO_CLOVIS_OP(mop); + cop->op_datum = (void *)mop; + m0_clovis_op_setup(cop, &clovis_op_cbs, 0); + + return 0; +} + +static struct mio_op_ops mio_clovis_op_ops = { + .mopo_fini = mio_clovis_op_fini, + .mopo_wait = mio_clovis_op_wait, + .mopo_set_cbs = mio_clovis_op_set_cbs +}; + +void mio__uint128_to_obj_id(struct m0_uint128 *uint128, + struct mio_obj_id *oid) +{ + uint64_t hi = uint128->u_hi; + uint64_t lo = uint128->u_lo; + + hi = mio_byteorder_cpu_to_be64(hi); + lo = mio_byteorder_cpu_to_be64(lo); + + mio_mem_copy(&oid->moi_bytes[0], &hi, sizeof(hi)); + mio_mem_copy(&oid->moi_bytes[8], &lo, sizeof(lo)); +} + +void mio__obj_id_to_uint128(const struct mio_obj_id *oid, + struct m0_uint128 *uint128) +{ + uint64_t *hi = (uint64_t *)&oid->moi_bytes[0]; + uint64_t *lo = (uint64_t *)&oid->moi_bytes[8]; + + uint128->u_hi = mio_byteorder_be64_to_cpu(*hi); + uint128->u_lo = mio_byteorder_be64_to_cpu(*lo); +} + +static int clovis_obj_open_pp(struct mio_op *op) +{ + int rc; + struct mio_obj *obj = op->mop_who.obj; + struct m0_clovis_op *cop; + + cop = MIO_CLOVIS_OP(op); + rc = m0_clovis_rc(cop); + if (rc < 0) + return rc; + + /* Launch a new op to get object attributes. */ + rc = clovis_obj_attrs_query(M0_CLOVIS_IC_GET, obj, + clovis_obj_attrs_get_pp, op); + if (rc < 0) + return rc; + else + return MIO_DRV_OP_NEXT; +} + +static int mio_clovis_obj_open(struct mio_obj *obj, struct mio_op *op) +{ + int rc; + struct m0_uint128 id128; + struct m0_clovis_obj *cobj; + struct m0_clovis_op *cops[1] = {NULL}; + + cobj = mio_mem_alloc(sizeof *cobj); + if (cobj == NULL) + return -ENOMEM; + + mio__obj_id_to_uint128(&obj->mo_id, &id128); + m0_clovis_obj_init(cobj, &mio_clovis_container.co_realm, &id128, + mio_clovis_inst_confs->mc_default_layout_id); + rc = m0_clovis_entity_open(&cobj->ob_entity, &cops[0]); + if (rc != 0) + goto error; + + obj->mo_drv_obj = (void *)cobj; + rc = mio_driver_op_add(op, clovis_obj_open_pp, NULL, cops[0]); + if (rc < 0) + goto error; + m0_clovis_op_launch(cops, 1); + return 0; + +error: + if (cops[0] != NULL) { + m0_clovis_op_fini(cops[0]); + m0_clovis_op_free(cops[0]); + } + m0_clovis_obj_fini(cobj); + mio_mem_free(cobj); + return rc; +} + +static int mio_clovis_obj_close(struct mio_obj *obj) +{ + m0_clovis_obj_fini((struct m0_clovis_obj *)obj->mo_drv_obj); + return 0; +} + +static void pool_id_to_fid(const struct mio_pool *pool_id, struct m0_fid *fid) +{ + fid->f_container = pool_id->mp_hi; + fid->f_key = pool_id->mp_lo; +} + +static int mio_clovis_obj_create(const struct mio_pool *pool_id, + struct mio_obj *obj, struct mio_op *op) +{ + int rc = 0; + struct m0_fid pfid; + struct m0_fid *ptr_pfid = NULL; + struct m0_uint128 id128; + struct m0_clovis_obj *cobj; + struct m0_clovis_op *cops[1] = {NULL}; + + if (pool_id != NULL) { + pool_id_to_fid(pool_id, &pfid); + ptr_pfid = &pfid; + } + + cobj = mio_mem_alloc(sizeof *cobj); + if (cobj == NULL) + return -ENOMEM; + + mio__obj_id_to_uint128(&obj->mo_id, &id128); + m0_clovis_obj_init(cobj, &mio_clovis_container.co_realm, &id128, + mio_clovis_inst_confs->mc_default_layout_id); + rc = m0_clovis_entity_create(ptr_pfid, &cobj->ob_entity, &cops[0]); + if (rc < 0) + goto error; + + obj->mo_drv_obj = (void *)cobj; + rc = mio_driver_op_add(op, NULL, NULL, cops[0]); + if (rc < 0) + goto error; + m0_clovis_op_launch(cops, 1); + return 0; + +error: + if (cops[0] != NULL) { + m0_clovis_op_fini(cops[0]); + m0_clovis_op_free(cops[0]); + } + m0_clovis_obj_fini(cobj); + mio_mem_free(cobj); + return rc; +} + +static int clovis_obj_delete_pp(struct mio_op *op) +{ + int rc = 0; + struct mio_obj *mobj = op->mop_who.obj; + struct m0_clovis_obj *cobj = (struct m0_clovis_obj *)mobj->mo_drv_obj; + + /* Launch a new op to delete this object's attributes. */ + rc = clovis_obj_attrs_query(M0_CLOVIS_IC_DEL, mobj, + clovis_obj_attrs_query_free_pp, op); + + /* The opened object is not needed any more. */ + mio_mem_free(cobj); + mio_mem_free(mobj); + + if (rc < 0) + return rc; + else + return MIO_DRV_OP_NEXT; +} + +static int +clovis_obj_delete_open_pp(struct mio_op *op) +{ + int rc = 0; + struct m0_clovis_op *cops[1] = {NULL}; + struct m0_clovis_obj *cobj; + struct mio_obj *mobj = op->mop_who.obj; + + cobj = (struct m0_clovis_obj *)mobj->mo_drv_obj; + rc = m0_clovis_entity_delete(&cobj->ob_entity, &cops[0]); + if (rc != 0) { + mio_log(MIO_ERROR, "Creating DELETE op failed!\n"); + goto error; + } + + rc = mio_driver_op_add(op, clovis_obj_delete_pp, NULL, cops[0]); + if (rc < 0) + goto error; + m0_clovis_op_launch(cops, ARRAY_SIZE(cops)); + return MIO_DRV_OP_NEXT; + +error: + if (cops[0] != NULL) { + m0_clovis_op_fini(cops[0]); + m0_clovis_op_free(cops[0]); + } + m0_clovis_obj_fini(cobj); + mio_mem_free(cobj); + mio_mem_free(mobj); + return rc; +} + +/** + * Deleting an object takes the following steps: + * (1) Open the object to fetch required Mero-wise object attributes. + * (2) Create and launch DELETE op to remove the object data. + * (3) Create and launch an KVS DEL op to remove this object MIO attributes. + */ +static int +mio_clovis_obj_delete(const struct mio_obj_id *oid, struct mio_op *op) +{ + int rc = 0; + struct m0_uint128 id128; + struct m0_clovis_obj *cobj; + struct m0_clovis_op *cops[1] = {NULL}; + struct mio_obj *mobj; + + /* Create a mio obj handler for callback. */ + mobj = mio_mem_alloc(sizeof *mobj); + if (mobj == NULL) + return -ENOMEM; + mobj->mo_id = *oid; + op->mop_who.obj = mobj; + + cobj = mio_mem_alloc(sizeof *cobj); + if (cobj == NULL) { + mio_mem_free(mobj); + return -ENOMEM; + } + mobj->mo_drv_obj = (void *)cobj; + mobj->mo_md_kvs = &mio_obj_attrs_kvs; + + mio__obj_id_to_uint128(&mobj->mo_id, &id128); + m0_clovis_obj_init(cobj, &mio_clovis_container.co_realm, &id128, + mio_clovis_inst_confs->mc_default_layout_id); + rc = m0_clovis_entity_open(&cobj->ob_entity, &cops[0]); + if (rc != 0) { + mio_log(MIO_ERROR, + "Creating OPEN op for object deletion failed!\n"); + goto error; + } + + rc = mio_driver_op_add(op, clovis_obj_delete_open_pp, NULL, cops[0]); + if (rc < 0) + goto error; + m0_clovis_op_launch(cops, ARRAY_SIZE(cops)); + return 0; + +error: + if (cops[0] != NULL) { + m0_clovis_op_fini(cops[0]); + m0_clovis_op_free(cops[0]); + } + m0_clovis_obj_fini(cobj); + mio_mem_free(cobj); + mio_mem_free(mobj); + return rc; +} + +static bool is_rw_2big(const struct mio_iovec *iov, int iovcnt) +{ + int i; + int nr_units = 0; + uint64_t unit_size; + + unit_size = m0_clovis_obj_layout_id_to_unit_size( + mio_clovis_inst_confs->mc_default_layout_id); + for (i = 0; i < iovcnt; i++) + nr_units += (iov[i].miov_len + unit_size - 1) / unit_size; + return nr_units > MIO_CLOVIS_MAX_RW_NR_UNITS_PER_OP? true : false; +} + +static int clovis_obj_write_pp(struct mio_op *op) +{ + int rc; + bool update_size; + uint64_t *max_eow; + struct mio_obj *obj = op->mop_who.obj; + + max_eow = (uint64_t *) + op->mop_drv_op_chain.mdoc_head->mdo_post_proc_data; + update_size = (*max_eow <= obj->mo_attrs.moa_size)? false : true; + mio_mem_free(max_eow); + if (!update_size) + return MIO_DRV_OP_FINAL; + + /* Launch a new op to update object size. */ + obj->mo_attrs.moa_size = *max_eow; + rc = clovis_obj_attrs_query(M0_CLOVIS_IC_PUT, obj, + clovis_obj_attrs_query_free_pp, op); + if (rc < 0) + return rc; + else + return MIO_DRV_OP_NEXT; +} + +static int clovis_obj_rw(struct mio_obj *obj, + const struct mio_iovec *iov, int iovcnt, + enum m0_clovis_obj_opcode opcode, + struct mio_op *op) +{ + int i; + int rc = 0; + uint64_t *max_eow = NULL; /* eow: End Of Write */ + struct m0_clovis_obj *cobj; + struct m0_clovis_op *cops[1] = {NULL}; + struct m0_indexvec ext; + struct m0_bufvec data; + struct m0_bufvec attr; + + assert(opcode == M0_CLOVIS_OC_READ || opcode == M0_CLOVIS_OC_WRITE); + + if (is_rw_2big(iov, iovcnt)) + return -E2BIG; + + if (iovcnt < 1) + return -EINVAL; + + /* Allocate memory for bufvec and indexvec. */ + rc = m0_bufvec_empty_alloc(&data, iovcnt) ? : + m0_bufvec_alloc(&attr, iovcnt, 1) ? : + m0_indexvec_alloc(&ext, iovcnt); + if (rc != 0) + goto error; + + max_eow = mio_mem_alloc(sizeof *max_eow); + if (max_eow == NULL) + goto error; + + /* + * Populate bufvec and indexvec. Avoid copying data + * into bufvec. + */ + for (i = 0; i < iovcnt; i++) { + data.ov_vec.v_count[i] = iov[i].miov_len; + data.ov_buf[i] = iov[i].miov_base; + + ext.iv_index[i] = iov[i].miov_off; + ext.iv_vec.v_count[i] = iov[i].miov_len; + if (iov[i].miov_off + iov[i].miov_len > *max_eow) + *max_eow = iov[i].miov_off + iov[i].miov_len; + + /* we don't want any attributes */ + attr.ov_vec.v_count[i] = 0; + } + + /* Create and launch an RW op. */ + cobj = (struct m0_clovis_obj *)obj->mo_drv_obj; + m0_clovis_obj_op(cobj, opcode, &ext, &data, &attr, 0, &cops[0]); + + /* Set callback and then launch IO op. */ + if (opcode == M0_CLOVIS_OC_WRITE) + rc = mio_driver_op_add( + op, clovis_obj_write_pp, max_eow, cops[0]); + else + rc = mio_driver_op_add(op, NULL, NULL, cops[0]); + if (rc < 0) + goto error; + + m0_clovis_op_launch(cops, ARRAY_SIZE(cops)); + return 0; + +error: + m0_indexvec_free(&ext); + m0_bufvec_free(&data); + m0_bufvec_free(&attr); + mio_mem_free(max_eow); + return rc; +} + +static int mio_clovis_obj_readv(struct mio_obj *obj, + const struct mio_iovec *iov, + int iovcnt, struct mio_op *op) +{ + return clovis_obj_rw(obj, iov, iovcnt, M0_CLOVIS_OC_READ, op); +} + +static int mio_clovis_obj_writev(struct mio_obj *obj, + const struct mio_iovec *iov, + int iovcnt, struct mio_op *op) +{ + return clovis_obj_rw(obj, iov, iovcnt, M0_CLOVIS_OC_WRITE, op); +} + +static int mio_clovis_obj_sync(struct mio_obj *obj, struct mio_op *op) +{ + int rc; + struct m0_clovis_obj *cobj; + struct m0_clovis_op *sync_op = {NULL}; + + rc = m0_clovis_sync_op_init(&sync_op); + if (rc < 0) + return rc; + + cobj = (struct m0_clovis_obj *)obj->mo_drv_obj; + rc = m0_clovis_sync_entity_add(sync_op, &cobj->ob_entity); + if (rc < 0) + goto error; + + rc = mio_driver_op_add(op, NULL, NULL, sync_op); + if (rc < 0) + goto error; + m0_clovis_op_launch(&sync_op, 1); + return 0; + +error: + m0_clovis_op_fini(sync_op); + m0_clovis_op_free(sync_op); + return rc; +} + +/** + * Note: currently Mero Clovis doesn't store size as object attribute + * and doesn't have any API to query object size. MIO will use an index + * (attribute index) to manage object attributes such as object size. + * This also implies that any object WRITE has to update the size. + * Depending on workload and performance of Mero index, MIO may support + * multiple indics. + * + * Format of object attributes that are stored in attribute index are + * defined as below: + * + * struct clovis_obj_attrs_onwire { + * struct mio_obj_attrs coa_attrs; + * int coa_nr_hints; + * int coa_hint_keys[]; // array of hint's keys + * uint64_t coa_hint_values[]; // array of hint's values + * }; + * + * Note: MIO assumes application takes care of concurrent accesses to + * an object and its attributes. + */ + +struct clovis_obj_attrs_pp_args { + int32_t *aca_rc; + struct m0_bufvec *aca_key; + struct m0_bufvec *aca_val; + /* Where the returned attributes are copied to. */ + struct mio_obj *aca_to; +}; + +static int clovis_obj_attr_nonhint_size(struct mio_obj *obj) +{ + int size; + + size = sizeof obj->mo_attrs.moa_size; + size += sizeof obj->mo_attrs.moa_wtime; + return size; +} + +static int +clovis_obj_attrs_mem2wire(struct mio_obj *obj, + uint64_t *attr_size, void **attr_buf) +{ + int i; + int nonhint_size; + uint64_t size; + void *buf; + char *ptr; + struct mio_hint_map *map = &obj->mo_attrs.moa_phints.mh_map; + + nonhint_size = clovis_obj_attr_nonhint_size(obj); + size = nonhint_size; + size += sizeof(int); + size += map->mhm_nr_set * (sizeof(int) + sizeof(uint64_t)); + + buf = mio_mem_alloc(size); + if (buf == NULL) + return -ENOMEM; + + ptr = buf; + mio_mem_copy(ptr, &obj->mo_attrs, nonhint_size); + ptr += nonhint_size; + + mio_mem_copy(ptr, &map->mhm_nr_set, sizeof(int)); + ptr += sizeof(int); + + for (i = 0; i < map->mhm_nr_set; i++) { + mio_mem_copy(ptr, map->mhm_keys + i, sizeof(int)); + ptr += sizeof(int); + } + + for (i = 0; i < map->mhm_nr_set; i++) { + mio_mem_copy(ptr, map->mhm_values + i, sizeof(uint64_t)); + ptr += sizeof(uint64_t); + } + + *attr_size = size; + *attr_buf = buf; + return 0; +} + +static int +clovis_obj_attrs_wire2mem(struct mio_obj *obj, int attr_size, void *attr_buf) +{ + int i; + int nonhint_size; + int size; + int nr_hints; + char *ptr; + /* Note that hint map has been initialised with default number. */ + struct mio_hint_map *map = &obj->mo_hints.mh_map; + + nonhint_size = clovis_obj_attr_nonhint_size(obj); + ptr = attr_buf; + mio_mem_copy(&obj->mo_attrs, ptr, nonhint_size); + ptr += nonhint_size; + + mio_mem_copy(&nr_hints, ptr, sizeof(int)); + ptr += sizeof(int); + if (nr_hints < 0 || nr_hints > MIO_OBJ_HINT_NUM) + return -EIO; + else if (nr_hints == 0) + return 0; + map->mhm_nr_set = nr_hints; + + size = nonhint_size; + size += sizeof(int); + size += nr_hints * (sizeof(int) + sizeof(uint64_t)); + if (attr_size != size) + return -EIO; + + for (i = 0; i < nr_hints; i++) { + mio_mem_copy(map->mhm_keys + i, ptr, sizeof(int)); + ptr += sizeof(int); + } + + for (i = 0; i < nr_hints; i++) { + mio_mem_copy(map->mhm_values + i, ptr, sizeof(uint64_t)); + ptr += sizeof(uint64_t); + } + + return 0; +} + +static int clovis_obj_attrs_query(int opcode, struct mio_obj *obj, + mio_driver_op_postprocess op_pp, + struct mio_op *op) +{ + int rc; + int32_t *qrc = NULL; /* return value for kvs query. */ + struct m0_uint128 *id128; + struct m0_bufvec *key = NULL; + struct m0_bufvec *val = NULL; + struct m0_clovis_idx *idx; + struct m0_clovis_op *cops[1] = {NULL}; + struct clovis_obj_attrs_pp_args *args; + + assert(opcode == M0_CLOVIS_IC_GET || opcode == M0_CLOVIS_IC_PUT || + opcode == M0_CLOVIS_IC_DEL); + + id128 = mio_mem_alloc(sizeof *id128); + qrc = mio_mem_alloc(sizeof(int32_t)); + args = mio_mem_alloc(sizeof *args); + if (id128 == NULL || qrc == NULL || args == NULL) { + rc = -ENOMEM; + goto error; + } + + /* Allocate bufvec's for keys and values. */ + key = mio__clovis_bufvec_alloc(1); + if (key == NULL) { + rc = -ENOMEM; + goto error; + } + + if (opcode != M0_CLOVIS_IC_DEL) { + val = mio__clovis_bufvec_alloc(1); + if (val == NULL) { + rc = -ENOMEM; + goto error; + } + } + + /* Fill key and value. TODO: serialise key and value? */ + mio__obj_id_to_uint128(&obj->mo_id, id128); + key->ov_vec.v_count[0] = sizeof *id128; + key->ov_buf[0] = id128; + + if (opcode == M0_CLOVIS_IC_PUT) + clovis_obj_attrs_mem2wire(obj, &val->ov_vec.v_count[0], + &val->ov_buf[0]); + + /* Create index's op. */ + idx = (struct m0_clovis_idx *)obj->mo_md_kvs->mk_drv_kvs; + rc = m0_clovis_idx_op(idx, opcode, key, val, qrc, 0, &cops[0]); + if (rc < 0) + goto error; + + /* Set callback function and arguments. */ + args->aca_val = val; + args->aca_key = key; + args->aca_rc = qrc; + args->aca_to = obj; + rc = mio_driver_op_add(op, op_pp, args, cops[0]); + if (rc < 0) + goto error; + + m0_clovis_op_launch(cops, 1); + return 0; + +error: + clovis_bufvec_free(key); + clovis_bufvec_free(val); + mio_mem_free(qrc); + mio_mem_free(args); + return rc; +} + +static int clovis_obj_attrs_query_free_pp(struct mio_op *op) +{ + struct clovis_obj_attrs_pp_args *args; + + args = (struct clovis_obj_attrs_pp_args *) + op->mop_drv_op_chain.mdoc_head->mdo_post_proc_data; + clovis_bufvec_free(args->aca_key); + clovis_bufvec_free(args->aca_val); + mio_mem_free(args->aca_rc); + mio_mem_free(args); + + return MIO_DRV_OP_FINAL; +} + +static int clovis_obj_attrs_get_pp(struct mio_op *op) +{ + struct m0_bufvec *ret_val; + struct m0_clovis_op *cop = MIO_CLOVIS_OP(op); + struct mio_obj *obj; + struct clovis_obj_attrs_pp_args *args; + + assert(cop != NULL); + args = (struct clovis_obj_attrs_pp_args *) + op->mop_drv_op_chain.mdoc_head->mdo_post_proc_data; + obj = args->aca_to; + ret_val = args->aca_val; + if (ret_val->ov_vec.v_count[0] != 0) + clovis_obj_attrs_wire2mem(obj, ret_val->ov_vec.v_count[0], + ret_val->ov_buf[0]); + + return clovis_obj_attrs_query_free_pp(op); +} + +static int mio_clovis_obj_size(struct mio_obj *obj, struct mio_op *op) +{ + return clovis_obj_attrs_query(M0_CLOVIS_IC_GET, obj, + clovis_obj_attrs_get_pp, op); +} + +static int mio_clovis_obj_hint_store(struct mio_obj *obj) +{ + int rc; + struct mio_op mop; + struct m0_clovis_op *cop; + + mio_memset(&mop, 0, sizeof mop); + mio_obj_op_init(&mop, obj, MIO_OBJ_ATTRS_SET); + rc = clovis_obj_attrs_query(M0_CLOVIS_IC_PUT, obj, + clovis_obj_attrs_query_free_pp, &mop); + if (rc < 0) + return rc; + + cop = MIO_CLOVIS_OP((&mop)); + rc = m0_clovis_op_wait(cop, + M0_BITS(M0_CLOVIS_OS_FAILED, + M0_CLOVIS_OS_STABLE), + M0_TIME_NEVER); + rc = rc? : m0_clovis_rc(cop); + m0_clovis_op_fini(cop); + m0_clovis_op_free(cop); + return rc; +} + +static int mio_clovis_obj_hint_load(struct mio_obj *obj) +{ + /* + * Hints are retrieved when an object is opened, no more work + * here. + */ + return 0; +} + +static struct mio_obj_ops mio_clovis_obj_ops = { + .moo_open = mio_clovis_obj_open, + .moo_close = mio_clovis_obj_close, + .moo_create = mio_clovis_obj_create, + .moo_delete = mio_clovis_obj_delete, + .moo_writev = mio_clovis_obj_writev, + .moo_readv = mio_clovis_obj_readv, + .moo_sync = mio_clovis_obj_sync, + .moo_size = mio_clovis_obj_size, + .moo_hint_store = mio_clovis_obj_hint_store, + .moo_hint_load = mio_clovis_obj_hint_load, +}; + +static void kvs_id_to_uint128(const struct mio_kvs_id *kid, + struct m0_uint128 *uint128) +{ + struct m0_fid idx_fid; + uint64_t hi; + uint64_t lo; + + hi = mio_byteorder_be64_to_cpu(*((uint64_t *)(kid->mki_bytes + 0))); + lo = mio_byteorder_be64_to_cpu(*((uint64_t *)(kid->mki_bytes + 8))); + /* Make mero KVS happy */ + idx_fid = M0_FID_TINIT('x', hi, lo); + + uint128->u_hi = idx_fid.f_container; + uint128->u_lo = idx_fid.f_key; +} + +static int +clovis_kvs_idx_alloc_init(struct mio_kvs_id *kid, struct m0_clovis_idx **out) +{ + struct m0_uint128 id; + struct m0_clovis_idx *idx; + + idx = mio_mem_alloc(sizeof *idx); + if (idx == NULL) + return -ENOMEM; + + kvs_id_to_uint128(kid, &id); + m0_clovis_idx_init(idx, &mio_clovis_container.co_realm, &id); + *out = idx; + return 0; +} + +static void clovis_kvs_idx_fini_free(struct m0_clovis_idx *idx) +{ + m0_clovis_entity_fini(&idx->in_entity); + mio_mem_free(idx); +} + +static int +clovis_kvs_keys_vals_alloc(int opcode, int nr_kvps, + struct m0_bufvec **ret_keys, + struct m0_bufvec **ret_vals) +{ + int rc = 0; + struct m0_bufvec *keys; + struct m0_bufvec *vals = NULL; + + assert(opcode == M0_CLOVIS_IC_GET || opcode == M0_CLOVIS_IC_PUT || + opcode == M0_CLOVIS_IC_DEL); + + keys = mio__clovis_bufvec_alloc(nr_kvps); + if (keys == NULL) { + rc = -ENOMEM; + goto error; + } + + if (opcode != M0_CLOVIS_IC_DEL) { + vals = mio__clovis_bufvec_alloc(nr_kvps); + if (vals == NULL) { + rc = -ENOMEM; + goto error; + } + } + + *ret_keys = keys; + *ret_vals = vals; + return 0; + +error: + clovis_bufvec_free(keys); + clovis_bufvec_free(vals); + return rc; +} + +static int clovis_kvs_query(struct m0_clovis_idx *idx, int opcode, + int nr_kvps, struct mio_kv_pair *kvps, int32_t *rcs, + struct m0_bufvec *keys, struct m0_bufvec *vals, + mio_driver_op_postprocess query_pp, void *cb_args, + struct mio_op *op) +{ + int i; + int rc = 0; + bool set_vals; + struct m0_clovis_op *cops[1] = {NULL}; + + assert(opcode == M0_CLOVIS_IC_GET || opcode == M0_CLOVIS_IC_PUT || + opcode == M0_CLOVIS_IC_DEL); + + set_vals = (opcode == M0_CLOVIS_IC_PUT)? true : false; + + /* Fill keys and values. */ + for (i = 0; i < nr_kvps; i++) { + keys->ov_vec.v_count[i] = kvps[i].mkp_klen; + keys->ov_buf[i] = kvps[i].mkp_key; + + if (set_vals) { + assert(vals != NULL); + vals->ov_vec.v_count[i] = kvps[i].mkp_vlen; + vals->ov_buf[i] = kvps[i].mkp_val; + } + } + + /* Create index op. */ + rc = m0_clovis_idx_op(idx, opcode, keys, vals, rcs, 0, &cops[0]); + if (rc < 0) + goto error; + + /* Set query's callback and arguments. */ + rc = mio_driver_op_add(op, query_pp, cb_args, cops[0]); + if (rc < 0) + goto error; + + /* Launch query. */ + m0_clovis_op_launch(cops, 1); + + return 0; + +error: + clovis_bufvec_free(keys); + clovis_bufvec_free(vals); + return rc; +} + +struct clovis_kvs_get_args { + struct m0_bufvec *kga_rvs; /* Returned values from clovis GET op. */ + struct mio_kv_pair *kga_orig_pairs; /* Original pointer from app. */ + struct m0_clovis_idx *kga_idx; /* The clovis index for the GET op. */ +}; + +static int clovis_kvs_get_pp(struct mio_op *op) +{ + int i; + int nr_kvps; + struct clovis_kvs_get_args *args; + struct mio_kv_pair *kvps; + struct m0_bufvec *rvs; + struct m0_clovis_op *cop = MIO_CLOVIS_OP(op); + + assert(cop != NULL); + if (cop->op_sm.sm_state != M0_CLOVIS_OS_STABLE) + return -EIO; + + /* Copy returned values. */ + args = (struct clovis_kvs_get_args *) + op->mop_drv_op_chain.mdoc_head->mdo_post_proc_data; + kvps = args->kga_orig_pairs; + rvs = args->kga_rvs; + nr_kvps = rvs->ov_vec.v_nr; + for (i = 0; i < nr_kvps; i++) { + kvps[i].mkp_val = rvs->ov_buf[i]; + kvps[i].mkp_vlen = rvs->ov_vec.v_count[i]; + } + + clovis_kvs_idx_fini_free(args->kga_idx); + mio_mem_free(args); + return MIO_DRV_OP_FINAL; +} + +static int mio_clovis_kvs_get(struct mio_kvs_id *kid, + int nr_kvps, struct mio_kv_pair *kvps, + int32_t *rcs, struct mio_op *op) +{ + int rc; + struct clovis_kvs_get_args *args; + struct m0_clovis_idx *idx; + struct m0_bufvec *keys = NULL; + struct m0_bufvec *vals = NULL; + + rc = clovis_kvs_idx_alloc_init(kid, &idx); + if (rc < 0) + return rc; + + rc = clovis_kvs_keys_vals_alloc( + M0_CLOVIS_IC_GET, nr_kvps, &keys, &vals); + if (rc < 0) + goto error; + + args = mio_mem_alloc(sizeof *args); + if (args == NULL) { + rc = -ENOMEM; + goto error; + } + + /* Save the arguments for post-processing. */ + args->kga_rvs = vals; + args->kga_orig_pairs = kvps; + args->kga_idx = idx; + + rc = clovis_kvs_query(idx, M0_CLOVIS_IC_GET, + nr_kvps, kvps, rcs, keys, vals, + clovis_kvs_get_pp, args, op); + if (rc < 0) { + clovis_kvs_idx_fini_free(idx); + mio_mem_free(args); + } + return rc; + +error: + clovis_kvs_idx_fini_free(idx); + clovis_bufvec_free(keys); + clovis_bufvec_free(vals); + mio_mem_free(args); + return rc; +} + +static int clovis_kvs_generic_pp(struct mio_op *op) +{ + struct m0_clovis_idx *idx; + + idx = (struct m0_clovis_idx*) + op->mop_drv_op_chain.mdoc_head->mdo_post_proc_data; + clovis_kvs_idx_fini_free(idx); + + return MIO_DRV_OP_FINAL; +} + +static int mio_clovis_kvs_put(struct mio_kvs_id *kid, + int nr_kvps, struct mio_kv_pair *kvps, + int32_t *rcs, struct mio_op *op) +{ + int rc; + struct m0_clovis_idx *idx; + struct m0_bufvec *keys = NULL; + struct m0_bufvec *vals = NULL; + + rc = clovis_kvs_idx_alloc_init(kid, &idx); + if (rc < 0) + return rc; + + rc = clovis_kvs_keys_vals_alloc( + M0_CLOVIS_IC_PUT, nr_kvps, &keys, &vals); + if (rc < 0) { + clovis_kvs_idx_fini_free(idx); + return rc; + } + + return clovis_kvs_query(idx, M0_CLOVIS_IC_PUT, + nr_kvps, kvps, rcs, keys, vals, + clovis_kvs_generic_pp, idx, op); +} + +static int mio_clovis_kvs_del(struct mio_kvs_id *kid, + int nr_kvps, struct mio_kv_pair *kvps, + int32_t *rcs, struct mio_op *op) +{ + + int rc; + struct m0_clovis_idx *idx; + struct m0_bufvec *keys = NULL; + struct m0_bufvec *vals = NULL; + + rc = clovis_kvs_idx_alloc_init(kid, &idx); + if (rc < 0) + return rc; + + rc = clovis_kvs_keys_vals_alloc( + M0_CLOVIS_IC_DEL, nr_kvps, &keys, &vals); + if (rc < 0) { + clovis_kvs_idx_fini_free(idx); + return rc; + } + + return clovis_kvs_query(idx, M0_CLOVIS_IC_DEL, + nr_kvps, kvps, rcs, keys, vals, + clovis_kvs_generic_pp, idx, op); +} + +static int mio_clovis_kvs_create_set(struct mio_kvs_id *kid, + struct mio_op *op) +{ + int rc; + struct m0_clovis_op *cops[1] = {NULL}; + struct m0_clovis_idx *idx; + + rc = clovis_kvs_idx_alloc_init(kid, &idx); + if (rc < 0) + return rc; + + rc = m0_clovis_entity_create(NULL, &idx->in_entity, &cops[0]); + if (rc < 0) + return rc; + + rc = mio_driver_op_add(op, clovis_kvs_generic_pp, idx, cops[0]); + if (rc < 0) + goto error; + m0_clovis_op_launch(cops, 1); + return 0; + +error: + clovis_kvs_idx_fini_free(idx); + m0_clovis_op_fini(cops[0]); + m0_clovis_op_free(cops[0]); + return rc; +} + +static int mio_clovis_kvs_del_set(struct mio_kvs_id *kid, + struct mio_op *op) +{ + int rc; + struct m0_clovis_op *cops[1] = {NULL}; + struct m0_clovis_idx *idx; + + rc = clovis_kvs_idx_alloc_init(kid, &idx); + if (rc < 0) + return rc; + + /* + * Clovis Index has to be opened before deleting it but not before + * querying it. How odd! Who to blame? :). + * The only thing openning an index is to make sure the index is in + * a right state. + */ + m0_clovis_entity_open(&idx->in_entity, &cops[0]); + rc = m0_clovis_entity_delete(&idx->in_entity, &cops[0]); + if (rc < 0) + goto error; + + rc = mio_driver_op_add(op, clovis_kvs_generic_pp, idx, cops[0]); + if (rc < 0) + goto error; + + m0_clovis_op_launch(cops, 1); + return 0; + +error: + clovis_kvs_idx_fini_free(idx); + m0_clovis_op_fini(cops[0]); + m0_clovis_op_free(cops[0]); + return rc; +} + +static struct mio_kvs_ops mio_clovis_kvs_ops = { + .mko_get = mio_clovis_kvs_get, + .mko_put = mio_clovis_kvs_put, + .mko_del = mio_clovis_kvs_del, + .mko_create_set = mio_clovis_kvs_create_set, + .mko_del_set = mio_clovis_kvs_del_set +}; + +void mio_clovis_driver_register() +{ + mio_driver_register( + MIO_MERO, &mio_clovis_sys_ops, + &mio_clovis_op_ops, &mio_clovis_obj_ops, + &mio_clovis_kvs_ops, &mio_clovis_comp_obj_ops); +} + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/src/driver_clovis.h b/deps/mio/src/driver_clovis.h new file mode 100644 index 0000000000000000000000000000000000000000..0aad5f846c60ae5b4d8421c3c61867e597b017b1 --- /dev/null +++ b/deps/mio/src/driver_clovis.h @@ -0,0 +1,64 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#ifndef __DRIVER_CLOVIS_H__ +#define __DRIVER_CLOVIS_H__ + +#include "lib/memory.h" +#include "clovis/clovis.h" +#include "clovis/clovis_idx.h" + +#ifndef __MIO_CLOVIS_COMP_OBJ_LAYER_GET_SUPP__ +#include "lib/list.h" +#include "lib/tlist.h" +#include "clovis/clovis_layout.h" + +#ifndef container_of +#define container_of(ptr, type, member) \ + ((type *)((char *)(ptr)-(char *)(&((type *)0)->member))) +#endif +#endif /* __MIO_CLOVIS_COMP_OBJ_LAYER_GET_SUPP__*/ + +#define ARRAY_SIZE(a) ((sizeof (a)) / (sizeof (a)[0])) + +enum { + MIO_CLOVIS_MAX_RW_NR_UNITS_PER_OP = 1024 +}; + +extern struct m0_clovis *mio_clovis_instance; +extern struct m0_clovis_container mio_clovis_container; +extern struct mio_mero_config *mio_clovis_inst_confs; + +extern struct mio_comp_obj_ops mio_clovis_comp_obj_ops; + +void mio_clovis_driver_register(); + +/* Helper functions. */ +struct m0_bufvec* mio__clovis_bufvec_alloc(int nr); +void mio__obj_id_to_uint128(const struct mio_obj_id *oid, + struct m0_uint128 *uint128); +void mio__uint128_to_obj_id(struct m0_uint128 *uint128, + struct mio_obj_id *oid); +#endif + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/src/driver_clovis_comp_obj.c b/deps/mio/src/driver_clovis_comp_obj.c new file mode 100644 index 0000000000000000000000000000000000000000..f6accf218b0dfe4c70171b072bd5f35213e48e69 --- /dev/null +++ b/deps/mio/src/driver_clovis_comp_obj.c @@ -0,0 +1,679 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <errno.h> +#include <assert.h> + +#include "lib/vec.h" +#include "clovis/clovis.h" +#include "clovis/clovis_idx.h" + +#include "logger.h" +#include "mio.h" +#include "mio_internal.h" +#include "driver_clovis.h" + +/* + * Creating a composite object includes 2 steps: + * (1) Create a `normal` object. + * (2) Set composite layout for this newly created object. + * + * mio_composite_obj_create() is called after an object is created + * by mio_obj_create(). The decision to not pack the above 2 steps + * in mio_composite_obj_create() is to handle failures properly. + * A failure could happen in creating a `normal` object or setting + * composite layout, which requires different clear-up handling. + * + * Note: MIO only supports creating a composite object from a newly + * created one (not yet written any data). + */ + +static int +mio_clovis_comp_obj_create(struct mio_obj *obj, struct mio_op *op) +{ + int rc; + struct m0_clovis_obj *cobj; + struct m0_clovis_op *cops[1] = {NULL}; + struct m0_clovis_layout *layout; + + layout = m0_clovis_layout_alloc(M0_CLOVIS_LT_COMPOSITE); + if (layout == NULL) + return -ENOMEM; + + cobj = (struct m0_clovis_obj *)obj->mo_drv_obj; + /* + * A bug in clovis doesn't set the object's layout pointer. + */ + if (cobj->ob_layout == NULL) + cobj->ob_layout = layout; + m0_clovis_layout_op(cobj, M0_CLOVIS_EO_LAYOUT_SET, + layout, &cops[0]); + + rc = mio_driver_op_add(op, NULL, NULL, cops[0]); + if (rc < 0) + goto error; + m0_clovis_op_launch(cops, ARRAY_SIZE(cops)); + return 0; + +error: + m0_clovis_op_fini(cops[0]); + m0_clovis_op_free(cops[0]); + m0_clovis_layout_free(layout); + return rc; +} + +struct clovis_comp_obj_add_layer_pp_args { + int alpa_nr_layers_to_add; + struct m0_clovis_obj *alpa_layer_objs; + struct m0_clovis_layout *alpa_layout; +}; + +static int clovis_comp_obj_add_layers_pp(struct mio_op *op) +{ + int i; + struct clovis_comp_obj_add_layer_pp_args *pp_args; + + pp_args = (struct clovis_comp_obj_add_layer_pp_args *) + op->mop_drv_op_chain.mdoc_head->mdo_post_proc_data; + for (i = 0; i < pp_args->alpa_nr_layers_to_add; i++) + m0_clovis_obj_fini(pp_args->alpa_layer_objs + i); + mio_mem_free(pp_args->alpa_layer_objs); + mio_mem_free(pp_args); + + return MIO_DRV_OP_FINAL; +} + +static int +mio_clovis_comp_obj_add_layers(struct mio_obj *obj, int nr_layers, + struct mio_comp_obj_layer *layers, + struct mio_op *op) +{ + int rc = 0; + int i; + int j; + struct m0_uint128 id128; + struct m0_clovis_obj *layer_objs; + struct m0_clovis_obj *cobj; + struct m0_clovis_op *cops[1] = {NULL}; + struct m0_clovis_layout *layout = NULL; + struct clovis_comp_obj_add_layer_pp_args *pp_args; + + pp_args = mio_mem_alloc(sizeof(*pp_args)); + layer_objs = mio_mem_alloc(nr_layers * sizeof(*layer_objs)); + if (pp_args == NULL || layer_objs == NULL) { + rc = -ENOMEM; + goto error; + } + + cobj = (struct m0_clovis_obj *)obj->mo_drv_obj; + /* The layout may have been changed. */ + if (cobj->ob_layout != NULL) + m0_clovis_layout_free(cobj->ob_layout); + layout = m0_clovis_layout_alloc(M0_CLOVIS_LT_COMPOSITE); + if (layout == NULL) { + rc = -ENOMEM; + goto error; + } + cobj->ob_layout = layout; + + for (i = 0; i < nr_layers; i++) { + mio__obj_id_to_uint128(&layers[i].mcol_oid, &id128); + m0_clovis_obj_init(layer_objs + i, + &mio_clovis_container.co_realm, &id128, + mio_clovis_inst_confs->mc_default_layout_id); + rc = m0_clovis_composite_layer_add( + layout, layer_objs + i, layers[i].mcol_priority); + if (rc < 0) + break; + } + if (rc != 0) { + for (j = 0; j < i; j++) + m0_clovis_composite_layer_del( + layout, layer_objs[j].ob_entity.en_id); + goto error; + } + + m0_clovis_layout_op(cobj, M0_CLOVIS_EO_LAYOUT_SET, + layout, &cops[0]); + + pp_args->alpa_nr_layers_to_add = nr_layers; + pp_args->alpa_layer_objs = layer_objs; + pp_args->alpa_layout = layout; + rc = mio_driver_op_add(op, clovis_comp_obj_add_layers_pp, + pp_args, cops[0]); + if (rc < 0) + goto error; + + m0_clovis_op_launch(cops, ARRAY_SIZE(cops)); + return 0; + +error: + if (layout) + m0_clovis_layout_free(layout); + mio_mem_free(layer_objs); + mio_mem_free(pp_args); + return rc; +} + +struct clovis_comp_obj_get_layers_args { + /* Returned object layout. */ + struct m0_clovis_layout *gla_clayout; + /* + * Customized data for layer query. For layer listing, it is + * set to the pointer of MIO layout data structure from + * applications. But for layer deleting, it is set to + * the pointer of an array of layers to be deleted. + */ + void *gla_data; +}; + +static int +clovis_comp_obj_get_layers(struct mio_obj *obj, + void *query_data, mio_driver_op_postprocess pp, + struct mio_op *op) +{ + int rc; + struct clovis_comp_obj_get_layers_args *args; + struct m0_clovis_layout *clayout = NULL; + struct m0_clovis_obj *cobj; + struct m0_clovis_op *cops[1] = {NULL}; + + args = mio_mem_alloc(sizeof *args); + if (args == NULL) + return -ENOMEM; + + cobj = (struct m0_clovis_obj *)obj->mo_drv_obj; + /* The layout may have been changed. */ + if (cobj->ob_layout != NULL) + m0_clovis_layout_free(cobj->ob_layout); + clayout = m0_clovis_layout_alloc(M0_CLOVIS_LT_COMPOSITE); + if (clayout == NULL) { + rc = -ENOMEM; + goto error; + } + cobj->ob_layout = clayout; + + m0_clovis_layout_op(cobj, M0_CLOVIS_EO_LAYOUT_GET, clayout, &cops[0]); + + args->gla_data = query_data; + args->gla_clayout = clayout; + rc = mio_driver_op_add(op, pp, args, cops[0]); + if (rc < 0) + goto error; + m0_clovis_op_launch(cops, ARRAY_SIZE(cops)); + return 0; + +error: + m0_clovis_op_fini(cops[0]); + m0_clovis_op_free(cops[0]); + m0_clovis_layout_free(clayout); + return rc; +} + +struct clovis_comp_obj_del_layers_args { + int dla_nr_layers_to_del; + struct mio_comp_obj_layer *dla_layers_to_del; +}; + +static int +clovis_comp_obj_del_layers_pp(struct mio_op *op) +{ + int rc = 0; + int i; + struct mio_obj *obj; + struct m0_uint128 id128; + struct m0_clovis_obj *cobj; + struct m0_clovis_op *cops[1] = {NULL}; + struct m0_clovis_layout *clayout; + int nr_layers_to_del; + struct mio_comp_obj_layer *layers_to_del; + struct clovis_comp_obj_get_layers_args *args; + struct clovis_comp_obj_del_layers_args *del_layers_args; + + obj = op->mop_who.obj; + assert(obj != NULL); + + args = (struct clovis_comp_obj_get_layers_args *) + op->mop_drv_op_chain.mdoc_head->mdo_post_proc_data; + assert(args != NULL); + del_layers_args = + (struct clovis_comp_obj_del_layers_args*) args->gla_data; + nr_layers_to_del = del_layers_args->dla_nr_layers_to_del; + layers_to_del = del_layers_args->dla_layers_to_del; + clayout = (struct m0_clovis_layout *)args->gla_clayout; + + /* Here to remove the layers required. */ + for (i = 0; i < nr_layers_to_del; i++) { + mio__obj_id_to_uint128(&layers_to_del[i].mcol_oid, &id128); + m0_clovis_composite_layer_del(clayout, id128); + } + + /* Create and launch LAYOUT op. */ + cobj = (struct m0_clovis_obj *)obj->mo_drv_obj; + m0_clovis_layout_op(cobj, M0_CLOVIS_EO_LAYOUT_SET, clayout, &cops[0]); + + rc = mio_driver_op_add(op, NULL, NULL, cops[0]); + if (rc < 0) + goto exit; + m0_clovis_op_launch(cops, ARRAY_SIZE(cops)); + rc = MIO_DRV_OP_NEXT; + +exit: + mio_mem_free(del_layers_args); + mio_mem_free(args); + return rc; +} + +static int +mio_clovis_comp_obj_del_layers(struct mio_obj *obj, + int nr_layers_to_del, + struct mio_comp_obj_layer *layers_to_del, + struct mio_op *op) +{ + struct clovis_comp_obj_del_layers_args *args; + + /* + * Deleting layers of a composite object is done in 2 steps: + * (1) retrieve the composite object's layout (how many layers). + * (2) delete layers from the layout and launch an operation to + * update the layout in Mero service side. + */ + + args = mio_mem_alloc(sizeof *args); + if (args == NULL) + return -ENOMEM; + args->dla_nr_layers_to_del = nr_layers_to_del; + args->dla_layers_to_del = layers_to_del; + + return clovis_comp_obj_get_layers(obj, args, + clovis_comp_obj_del_layers_pp, op); +} + +/** + * A new Clovis API to parse the Clovis composite layout data structure is + * needed as a privately defined list is used in Clovis. + * Place holder: m0_clovis_composite_layer_get(). + * + * Temporary solution: MIO hacks it by iterating the layer list by explictly + * manipulating the list as m0_tl_* APIs are exposed in 'libmero'. + */ +#ifdef __MIO_CLOVIS_COMP_OBJ_LAYER_GET_SUPP__ +static int clovis_comp_obj_list_layers_pp(struct mio_op *op) +{ + int i; + int rc = 0; + uint64_t nr_layers = 0; + struct m0_uint128 *layer_ids; + struct m0_clovis_op *cop; + struct m0_clovis_layout *clayout; + struct mio_comp_obj_layout *mlayout; + struct clovis_comp_obj_get_layers_args *args; + + cop = (struct m0_clovis_op *) + op->mop_drv_op_chain.mdoc_head->mdo_op; + assert(cop != NULL); + if (cop->op_sm.sm_state != M0_CLOVIS_OS_STABLE) + return -EIO; + + args = (struct clovis_comp_obj_get_layers_args *) + op->mop_drv_op_chain.mdoc_head->mdo_post_proc_data; + mlayout = (struct mio_comp_obj_layout *)args->gla_data; + clayout = (struct m0_clovis_layout *)args->gla_clayout; + + /* Retrieve layers. */ + rc = m0_clovis_composite_layer_get(clayout, &nr_layers, &layer_ids); + if (rc < 0) + goto exit; + + mlayout->mlo_nr_layers = nr_layers; + mlayout->mlo_layers = + mio_mem_alloc(nr_layers * sizeof(struct mio_comp_obj_layer)); + if (mlayout->mlo_layers == NULL) { + rc = -ENOMEM; + goto exit; + } + + for (i = 0; i < nr_layers; i++) + mio__uint128_to_obj_id( + layers_ids + i, &((mlayout->mlo_layers[i]).mcol_oid)); + assert(rc == 0); + +exit: + mio_mem_free(layer_ids); + return rc; +} + +#else + +/* + * Uggly hacking :). + */ +static int clovis_comp_obj_list_layers_pp(struct mio_op *op) +{ + int i; + int rc = 0; + uint64_t nr_layers = 0; + struct m0_clovis_op *cop; + struct m0_clovis_layout *clayout; + struct mio_comp_obj_layout *mlayout; + struct m0_clovis_composite_layout *comp_layout; + struct m0_clovis_composite_layer *comp_layer; + struct m0_list_link *lnk; + struct m0_tlink *tlnk; + struct clovis_comp_obj_get_layers_args *args; + + cop = (struct m0_clovis_op *) + op->mop_drv_op_chain.mdoc_head->mdo_op; + assert(cop != NULL); + if (cop->op_sm.sm_state != M0_CLOVIS_OS_STABLE) + return -EIO; + + args = (struct clovis_comp_obj_get_layers_args *) + op->mop_drv_op_chain.mdoc_head->mdo_post_proc_data; + mlayout = (struct mio_comp_obj_layout *)args->gla_data; + clayout = (struct m0_clovis_layout *)args->gla_clayout; + comp_layout = container_of(clayout, struct m0_clovis_composite_layout, + ccl_layout); + + nr_layers = comp_layout->ccl_nr_layers; + mlayout->mlo_nr_layers = nr_layers; + mlayout->mlo_layers = + mio_mem_alloc(nr_layers * sizeof(struct mio_comp_obj_layer)); + if (mlayout->mlo_layers == NULL) { + rc = -ENOMEM; + goto exit; + } + + lnk = comp_layout->ccl_layers.t_head.l_head; + for (i = 0; i < nr_layers; i++) { + if (lnk == NULL) + break; + + tlnk = container_of(lnk, struct m0_tlink, t_link); + comp_layer = container_of(tlnk, + struct m0_clovis_composite_layer, + ccr_tlink); + mio__uint128_to_obj_id(&comp_layer->ccr_subobj, + &(mlayout->mlo_layers[i]).mcol_oid); + + lnk = lnk->ll_next; + } + assert(rc == 0); + return MIO_DRV_OP_FINAL; + +exit: + /* + * No need to call m0_clovis_layout_free(clayout) as + * m0_clovis_obj_fini() will release layout data structure + * which is triggerred by mio_obj_close(). + */ + return rc; +} +#endif + +static int +mio_clovis_comp_obj_list_layers(struct mio_obj *obj, + struct mio_comp_obj_layout *ret_layout, + struct mio_op *op) +{ + return clovis_comp_obj_get_layers(obj, ret_layout, + clovis_comp_obj_list_layers_pp, op); +} + +struct clovis_comp_obj_exts_pp_args { + struct m0_clovis_idx *epa_idx; + struct m0_bufvec *epa_keys; + struct m0_bufvec *epa_vals; /* Returned values from Clovis GET op. */ + int *epa_rcs; + int *epa_nr_ret_exts; + struct mio_obj_ext *epa_ret_exts; +}; + +static int +clovis_comp_obj_extent_query(struct mio_obj_id *layer_id, + int nr_exts, struct mio_obj_ext *exts, + int *nr_ret_exts, int opcode, struct mio_op *op, + mio_driver_op_postprocess pp, + struct clovis_comp_obj_exts_pp_args *pp_args) +{ + int i; + int rc = 0; + bool set_vals; + struct m0_bufvec *keys = NULL; + struct m0_bufvec *vals = NULL; + int *rcs = NULL; + struct m0_uint128 layer_id128; + struct m0_clovis_op *cops[1] = {NULL}; + struct m0_clovis_idx *idx; + struct m0_clovis_composite_layer_idx_key key; + struct m0_clovis_composite_layer_idx_val val; + + set_vals = (opcode == M0_CLOVIS_IC_PUT)? true : false; + + idx = mio_mem_alloc(sizeof *idx); + keys = mio__clovis_bufvec_alloc(nr_exts); + M0_ALLOC_ARR(rcs, nr_exts); + if (idx == NULL || keys == NULL || rcs == NULL) { + rc = -ENOMEM; + goto err_exit; + } + if (opcode != M0_CLOVIS_IC_DEL) { + vals = mio__clovis_bufvec_alloc(nr_exts); + if (vals == NULL) { + rc = -ENOMEM; + goto err_exit; + } + } + + mio__obj_id_to_uint128(layer_id, &layer_id128); + for (i = 0; i < nr_exts; i++) { + /* For NEXT op, only set the first key. */ + if (opcode == M0_CLOVIS_IC_NEXT && i >= 1) + break; + + key.cek_layer_id = layer_id128; + key.cek_off = exts[i].moe_off; + rc = m0_clovis_composite_layer_idx_key_to_buf( + &key, &keys->ov_buf[i], &keys->ov_vec.v_count[i]); + if (rc < 0) + break; + + if (set_vals) { + val.cev_len = exts[i].moe_size; + rc = m0_clovis_composite_layer_idx_val_to_buf( + &val, &vals->ov_buf[i], + &vals->ov_vec.v_count[i]); + } + if (rc < 0) + break; + } + if (rc != 0) + goto err_exit; + + mio_memset(idx, 0, sizeof *idx); + m0_clovis_composite_layer_idx(layer_id128, true, idx); + m0_clovis_idx_op(idx, opcode, keys, vals, rcs, 0, &cops[0]); + + assert(pp_args != NULL); + pp_args->epa_idx = idx; + pp_args->epa_keys = keys; + pp_args->epa_vals = vals; + pp_args->epa_rcs = rcs; + pp_args->epa_ret_exts = exts; + pp_args->epa_nr_ret_exts = nr_ret_exts; + rc = mio_driver_op_add(op, pp, pp_args, cops[0]); + if (rc < 0) + goto err_exit; + + m0_clovis_op_launch(cops, 1); + return 0; + +err_exit: + if (cops[0] != NULL) { + m0_clovis_op_fini(cops[0]); + m0_clovis_op_free(cops[0]); + } + m0_bufvec_free(keys); + m0_bufvec_free(vals); + m0_free0(&rcs); + mio_mem_free(idx); + return rc; +} + +static int clovis_comp_obj_exts_release_pp(struct mio_op *op) +{ + struct clovis_comp_obj_exts_pp_args *pp_args; + + pp_args = (struct clovis_comp_obj_exts_pp_args *) + op->mop_drv_op_chain.mdoc_head->mdo_post_proc_data; + mio_mem_free(pp_args->epa_idx); + m0_bufvec_free(pp_args->epa_keys); + m0_bufvec_free(pp_args->epa_vals); + m0_free0(&pp_args->epa_rcs); + mio_mem_free(pp_args); + + return MIO_DRV_OP_FINAL; +} + +static int +mio_clovis_comp_obj_add_extents(struct mio_obj *obj, + struct mio_obj_id *layer_id, + int nr_exts, struct mio_obj_ext *exts, + struct mio_op *op) +{ + int rc; + struct clovis_comp_obj_exts_pp_args *pp_args; + + pp_args = mio_mem_alloc(sizeof *pp_args); + if (pp_args == NULL) + return -ENOMEM; + + rc = clovis_comp_obj_extent_query( + layer_id, nr_exts, exts, NULL, M0_CLOVIS_IC_PUT, op, + clovis_comp_obj_exts_release_pp, pp_args); + if (rc < 0) + mio_mem_free(pp_args); + return rc; +} + +static int +mio_clovis_comp_obj_del_extents(struct mio_obj *obj, + struct mio_obj_id *layer_id, + int nr_exts, struct mio_obj_ext *exts, + struct mio_op *op) +{ + int rc; + struct clovis_comp_obj_exts_pp_args *pp_args; + + pp_args = mio_mem_alloc(sizeof *pp_args); + if (pp_args == NULL) + return -ENOMEM; + + rc = clovis_comp_obj_extent_query( + layer_id, nr_exts, exts, NULL, M0_CLOVIS_IC_DEL, op, + clovis_comp_obj_exts_release_pp, pp_args); + if (rc < 0) + mio_mem_free(pp_args); + return rc; +} + +static int clovis_comp_obj_exts_get_pp(struct mio_op *op) +{ + int i; + int nr_exts; + struct m0_bufvec *keys; + struct m0_bufvec *vals; + struct m0_clovis_op *cop; + struct m0_clovis_composite_layer_idx_key ekey; + struct m0_clovis_composite_layer_idx_val eval; + struct clovis_comp_obj_exts_pp_args *pp_args; + struct mio_obj_ext *ret_exts; + + cop = (struct m0_clovis_op *) + op->mop_drv_op_chain.mdoc_head->mdo_op; + assert(cop != NULL); + if (cop->op_sm.sm_state != M0_CLOVIS_OS_STABLE) + return -EIO; + + /* Copy returned values. */ + pp_args = (struct clovis_comp_obj_exts_pp_args *) + op->mop_drv_op_chain.mdoc_head->mdo_post_proc_data; + ret_exts = pp_args->epa_ret_exts; + assert(ret_exts != NULL); + keys = pp_args->epa_keys; + vals = pp_args->epa_vals; + nr_exts = keys->ov_vec.v_nr; + for (i = 0; i < nr_exts; i++) { + m0_clovis_composite_layer_idx_key_from_buf( + &ekey, keys->ov_buf[i]); + ret_exts[i].moe_off = ekey.cek_off; + if (vals->ov_buf[i] == NULL) + continue; + m0_clovis_composite_layer_idx_val_from_buf( + &eval, vals->ov_buf[i]); + ret_exts[i].moe_size = eval.cev_len; + } + assert(pp_args->epa_nr_ret_exts != NULL); + *pp_args->epa_nr_ret_exts = nr_exts; + + /* Free all allocated resources for the extent query. */ + return clovis_comp_obj_exts_release_pp(op); +} + +static int +mio_clovis_comp_obj_get_extents(struct mio_obj *obj, + struct mio_obj_id *layer_id, + off_t offset, int nr_exts, + struct mio_obj_ext *exts, int *nr_ret_exts, + struct mio_op *op) +{ + int rc; + struct clovis_comp_obj_exts_pp_args *pp_args; + + pp_args = mio_mem_alloc(sizeof *pp_args); + if (pp_args == NULL) + return -ENOMEM; + + mio_memset(exts, 0, nr_exts * sizeof(*exts)); + exts[0].moe_off = offset; + rc = clovis_comp_obj_extent_query( + layer_id, nr_exts, exts, nr_ret_exts, + M0_CLOVIS_IC_NEXT, op, + clovis_comp_obj_exts_get_pp, pp_args); + if (rc < 0) { + mio_mem_free(pp_args); + return rc; + } + + return 0; +} + +struct mio_comp_obj_ops mio_clovis_comp_obj_ops = { + .mcoo_create = mio_clovis_comp_obj_create, + .mcoo_add_layers = mio_clovis_comp_obj_add_layers, + .mcoo_del_layers = mio_clovis_comp_obj_del_layers, + .mcoo_list_layers = mio_clovis_comp_obj_list_layers, + .mcoo_add_extents = mio_clovis_comp_obj_add_extents, + .mcoo_del_extents = mio_clovis_comp_obj_del_extents, + .mcoo_get_extents = mio_clovis_comp_obj_get_extents +}; + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/src/hints.c b/deps/mio/src/hints.c new file mode 100644 index 0000000000000000000000000000000000000000..d3425ca31684256a2bdf6eb6f6e8323c09a319eb --- /dev/null +++ b/deps/mio/src/hints.c @@ -0,0 +1,294 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <errno.h> +#include <assert.h> + +#include "logger.h" +#include "mio.h" +#include "mio_internal.h" + +enum { + MIO_HINT_INVALID = -1 +}; + +struct hint { + char *h_name; + enum mio_hint_type h_type; +}; + +static struct hint hint_table[] = { + [MIO_HINT_OBJ_CACHE_FLUSH_SIZE] = { + .h_name = "MIO_HINT_OBJ_CACHE_FLUSH_SIZE", + .h_type = MIO_HINT_SESSION, + }, + [MIO_HINT_OBJ_LIFETIME] = { + .h_name = "MIO_HINT_OBJ_LIFETIME", + .h_type = MIO_HINT_PERSISTENT, + }, + [MIO_HINT_OBJ_WHERE] = { + .h_name = "MIO_HINT_OBJ_WHERE", + .h_type = MIO_HINT_SESSION, + } +}; + +int mio_hint_map_init(struct mio_hint_map *map, int nr_entries) +{ + int i; + + assert(map != NULL && nr_entries > 0); + map->mhm_nr_entries = nr_entries; + + map->mhm_keys = mio_mem_alloc(nr_entries * sizeof(int)); + map->mhm_values = mio_mem_alloc(nr_entries * sizeof(uint64_t)); + if (map->mhm_keys == NULL || + map->mhm_values == NULL) { + mio_log(MIO_ERROR, "Can't create map !"); + mio_hint_map_fini(map); + return -ENOMEM; + } + + for (i = 0; i < nr_entries; i++) { + map->mhm_keys[i] = MIO_HINT_INVALID; + map->mhm_values[i] = 0; + } + map->mhm_nr_set = 0; + + return 0; +} + +void mio_hint_map_fini(struct mio_hint_map *map) +{ + mio_mem_free(map->mhm_keys); + mio_mem_free(map->mhm_values); + map->mhm_nr_entries = 0; + map->mhm_nr_set = 0; +} + +int mio_hint_map_copy(struct mio_hint_map *to, struct mio_hint_map *from) +{ + int i; + int j; + int rc; + int hkey; + uint64_t hvalue; + int nr_new = 0; + + assert(to != NULL && from != NULL); + + if (to->mhm_nr_entries == 0 ) { + rc = mio_hint_map_init(to, from->mhm_nr_entries); + if (rc < 0) { + mio_log(MIO_ERROR, "Failed to initialise hint map!"); + return rc; + } + } + + /* Check if 'to' hint map has enough space for new hints. */ + for (i = 0; i < from->mhm_nr_set; i++) { + hkey = from->mhm_keys[i]; + for (j = 0; j < to->mhm_nr_set; j++) + if (to->mhm_keys[j] == hkey) + break; + if (j == to->mhm_nr_set) + nr_new++; + } + if (to->mhm_nr_set + nr_new > to->mhm_nr_entries) + return -E2BIG; + + /* It is safe to add new hints now. */ + for (i = 0; i < from->mhm_nr_set; i++) { + hkey = from->mhm_keys[i]; + hvalue = from->mhm_values[i]; + for (j = 0; j < to->mhm_nr_set; j++) + if (to->mhm_keys[j] == hkey) + break; + if (j == to->mhm_nr_set) { + j = to->mhm_nr_set; + to->mhm_nr_set++; + } + + to->mhm_keys[j] = hkey; + to->mhm_values[j] = hvalue; + } + return 0; +} + +int mio_hint_map_set(struct mio_hint_map *map, int key, uint64_t value) +{ + int i; + + for (i = 0; i < map->mhm_nr_set; i++) { + if (map->mhm_keys[i] == key) + break; + } + if (i == map->mhm_nr_set) { + if (map->mhm_nr_set == map->mhm_nr_entries) + return -EINVAL; + else + map->mhm_nr_set++; + } + + map->mhm_keys[i] = key; + map->mhm_values[i] = value; + return 0; +} + +int mio_hint_map_get(struct mio_hint_map *map, int key, uint64_t *value) +{ + int i; + + assert(map != NULL && value != NULL); + + for (i = 0; i < map->mhm_nr_set; i++) { + if (map->mhm_keys[i] == key) + break; + } + if (i == map->mhm_nr_set) + return -ENOENT; + *value = map->mhm_values[i]; + return 0; +} + +#define NKEYS (sizeof(hint_table)/sizeof(struct hint)) +enum mio_hint_type mio_hint_type(enum mio_hint_key key) +{ + assert(key >= 0 && key < NKEYS); + return hint_table[key].h_type; +} + +char* mio_hint_name(enum mio_hint_key key) +{ + assert(key >= 0 && key < NKEYS); + return hint_table[key].h_name; +} + +int mio_hints_init(struct mio_hints *hints) +{ + assert(hints != NULL); + return mio_hint_map_init(&hints->mh_map, MIO_OBJ_HINT_NUM); +} + +void mio_hints_fini(struct mio_hints *hints) +{ + assert(hints != NULL); + mio_hint_map_fini(&hints->mh_map); +} + +#define drv_obj_ops (mio_instance->m_driver->md_obj_ops) +static int mio_obj_hint_store(struct mio_obj *obj) +{ + int i; + int rc; + int nr_hints; + int nr_phints = 0; + int phint_cnt = 0; + struct mio_hints *phints = &obj->mo_attrs.moa_phints; + + nr_hints = obj->mo_hints.mh_map.mhm_nr_set; + + for (i = 0; i < nr_hints; i++) + if (mio_hint_type(obj->mo_hints.mh_map.mhm_keys[i]) == + MIO_HINT_PERSISTENT) + nr_phints++; + + if (phints->mh_map.mhm_nr_entries != 0) + mio_hint_map_fini(&phints->mh_map); + rc = mio_hint_map_init(&phints->mh_map, MIO_OBJ_HINT_NUM); + if (rc < 0) + return rc; + + for (i = 0; i < nr_hints; i++) { + if (mio_hint_type(obj->mo_hints.mh_map.mhm_keys[i]) == + MIO_HINT_PERSISTENT) { + phints->mh_map.mhm_keys[phint_cnt] = + obj->mo_hints.mh_map.mhm_keys[i]; + phints->mh_map.mhm_values[phint_cnt] = + obj->mo_hints.mh_map.mhm_values[i]; + phint_cnt++; + } + } + phints->mh_map.mhm_nr_set = phint_cnt; + + return drv_obj_ops->moo_hint_store(obj); +} + +static int mio_obj_hint_load(struct mio_obj *obj) +{ + return drv_obj_ops->moo_hint_load(obj); +} + +int mio_obj_hints_set(struct mio_obj *obj, struct mio_hints *hints) +{ + int rc; + + assert(obj != NULL && hints != NULL); + + rc = mio_hint_map_copy(&obj->mo_hints.mh_map, &hints->mh_map)? : + mio_obj_hint_store(obj); + if (rc < 0) { + mio_log(MIO_ERROR, + "Copying and store hints failed! error = %d\n", rc); + return rc; + } + + return 0; +} + +int mio_obj_hints_get(struct mio_obj *obj, struct mio_hints *hints) +{ + int rc; + + assert(obj != NULL && hints != NULL); + + rc = mio_obj_hint_load(obj); + if (rc < 0) + return rc; + + rc = mio_hint_map_copy(&hints->mh_map, &obj->mo_hints.mh_map); + return rc; +} + +/** + * Helper functions to set or get individual hint. + */ +int mio_hint_add(struct mio_hints *hints, + int hint_key, uint64_t hint_value) +{ + int rc; + + assert(hints != NULL); + /* Overwrite the hint's value if it has already been set before. */ + rc = mio_hint_map_set(&hints->mh_map, hint_key, hint_value); + return rc; +} + +int mio_hint_lookup(struct mio_hints *hints, + int hint_key, uint64_t *hint_value) +{ + int rc; + + assert(hints != NULL); + rc = mio_hint_map_get(&hints->mh_map, hint_key, hint_value); + return rc; +} + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/src/logger.c b/deps/mio/src/logger.c new file mode 100644 index 0000000000000000000000000000000000000000..b14ce01529c3212341755286d2fbafed9dfaf190 --- /dev/null +++ b/deps/mio/src/logger.c @@ -0,0 +1,76 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <errno.h> +#include <string.h> + +#include "logger.h" +#include "mio_internal.h" + +enum mio_log_level mio_log_level = MIO_INFO; + +struct { + const char *name; +} mio_log_levels[] = { + [MIO_ERROR] = {"error"}, + [MIO_WARN] = {"warning"}, + [MIO_INFO] = {"info"}, + [MIO_TRACE] = {"trace"}, + [MIO_DEBUG] = {"debug"}, +}; + +static FILE *mio_log_file; + +void mio_log(enum mio_log_level lev, const char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + fprintf(mio_log_file, "%s: ", mio_log_levels[lev].name); + vfprintf(mio_log_file, fmt, va); + va_end(va); + +} + +int mio_log_init(enum mio_log_level level, char *logfile) +{ + FILE *fp; + + if (logfile != NULL) { + fp = fopen(logfile, "w"); + if (fp == NULL) { + fprintf(stderr, + "Cann't open log file %s (%d)\n", logfile, errno); + return -errno; + } + } else + fp = stderr; + + mio_log_level = level; + mio_log_file = fp; + return 0; +} + +void mio_log_fini() +{ + fclose(mio_log_file); +} + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/src/logger.h b/deps/mio/src/logger.h new file mode 100644 index 0000000000000000000000000000000000000000..67c7baba7b8d0b957d82d98d95349ed95d0b26e4 --- /dev/null +++ b/deps/mio/src/logger.h @@ -0,0 +1,44 @@ +/* -*- C -*- */ +/* + */ + +#pragma once + +#ifndef __MIO_LOGGER_H__ +#define __MIO_LOGGER_H__ + +#include <stdarg.h> /* va_list */ +#include <stdio.h> /* vfprintf(), stderr */ + +enum mio_log_level { + MIO_LOG_INVALID = -1, + MIO_ERROR = 0, + MIO_WARN = 1, + MIO_INFO = 2, + MIO_TRACE = 3, + MIO_DEBUG = 4, + MIO_MAX_LEVEL, +}; + +int mio_log_init(enum mio_log_level level, char *logfile); +void mio_log(enum mio_log_level lev, const char *fmt, ...) + __attribute__((format(printf, 2, 3))); +//void mio_set_debug_level(enum mio_log_level level); + +#define mio_log_ex(lev, fmt, args...) \ + mio_log(lev, "%s:%d "fmt, __FUNCTION__, __LINE__, ##args) + +#endif /* __MIO_LOGGER_H__ */ + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/src/mio.c b/deps/mio/src/mio.c new file mode 100644 index 0000000000000000000000000000000000000000..63136283968a2cc4bf9d04e1d7719c27726449be --- /dev/null +++ b/deps/mio/src/mio.c @@ -0,0 +1,442 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + + +#include <errno.h> +#include <assert.h> + +#include "logger.h" +#include "mio_internal.h" +#include "mio.h" + +struct mio_kvs mio_obj_attrs_kvs; +struct mio *mio_instance; + +/* --------------------------------------------------------------- * + * Operation * + * ----------------------------------------------------------------*/ + +void mio_op_init(struct mio_op *op) +{ + assert(op != NULL); + + /* + * When mio_op_init() is called, no driver specific operation + * has been created and initialised yet. + */ + mio_memset(op, 0, sizeof *op); + op->mop_op_ops = mio_instance->m_driver->md_op_ops; +} + +void mio_op_fini(struct mio_op *op) +{ + assert(op != NULL && op->mop_op_ops != NULL); + + if (op->mop_op_ops->mopo_fini) + op->mop_op_ops->mopo_fini(op); +} + +struct mio_op* mio_op_alloc_init() +{ + struct mio_op *op; + + op = mio_mem_alloc(sizeof *op); + if (op != NULL) + mio_op_init(op); + return op; +} + +void mio_op_fini_free(struct mio_op *op) +{ + mio_op_fini(op); + mio_mem_free(op); +} + +int mio_op_poll(struct mio_pollop *ops, int nr_ops, uint64_t timeout) +{ + int rc; + int i; + int nr_done = 0; + struct mio_op *mop; + struct mio_pollop *pop; + bool op_done = false; + uint64_t start; + uint64_t end; + mio_driver_op_postprocess post_proc; + + assert(ops != NULL); + start = mio_now(); + +again: + for (i = 0; i < nr_ops; i++) { + pop = ops + i; + mop = pop->mp_op; + assert(mop != NULL); + assert(mop->mop_op_ops != NULL); + op_done = false; + mop->mop_rc = mop->mop_op_ops->mopo_wait( + mop, timeout, &pop->mp_retstate); + + post_proc = mop->mop_drv_op_chain.mdoc_head->mdo_post_proc; + if (pop->mp_retstate == MIO_OP_COMPLETED) { + if (post_proc != NULL) { + rc = post_proc(mop); + /* + * Check to see if a new action has been launched. + * If no more action is launched, it is time to + * finalise the operation. + */ + if (rc == MIO_DRV_OP_NEXT) + pop->mp_retstate = MIO_OP_ONFLY; + else { + assert(rc == MIO_DRV_OP_FINAL); + op_done = true; + } + } else + op_done = true; + } else if (pop->mp_retstate == MIO_OP_FAILED) + op_done = true; + + if (op_done) + nr_done++; + } + + end = mio_now(); + if (timeout == MIO_TIME_NEVER && nr_done != nr_ops) + goto again; + else if (timeout != MIO_TIME_NEVER && end - start < timeout) { + timeout -= end - start; + goto again; + } + + /* Return the number of operations done (completed or failed.)*/ + return nr_done; +} + +void mio_op_callbacks_set(struct mio_op *op, + mio_callback cb_complete, + mio_callback cb_failed, + void *cb_data) +{ + assert(op != NULL); + op->mop_app_cbs.moc_cb_complete = cb_complete; + op->mop_app_cbs.moc_cb_failed = cb_failed; + op->mop_app_cbs.moc_cb_data = cb_data; +} + +/* --------------------------------------------------------------- * + * Object Access * + * ----------------------------------------------------------------*/ +void mio_obj_op_init(struct mio_op *op, struct mio_obj *obj, + enum mio_obj_opcode opcode) +{ + assert(op != NULL); + op->mop_opcode = opcode; + op->mop_who.obj = obj; + op->mop_op_ops = mio_instance->m_driver->md_op_ops; +} + +static void obj_init(struct mio_obj *obj, const struct mio_obj_id *oid) +{ + assert(oid != NULL && obj != NULL); + mio_mem_copy(obj->mo_id.moi_bytes, + (void *)oid->moi_bytes, MIO_OBJ_ID_LEN); + obj->mo_drv_obj_ops = mio_instance->m_driver->md_obj_ops; + /** + * TODO: map to an attributes key-value set by a policy + * such as object ID. + */ + obj->mo_md_kvs = &mio_obj_attrs_kvs; + mio_hint_map_init(&obj->mo_hints.mh_map, MIO_OBJ_HINT_NUM); +} + +int mio_obj_open(const struct mio_obj_id *oid, + struct mio_obj *obj, struct mio_op *op) +{ + assert(oid != NULL && obj != NULL && op != NULL); + obj_init(obj, oid); + mio_obj_op_init(op, obj, MIO_OBJ_OPEN); + return obj->mo_drv_obj_ops->moo_open(obj, op); +} + +void mio_obj_close(struct mio_obj *obj) +{ + assert(obj != NULL); + mio_hint_map_fini(&obj->mo_hints.mh_map); + if (obj->mo_drv_obj_ops->moo_close != NULL) + obj->mo_drv_obj_ops->moo_close(obj); +} + +int mio_obj_create(const struct mio_obj_id *oid, + const struct mio_pool *pool_id, + struct mio_obj *obj, struct mio_op *op) +{ + assert(oid != NULL && obj != NULL && op != NULL); + obj_init(obj, oid); + mio_obj_op_init(op, obj, MIO_OBJ_CREATE); + return obj->mo_drv_obj_ops->moo_create(pool_id, obj, op); +} + +int mio_obj_delete(const struct mio_obj_id *oid, struct mio_op *op) +{ + assert(op != NULL); + mio_obj_op_init(op, NULL, MIO_OBJ_DELETE); + return mio_instance->m_driver->md_obj_ops->moo_delete(oid, op); +} + +int mio_obj_writev(struct mio_obj *obj, + const struct mio_iovec *iov, + int iovcnt, struct mio_op *op) +{ + assert(obj != NULL && op != NULL); + mio_obj_op_init(op, obj, MIO_OBJ_WRITE); + return obj->mo_drv_obj_ops->moo_writev(obj, iov, iovcnt, op); +} + +int mio_obj_readv(struct mio_obj *obj, + const struct mio_iovec *iov, + int iovcnt, struct mio_op *op) +{ + assert(obj != NULL && op != NULL); + mio_obj_op_init(op, obj, MIO_OBJ_READ); + return obj->mo_drv_obj_ops->moo_readv(obj, iov, iovcnt, op); +} + +int mio_obj_sync(struct mio_obj *obj, struct mio_op *op) +{ + assert(obj != NULL && op != NULL); + mio_obj_op_init(op, obj, MIO_OBJ_SYNC); + return obj->mo_drv_obj_ops->moo_sync(obj, op); +} + +int mio_obj_size(struct mio_obj *obj, struct mio_op *op) +{ + assert(obj != NULL && op != NULL); + mio_obj_op_init(op, obj, MIO_OBJ_ATTRS_GET); + return obj->mo_drv_obj_ops->moo_size(obj, op); +} + +/* --------------------------------------------------------------- * + * Key-value Store * + * ----------------------------------------------------------------*/ +static void kvs_op_init(struct mio_op *op, struct mio_kvs_id *kid, + enum mio_kvs_opcode opcode) +{ + assert(op != NULL); + mio_memset(op, 0, sizeof op); + op->mop_opcode = opcode; + op->mop_who.kvs_id = kid; + op->mop_op_ops = mio_instance->m_driver->md_op_ops; +} + +#define drv_kvs_ops (mio_instance->m_driver->md_kvs_ops) +int mio_kvs_pair_get(struct mio_kvs_id *kid, + int nr_kvps, struct mio_kv_pair *kvps, + int32_t *rcs, struct mio_op *op) +{ + assert(kid != NULL && op != NULL); + if (drv_kvs_ops->mko_get == NULL) + return -EOPNOTSUPP; + + kvs_op_init(op, kid, MIO_KVS_GET); + return drv_kvs_ops->mko_get(kid, nr_kvps, kvps, rcs, op); +} + +int mio_kvs_pair_put(struct mio_kvs_id *kid, + int nr_kvps, struct mio_kv_pair *kvps, + int32_t *rcs, struct mio_op *op) +{ + assert(kid != NULL && op != NULL); + if (drv_kvs_ops->mko_put == NULL) + return -EOPNOTSUPP; + + kvs_op_init(op, kid, MIO_KVS_PUT); + return drv_kvs_ops->mko_put(kid, nr_kvps, kvps, rcs, op); +} + +int mio_kvs_pair_del(struct mio_kvs_id *kid, + int nr_kvps, struct mio_kv_pair *kvps, + int32_t *rcs, struct mio_op *op) +{ + assert(kid != NULL && op != NULL); + if (drv_kvs_ops->mko_del == NULL) + return -EOPNOTSUPP; + + kvs_op_init(op, kid, MIO_KVS_DEL); + return drv_kvs_ops->mko_del(kid, nr_kvps, kvps, rcs, op); +} + +int mio_kvs_create_set(struct mio_kvs_id *kid, struct mio_op *op) +{ + assert(kid != NULL && op != NULL); + if (drv_kvs_ops->mko_create_set == NULL) + return -EOPNOTSUPP; + + kvs_op_init(op, kid, MIO_KVS_CREATE_SET); + return drv_kvs_ops->mko_create_set(kid, op); +} + +int mio_kvs_del_set(struct mio_kvs_id *kid, struct mio_op *op) +{ + assert(kid != NULL && op != NULL); + if (drv_kvs_ops->mko_del_set == NULL) + return -EOPNOTSUPP; + + kvs_op_init(op, kid, MIO_KVS_DELETE_SET); + return drv_kvs_ops->mko_del_set(kid, op); +} + +/* --------------------------------------------------------------- * + * Composite Layout * + * ----------------------------------------------------------------*/ +#define drv_comp_obj_ops (mio_instance->m_driver->md_comp_obj_ops) + +int mio_composite_obj_create(const struct mio_obj_id *oid, + struct mio_obj *obj, struct mio_op *op) +{ + assert(obj != NULL && op != NULL); + obj_init(obj, oid); + mio_obj_op_init(op, obj, MIO_COMP_OBJ_CREATE); + return drv_comp_obj_ops->mcoo_create(obj, op); +} + +int mio_composite_obj_del(const struct mio_obj_id *oid, struct mio_op *op) +{ + assert(op != NULL); + mio_obj_op_init(op, NULL, MIO_COMP_OBJ_DELETE); + return drv_comp_obj_ops->mcoo_del(oid, op); +} + +int mio_composite_obj_add_layers(struct mio_obj *obj, int nr_layers, + struct mio_comp_obj_layer *layers, + struct mio_op *op) +{ + assert(obj != NULL && op != NULL); + mio_obj_op_init(op, obj, MIO_COMP_OBJ_ADD_LAYERS); + return drv_comp_obj_ops->mcoo_add_layers(obj, nr_layers, layers, op); +} + +int mio_composite_obj_del_layers(struct mio_obj *obj, + int nr_layers_to_del, + struct mio_comp_obj_layer *layers_to_del, + struct mio_op *op) +{ + assert(obj != NULL && op != NULL); + mio_obj_op_init(op, obj, MIO_COMP_OBJ_DEL_LAYERS); + return drv_comp_obj_ops->mcoo_del_layers( + obj, nr_layers_to_del, layers_to_del, op); +} + +int mio_composite_obj_list_layers(struct mio_obj *obj, + struct mio_comp_obj_layout *ret_layout, + struct mio_op *op) +{ + assert(obj != NULL && op != NULL); + mio_obj_op_init(op, obj, MIO_COMP_OBJ_LIST_LAYERS); + return drv_comp_obj_ops->mcoo_list_layers(obj, ret_layout, op); +} + +int mio_composite_obj_add_extents(struct mio_obj *obj, + struct mio_obj_id *layer_id, + int nr_exts, struct mio_obj_ext *exts, + struct mio_op *op) +{ + assert(obj != NULL && op != NULL); + mio_obj_op_init(op, obj, MIO_COMP_OBJ_ADD_EXTENTS); + return drv_comp_obj_ops->mcoo_add_extents( + obj, layer_id, nr_exts, exts, op); +} + +int mio_composite_obj_del_extents(struct mio_obj *obj, + struct mio_obj_id *layer_id, + int nr_exts, struct mio_obj_ext *exts, + struct mio_op *op) +{ + assert(obj != NULL && op != NULL); + mio_obj_op_init(op, obj, MIO_COMP_OBJ_DEL_EXTENTS); + return drv_comp_obj_ops->mcoo_del_extents( + obj, layer_id, nr_exts, exts, op); +} + +int +mio_composite_obj_get_extents(struct mio_obj *obj, + struct mio_obj_id *layer_id, off_t offset, + int nr_exts, struct mio_obj_ext *exts, + int *nr_ret_exts, struct mio_op *op) +{ + assert(obj != NULL && op != NULL); + mio_obj_op_init(op, obj, MIO_COMP_OBJ_GET_EXTENTS); + return drv_comp_obj_ops->mcoo_get_extents( + obj, layer_id, offset, nr_exts, exts, nr_ret_exts, op); +} + + +/* --------------------------------------------------------------- * + * MIO initialisation/finalisation * + * ----------------------------------------------------------------*/ +int mio_init(const char *yaml_conf) +{ + int rc; + + mio_instance = mio_mem_alloc(sizeof *mio_instance); + if (mio_instance == NULL) + return -ENOMEM; + + mio_drivers_register(); + + rc = mio_conf_init(yaml_conf); + if (rc < 0) { + fprintf(stderr, "Failed in parsing configuration file\n"); + return rc; + } + + rc = mio_log_init(mio_instance->m_log_level, mio_instance->m_log_file); + if (rc < 0) { + fprintf(stderr, "Failed to initialise logging sub-system. \n"); + return rc; + } + + rc = mio_instance->m_driver->md_sys_ops->mdo_init(mio_instance); + if (rc < 0) { + mio_log(MIO_ERROR, "Initialising MIO driver failed!\n"); + mio_conf_fini(); + } + return rc; +} + +void mio_fini() +{ + mio_instance->m_driver->md_sys_ops->mdo_fini(); + mio_mem_free(mio_instance); + mio_conf_fini(); +} + +int mio_thread_init(struct mio_thread *thread) +{ + return mio_instance->m_driver->md_sys_ops->mdo_thread_init(thread); +} + +void mio_thread_fini(struct mio_thread *thread) +{ + mio_instance->m_driver->md_sys_ops->mdo_thread_fini(thread); +} + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/src/mio.h b/deps/mio/src/mio.h new file mode 100644 index 0000000000000000000000000000000000000000..c7d8aaab7dcdb3438ccd849d778781efcca92ced --- /dev/null +++ b/deps/mio/src/mio.h @@ -0,0 +1,648 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#ifndef __MIO_H__ +#define __MIO_H__ + +#include "mio_internal.h" +#include "logger.h" + +typedef void (*mio_callback)(struct mio_op *op); +struct mio_kvs_id; + +/** + * Definitions of MIO operations: + * - Data structure (mio_op) to interact with MIO applications. + * - Operation codes for object and key-value store (kvs). + * - mio_op_state defines operation states. + * - operations on ops such as initialisation and finalisation. + */ +enum mio_obj_opcode { + MIO_OBJ_INVALID, + MIO_OBJ_CREATE, + MIO_OBJ_DELETE, + MIO_OBJ_OPEN, + MIO_OBJ_CLOSE, + MIO_OBJ_SYNC, + MIO_OBJ_ATTRS_SET, + MIO_OBJ_ATTRS_GET, + MIO_OBJ_READ, + MIO_OBJ_WRITE, + MIO_OBJ_OP_NR +}; + +enum mio_kvs_opcode { + MIO_KVS_CREATE_SET = MIO_OBJ_OP_NR + 1, + MIO_KVS_DELETE_SET, + /** Check a kvs for an existence. */ + MIO_KVS_LOOKUP_SET, + /** Lookup a value with the given key. */ + MIO_KVS_GET, + /** Insert or update the value, given a key. */ + MIO_KVS_PUT, + /** Delete the value, if any, for the given key. */ + MIO_KVS_DEL, + MIO_KVS_OP_NR +}; + +enum mio_composite_obj_opcode { + MIO_COMP_OBJ_CREATE = MIO_KVS_OP_NR + 1, + MIO_COMP_OBJ_DELETE, + MIO_COMP_OBJ_ADD_LAYERS, + MIO_COMP_OBJ_DEL_LAYERS, + MIO_COMP_OBJ_LIST_LAYERS, + MIO_COMP_OBJ_ADD_EXTENTS, + MIO_COMP_OBJ_DEL_EXTENTS, + MIO_COMP_OBJ_GET_EXTENTS, + MIO_COMP_OBJ_OP_NR +}; + +enum mio_op_state { + MIO_OP_ONFLY = 0, + MIO_OP_COMPLETED, + MIO_OP_FAILED +}; + +/** + * Callback functions set by applications which are called when + * all actions of an operation are done. + */ +struct mio_op_app_cbs { + mio_callback moc_cb_complete; + mio_callback moc_cb_failed; + void *moc_cb_data; +}; + +struct mio_op { + unsigned int mop_opcode; /* Type of operation. */ + union { /* Which object or key-value set. */ + struct mio_obj *obj; + struct mio_kvs_id *kvs_id; + } mop_who; + int mop_state; /* Current state of operation. */ + int mop_rc; /* == 0 when operation successes, + * < 0 the error code if the + * operation fails. */ + + struct mio_op_app_cbs mop_app_cbs; + + /* See mio_drv_op_chain in mio_inernal for explanation. */ + struct mio_driver_op_chain mop_drv_op_chain; + + struct mio_op_ops *mop_op_ops; +}; +/** + * Initialise and finalise an operation. Applications have to allocate + * memory for the operation before calling mio_op_init(). + */ +void mio_op_init(struct mio_op *op); +void mio_op_fini(struct mio_op *op); +struct mio_op* mio_op_alloc_init(); +void mio_op_fini_free(struct mio_op *op); + +/** + * mio_op_poll() is defined similar to POSIX poll() system call + * and it waits for one of a set of operations to reach COMPLETED + * or FAILED state. + * + * The set of operations to be monitored is specified in the ops + * argument, which is an array of structures of the following form: + * + * struct mio_pollop { + * struct mio_op *mp_op; //Operation to poll. + * int mp_retstate; // Returned state. + * }; + * If none of the operations reach states requested (COMPLETED + * or FAILED) and no error has occurred for any of the operations, + * then mio_op_poll() blocks until one of the states occurs. + * The field retstat is an output parameter, filled by MIO with the + * state that actually occurred. + * + * The timeout argument specifies the number of milliseconds that + * mio_op_poll()should block waiting for an operation to reach state + * requested. The call will block until either: + * - an operation reaches the state requested; + * - the timeout expires. + * + * Specifying a negative value in timeout means an infinite timeout. + * Specifying a timeout of zero causes mio_op_poll() to + * return immediately, even if no operations reach the states + * requested. + * + * @param ops The pointer to an array of data structure mio_pollop, + * containing the operations and states to query on. + * @param nr_ops The number of members in array ops. + * @param timeout. Timeout value in milliseconds. + * @return 0 the operation is completed or failed, < 0 for error. + */ +struct mio_pollop { + struct mio_op *mp_op; /* Operation to poll. */ + int mp_retstate; /* Returned state. */ +}; + +int mio_op_poll(struct mio_pollop *ops, int nr_ops, uint64_t timeout); + +#define MIO_TIME_NEVER (~0ULL) + +/** + * Callbacks provides an alternative way to handle operations + * asynchronously. mio_op_set_callbacks() set callbacks for + * an operation. + * + * @param op The pointer to operation. + * @cb_complete The callback function is triggered when + * the operation reach COMPLETED state. + * @cb_complete The callback function is triggered when + * the operation turns into FAILED state. + * @cb_cb The data passed to callback functions. + */ +void mio_op_callbacks_set(struct mio_op *op, + mio_callback cb_complete, + mio_callback cb_failed, + void *cb_data); + +/** + * Hints set to this opened object. MIO differentiates + * 2 types of hints: (a) session hints which are set only for + * object that are openned and are kept alive only during + * the period of openning session. Session hints will be + * destroyed when an object is closed and the hints won't + * be valid for next session. Example of session hints: cache + * and pre-fetching hints. (b) Persistent hints which are persisted + * and are retrieved and set when an object is openned. The + * persistent hints are valid for the life time of the object. + */ +enum mio_hint_type { + MIO_HINT_SESSION, + MIO_HINT_PERSISTENT +}; + +enum mio_hint_key { + MIO_HINT_OBJ_CACHE_FLUSH_SIZE, + MIO_HINT_OBJ_LIFETIME, + MIO_HINT_OBJ_WHERE, + MIO_HINT_KEY_NUM +}; + +/** + * Hints are stored and managed as a map between hint’s key and value. + */ +struct mio_hints { + struct mio_hint_map mh_map; +}; + +/** + * Object identifier is defined as a byte array with lower-indexed/big-endian + * ordering and the option of Maestro changing to 256 bit later, + * with lower-bits-0 indicating legacy IDs (i.e., the ones at bytes[8..15]). + */ +enum { + MIO_OBJ_ID_LEN = 16, + MIO_KVS_ID_LEN = 16 +}; +struct mio_obj_id { + uint8_t moi_bytes[MIO_OBJ_ID_LEN]; +}; + +struct mio_kvs_id { + uint8_t mki_bytes[MIO_KVS_ID_LEN]; +}; + +struct mio_pool { + uint64_t mp_hi; + uint64_t mp_lo; +}; + +/** + * mio_iovec specifies the base address and length of an area in memory + * from/to which data should be written. It also specifies byte range of + * an object. + */ +struct mio_iovec { + char *miov_base; /* Base address. */ + off_t miov_off; /* Offset. */ + size_t miov_len; /* Length. */ +}; + +enum { + MIO_MAX_HINTS_PER_OBJ = 16, +}; + +/** + * Object attributes stored to and loaded from storage backend. + */ +struct mio_obj_attrs { + uint64_t moa_size; + uint64_t moa_wtime; + + /* Persistent hints only. */ + struct mio_hints moa_phints; +}; + +/** + * In-memory object handler. + */ +struct mio_obj { + struct mio_obj_id mo_id; + struct mio_obj_op *mo_op; + + /** Driver specific object ops. */ + struct mio_obj_ops *mo_drv_obj_ops; + + /** Hints (persistent + session hints) set for this object. */ + struct mio_hints mo_hints; + + /** Associated metadata key-vaule set. */ + struct mio_kvs *mo_md_kvs; + + struct mio_obj_attrs mo_attrs; + + /** Pointer to driver specific object structure. */ + void *mo_drv_obj; +}; + +/** + * Open an object identified by object identifier oid. + * Upon successful completion mio_obj_open() return a ‘obj’ + * pointer. Otherwise, NULL is returned with an error code. + + * @param oid The object identifier. + * @param obj Pointer to the object handle which can be used can be + * subsequently used to access the object until the object is closed. + * Note that the object handle must be pre-allocated by application. + * @param op The open operation for progress query. See Table 5 for + * mio_op data structure definition + * @return 0 for success, < 0 for error. + */ +int mio_obj_open(const struct mio_obj_id *oid, + struct mio_obj *obj, struct mio_op *op); + +/** + * Close an object handle and free resources held by the object. + * @param obj Pointer to the object handle. + */ +void mio_obj_close(struct mio_obj *obj); + +/** + * Create an object with identifier ‘oid’. See mio_obj_open() + * above for notes on object identifier. + * Note that an internal key-value set will be created when + * creating an object, offering a convenient mechanism + * for applications to store and query customized object attributes. + + * + * @param oid The object identifier. + * @param pool_id The pool where the object is stored to. + * @param[out] obj Pointer to the object handle which can be + * used can be subsequently used to access the object until + * the object is closed. Note that the object handle must be + * pre-allocated by application. + * @return 0 for success, < 0 for error. + * + * TODO: hints to create an object such as which pool to store. + * Should MIO expose pools to applications? + */ +int mio_obj_create(const struct mio_obj_id *oid, + const struct mio_pool *pool_id, + struct mio_obj *obj, struct mio_op *op); + +/** + * Delete an object. + * @param oid The object identifier. + * @return 0 for success, < 0 for error. + */ +int mio_obj_delete(const struct mio_obj_id *oid, struct mio_op *op); + +/** + * mio_obj_writev() writes from a set of buffers specified by + * the members of the iov: iov[0], iov[1], ..., iov[iovcnt-1] + * to object offsets specified by the members of the offsets: + * offsets[0], offsets[1], ..., offsets[iovcnt-1]. + * + * mio_obj_readv() reads from object offsets specified by + * the members of the offsets: + * offsets[0], offsets[1], ..., offsets[iovcnt-1] into a set + * of buffers of iov: iov[0], iov[1], ..., iov[iovcnt-1]. + * + * Upon successfully returning, mio_obj_writev() and mio_obj_readv() + * return with a launched operation. op can be used to query + * the process of the operation. + * + * @param obj Pointer to the object handle. + * @param iov The data buffer array. Each member specifies an + * area of memory to write to or read from and an object offset. + * @param iovcnt The number of data buffers. The number of + * offsets and iov must be equal to iovcnt. + * @param op[out]. The returned operation data structure for + * state querying. + * @return 0 for success, < 0 for error. + * + */ +int mio_obj_writev(struct mio_obj *obj, + const struct mio_iovec *iov, + int iovcnt, struct mio_op *op); + +int mio_obj_readv(struct mio_obj *obj, + const struct mio_iovec *iov, + int iovcnt, struct mio_op *op); + +/** + * mio_obj_sync() flushes all previous writes to obj to be + * persisted to the storage device. + * + * @param obj The object is going to be sync'ed. + * @param op[out]. The returned operation data structure for + * state querying. + * @return 0 for success, anything else for an error. + */ +int mio_obj_sync(struct mio_obj *obj, struct mio_op *op); + +/** + * Send a request to retrieve object size. + * + * @param obj The object in question. + * @param op[out]. The returned operation data structure for + * state querying. + * @return 0 for success, anything else for an error. + */ +int mio_obj_size(struct mio_obj *obj, struct mio_op *op); + +/** + * Data structure represents a record stored in a key-value set. + * MIO key-value set accepts variable lengths of keys and values. + */ +struct mio_kv_pair { + void *mkp_key; + size_t mkp_klen; + void *mkp_val; + size_t mkp_vlen; +}; + +struct mio_kvs { + struct mio_kvs_id mk_id; + /** Driver specific key-value set data structure. */ + void *mk_drv_kvs; + struct mio_kvs_ops *mk_ops; +}; + +extern struct mio_kvs mio_obj_attrs_kvs; + +/** + * + * For mio_kvs_pair_get() and mio_kvs_pair_del() arguments should be + * as follows: + * - 'kvps' key-value pairs should set mio_kv_pair::key’s for + * records being requested and set mio_kv_pair::val’s to NULLs. + * At least one key should be specified. + * - After successful operation completion retrieved record + * values are stored in mio_kv_pair::mkp_val. If some value + * retrieval has failed, then corresponding element in 'rcs' array + * is set to a suitable error code. + * + * For mio_kvs_pair_put() arguments should be as follows: + * - 'kvps' key-value pairs should set mio_kv_pair::key’s + * for records being requested and set mio_kv_pair::val’s + * to corresponding values. + * + * Error handling: + * 'rcs' holds an array of per-item return codes for the operation. + * It should be allocated by user with at least `nr_kvps` elements. + * For example, 6 records with keys k0...k5 were requested through + * mio_kvs_get(), k3 being absent in the key-value set. + * After operation completion rcs[3] will be set to –ENOENT + * and rcs[0,1,2,4,5] will be 0. + * + * Per-item return codes are more fine-grained than global operation + * return code (mio_op::mo_rc). On operation completion the global + * return code is set to negative value if it's impossible + * to process any item . + * - If the global return code is 0, then the user should check + * per-item return codes. + * - If the global return code is not 0, then per-item return codes + * are undefined. + * + * @param kvs_id The key-value set identifier. The format of + * key-value set identifier is driver specific and must explicitly + * stated in documentation. + * @param nr_kvps The number of key-value pairs. + * @param rcs. Array for per-item return code. + * @param op[out]. The operation pointer for progress query. + * @return 0 for success, < 0 for error. + */ +int mio_kvs_pair_get(struct mio_kvs_id *kvs_id, + int nr_kvps, struct mio_kv_pair *kvps, + int32_t *rcs, struct mio_op *op); + +int mio_kvs_pair_put(struct mio_kvs_id *kvs_id, + int nr_kvps, struct mio_kv_pair *kvps, + int32_t *rcs, struct mio_op *op); + +int mio_kvs_pair_del(struct mio_kvs_id *kvs_id, + int nr_kvps, struct mio_kv_pair *kvps, + int32_t *rcs, struct mio_op *op); + +/** + * mio_kvs_create_set() creates a key-value set, + * while mio_kvs_del_set() deletes a key-value set. + * + * @param kvs_id The key-value set identifier. + * @return 0 for success, < 0 for error. + */ +int mio_kvs_create_set(struct mio_kvs_id *kvs_id, struct mio_op *op); +int mio_kvs_del_set(struct mio_kvs_id *kvs_id, struct mio_op *op); + +/** + * mio_obj_hints_set() sets new values for the hints of the object + * handler associated with object. + * mio_obj_hints_get() retrieves object’s hints. + * + * As potentially there may be many hints for an object, the argument + * hints allows us to set or get multiple hints in one single call. + * + * @param obj Pointer to the object handle. + * @param hints Hints to set for an object. + * @return 0 for success, < 0 for error. + */ +int mio_obj_hints_set(struct mio_obj *obj, struct mio_hints *hints); +int mio_obj_hints_get(struct mio_obj *obj, struct mio_hints *hints); + +/** + * Helper functions to set or get individual hint. + */ +int mio_hints_init(struct mio_hints *hints); +void mio_hints_fini(struct mio_hints *hints); +int mio_hint_add(struct mio_hints *hints, int hint_key, uint64_t hint_value); +int mio_hint_lookup(struct mio_hints *hints, int hint_key, uint64_t *hint_value); + +enum mio_hint_type mio_hint_type(enum mio_hint_key key); +char* mio_hint_name(enum mio_hint_key key); + +/** + * TODO: short description/definition of composite object. + * + * Data structures and APIs for MIO composite object. + * - object extent is defined as a tuple (offset, size). + * - Composite layer (sub-object). + * - Composite object operations for MIO driver implementation. + * - APIs to create/delete/list layers. + * - APIs to create/delete/list extents. + */ +struct mio_obj_ext { + off_t moe_off; + size_t moe_size; +}; + +struct mio_comp_obj_layer { + int mcol_priority; + struct mio_obj_id mcol_oid; +}; + +struct mio_comp_obj_layout { + int mlo_nr_layers; + struct mio_comp_obj_layer *mlo_layers; +}; + +/** + * mio_composite_obj_create() crates a composite object. If the + * object of identifier `oid` exists this function returns –EEXIST + * error code. + * mio_composite_obj_del() deletes a composite object. + * + * @param oid The object identifier. + * @return 0 for success, anything else for an error + */ +int mio_composite_obj_create(const struct mio_obj_id *oid, + struct mio_obj *obj, struct mio_op *op); +int mio_composite_obj_del(const struct mio_obj_id *oid, struct mio_op *op); + +/** + * mio_composite_obj_add_layer() adds a new layer (sub-object) to a + * composite object. mio_composite_obj_del_layer() deletes a layer + * from the composite object. All extents in the layer will + * be removed as well. + * + * @param obj The object to add to. + * @param layers The layers to be added or deleted. + * @param op The operation will be initialised when returned. + * @return 0 for success, anything else for an error. + */ +int mio_composite_obj_add_layers(struct mio_obj *obj, int nr_layers, + struct mio_comp_obj_layer *layers, + struct mio_op *op); +int mio_composite_obj_del_layers(struct mio_obj *obj, + int nr_layers_to_del, + struct mio_comp_obj_layer *layers_to_del, + struct mio_op *op); + +/** + * List layers from highest priority to lowest one. + * The memory to store layers and priorities are allocated + * inside the function. + * + * @param object The object to add to. + * @param layout[out] The returned composite layout. + * @param op The operation will be initialised when returned. + * @return 0 for success, anything else for an error. + */ +int mio_composite_obj_list_layers(struct mio_obj *obj, + struct mio_comp_obj_layout *ret_layout, + struct mio_op *op); + +/** + * Add/remove extents of the specified layer of a composite object. + * + * @param object The object to add to. + * @param layer The sub-object of the layer. + * @param ext The extent in question. + * @return 0 for success, anything else for an error. + */ +int mio_composite_obj_add_extents(struct mio_obj *obj, + struct mio_obj_id *layer_id, + int nr_exts, struct mio_obj_ext *exts, + struct mio_op *op); +int mio_composite_obj_del_extents(struct mio_obj *obj, + struct mio_obj_id *layer_id, + int nr_exts, struct mio_obj_ext *exts, + struct mio_op *op); +/** + * Query `nr_exts` extents of the specified layer whose offsets are + * larger than `offset`. The number of extents found is returned. + * + * @param object The object to add to. + * @param layer The sub-object of the layer. + * @param offset The returned extents’ offset must be >= this + * argument. + * @param nr_exts. The number of members in the array `exts`. + * @param exts[out] The output array for extents. + * @param nr_ret_exts[out] The returned number of extents from query. + * @return = 0 for success, anything else for an error. + */ +int +mio_composite_obj_get_extents(struct mio_obj *obj, + struct mio_obj_id *layer_id, off_t offset, + int nr_exts, struct mio_obj_ext *exts, + int *nr_ret_exts, struct mio_op *op); + +/** + * The structure 'mio' holds global information of underlying object store + * and key-value set. + */ +struct mio { + enum mio_log_level m_log_level; + char *m_log_file; + + enum mio_driver_id m_driver_id; + struct mio_driver *m_driver; + void *m_driver_confs; +}; +extern struct mio *mio_instance; + +/** + * Initialises Maestro IO interface. + * + * @param yaml_conf cnfiguration file in Yaml format. + * @return 0 for success, anything else for an error. + */ +int mio_init(const char *yaml_conf); + +/** + * Finalises Maestro IO interface. + */ +void mio_fini(); + +/** + * Some object stores such as Mero supports thread-wise functionalities + * (such as ADDB) which requires thread to be initialised in a certain way. + * Call mio_thread_init() at the beginning of a thread and mio_thread_fini() + * at the end of it. + */ +struct mio_thread { + void *mt_drv_thread; +}; + +int mio_thread_init(struct mio_thread *thread); +void mio_thread_fini(struct mio_thread *thread); + +#endif + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/src/mio_driver.c b/deps/mio/src/mio_driver.c new file mode 100644 index 0000000000000000000000000000000000000000..ca286ea66a7e40a425cd80d7bcfa0c1353faeed9 --- /dev/null +++ b/deps/mio/src/mio_driver.c @@ -0,0 +1,114 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <assert.h> +#include <sys/errno.h> + +#include "mio_internal.h" +#include "mio.h" +#include "driver_clovis.h" + +static struct mio_driver mio_drivers[MIO_DRIVER_NUM]; + +/** + * This function must be called in each driver specific operation + * functions for object, key/value and others before launching + * the operations to add driver specific operation into the chain. + */ +int mio_driver_op_add(struct mio_op *op, mio_driver_op_postprocess post_proc, + void *post_proc_data, void *drv_op) +{ + struct mio_driver_op *dop; + + assert(op != NULL); + + dop = (struct mio_driver_op *)mio_mem_alloc(sizeof *dop); + if (dop == NULL) + return -ENOMEM; + + /* + * Set driver op's action function such as post-processing + * for key/value set GET query. See struct mio_driver_op + * for details. + */ + dop->mdo_op = drv_op; + dop->mdo_post_proc = post_proc; + dop->mdo_post_proc_data = post_proc_data; + + /* Insert into the chain. */ + dop->mdo_next = op->mop_drv_op_chain.mdoc_head; + op->mop_drv_op_chain.mdoc_head = dop; + + /* + * Set driver operation's callbacks which will invoke real + * application set callbacks when all job of MIO op is done. + */ + if (op->mop_op_ops != NULL && op->mop_op_ops->mopo_set_cbs && + op->mop_app_cbs.moc_cb_complete != NULL && + op->mop_app_cbs.moc_cb_failed != NULL) { + op->mop_op_ops->mopo_set_cbs(op); + } + + return 0; +} + +void mio_driver_op_invoke_real_cb(struct mio_op *op, int rc) +{ + struct mio_op_app_cbs *app_cbs; + + assert(op != NULL); + + app_cbs = &op->mop_app_cbs; + op->mop_rc = rc; + if (rc == 0) + app_cbs->moc_cb_complete(op); + else + app_cbs->moc_cb_failed(op); +} + +struct mio_driver* mio_driver_get(enum mio_driver_id driver_id) +{ + return mio_drivers + driver_id; +} + +void mio_driver_register(enum mio_driver_id driver_id, + struct mio_driver_sys_ops *sys_ops, + struct mio_op_ops *op_ops, + struct mio_obj_ops *obj_ops, + struct mio_kvs_ops *kvs_ops, + struct mio_comp_obj_ops *comp_obj_ops) +{ + struct mio_driver *drv; + + drv = mio_drivers + driver_id; + drv->md_sys_ops = sys_ops; + drv->md_op_ops = op_ops; + drv->md_obj_ops = obj_ops; + drv->md_kvs_ops = kvs_ops; + drv->md_comp_obj_ops = comp_obj_ops; +} + +void mio_drivers_register() +{ + mio_clovis_driver_register(); +} + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/src/mio_internal.h b/deps/mio/src/mio_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..19730e61f60c5f222133e86ae54fa24e21bd52d1 --- /dev/null +++ b/deps/mio/src/mio_internal.h @@ -0,0 +1,350 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#ifndef __MIO_INTERNAL__ +#define __MIO_INTERNAL__ + +#include <stdint.h> + +#include "clovis/clovis.h" + +struct mio; +struct mio_op; +struct mio_obj_id; +struct mio_kvs_id; +struct mio_pool; +struct mio_obj; +struct mio_iovec; +struct mio_kv_pair; +struct mio_thread; + +enum mio_obj_opcode; +struct mio_obj_ext; +struct mio_comp_obj_layer; +struct mio_comp_obj_layout; + +/** + * MIO defines sets of operations a driver must implemnt: + * - mio_op_ops defines driver specific functions on operation, + * such as initialisation/finalisation and setting callbacks. (mandate) + * - mio_obj_ops defines object access operations (mandate). + * - mio_kvs_ops defines key-value operations (optional). + * - mero-inspired operations, such as composite object related + * operations (optional). + * + * Notes on writing driver specific functions to implement the sets of + * operations mentioned above. + * - mio_driver_op_set() must be called and must be called after the op + * is created and before it being launched. + */ +typedef void (*mio_callback)(struct mio_op *op); +struct mio_op_ops { + int (*mopo_init)(struct mio_op *op); + void (*mopo_fini)(struct mio_op *op); + int (*mopo_wait)(struct mio_op *op, uint64_t timeout, int *retstate); + int (*mopo_set_cbs)(struct mio_op *op); +}; + +struct mio_obj_ops { + int (*moo_open)(struct mio_obj *obj, struct mio_op *op); + int (*moo_close)(struct mio_obj *obj); + int (*moo_create)(const struct mio_pool *pool_id, + struct mio_obj *obj, struct mio_op *op); + int (*moo_delete)(const struct mio_obj_id *oid, struct mio_op *op); + + int (*moo_writev)(struct mio_obj *obj, + const struct mio_iovec *iov, + int iovcnt, struct mio_op *op); + int (*moo_readv)(struct mio_obj *obj, + const struct mio_iovec *iov, + int iovcnt, struct mio_op *op); + int (*moo_sync)(struct mio_obj *obj, struct mio_op *op); + int (*moo_size)(struct mio_obj *obj, struct mio_op *op); + + /** + * Load and store persistent hints. Unlike other operations, + * storing/loading hints are synchronous operations because + * not all hints are persistent hints, if applications use + * only session hints, no IO (to retrieve persistent hints) + * will be launched, thus no 'op' is needed. And as setting + * hints is rare comapred to object accesses, its overhead + * is considered small. + */ + int (*moo_hint_store)(struct mio_obj *obj); + int (*moo_hint_load)(struct mio_obj *obj); +}; + +struct mio_kvs_ops { + int (*mko_get)(struct mio_kvs_id *kvs_id, + int nr_kvps, struct mio_kv_pair *kvps, + int32_t *rcs, struct mio_op *op); + + int (*mko_put)(struct mio_kvs_id *kvs_id, + int nr_kvps, struct mio_kv_pair *kvps, + int32_t *rcs, struct mio_op *op); + + int (*mko_del)(struct mio_kvs_id *kvs_id, + int nr_kvps, struct mio_kv_pair *kvps, + int32_t *rcs, struct mio_op *op); + + int (*mko_create_set)(struct mio_kvs_id *kvs_id, struct mio_op *op); + int (*mko_del_set)(struct mio_kvs_id *kvs_id, struct mio_op *op); +}; + +struct mio_comp_obj_ops { + int (*mcoo_create)(struct mio_obj *obj, struct mio_op *op); + int (*mcoo_del)(const struct mio_obj_id *oid, struct mio_op *op); + + int (*mcoo_add_layers)(struct mio_obj *obj, + int nr_layers, + struct mio_comp_obj_layer *layers, + struct mio_op *op); + int (*mcoo_del_layers)(struct mio_obj *obj, + int nr_layers_to_del, + struct mio_comp_obj_layer *layers_to_del, + struct mio_op *op); + int (*mcoo_list_layers)(struct mio_obj *obj, + struct mio_comp_obj_layout *ret_layout, + struct mio_op *op); + + int (*mcoo_add_extents)(struct mio_obj *obj, + struct mio_obj_id *layer_id, + int nr_exts, struct mio_obj_ext *exts, + struct mio_op *op); + int (*mcoo_del_extents)(struct mio_obj *obj, + struct mio_obj_id *layer_id, + int nr_exts, struct mio_obj_ext *exts, + struct mio_op *op); + + int (*mcoo_get_extents)(struct mio_obj *obj, + struct mio_obj_id *layer_id, off_t offset, + int nr_exts, struct mio_obj_ext *exts, + int *nr_ret_exts, struct mio_op *op); +}; + +/** + * MIO defines a generic driver interface to use different object stores + * as backend. It includes: + * - Types of interface driver. Currently only Mero object store is + * supported. Ceph driver will be implemented in future. + * - Operations to initialise and finalise a driver. + * - Operation set that a driver is to implement. Each driver must + * implement an object store interface and key-value set interface. + * mero-inspired interface is optional. + */ +enum mio_driver_id { + MIO_DRIVER_INVALID = -1, + MIO_MERO, + MIO_DRIVER_NUM +}; + +/** + * Initialisation and finalisation functions for an interface driver. + */ +struct mio_driver_sys_ops { + int (*mdo_init) (struct mio *mio_inst); + void (*mdo_fini) (void); + + int (*mdo_thread_init)(struct mio_thread *thread); + void (*mdo_thread_fini)(struct mio_thread *thread); +}; + +/** + * Each Maestro IO driver is defined by a set of operations. Driver + * initialisaton/finalisation and object and key-value set accessing operations + * must be implemented for a driver, while mero-inspired operations + * are optional. + */ +struct mio_driver { + /** Driver's operations, such as initialisation and finalisation. */ + struct mio_driver_sys_ops *md_sys_ops; + + struct mio_op_ops *md_op_ops; + + /** Object and key-value set operations. */ + struct mio_obj_ops *md_obj_ops; + struct mio_kvs_ops *md_kvs_ops; + + /** Mero-inspired APIs. */ + struct mio_comp_obj_ops *md_comp_obj_ops; +}; + +/** + * mio_driver_op contains a pointer to the driver specific operation and + * a function pointer which is called to do post processing or to create + * and move to next op. In this way, MIO is able to chain and execute a + * number of dependent ops. Examples of mio_driver_op::mdo_func are: + * - Post-processing of GET operation to copy returned values from + * the key-value store. + * - Object WRITE which includes writing data (to data store) and + * updating object attributes (such as size) to metadata store. + * + * Beaware that when chaining multiple driver operations to accomplish + * a task, it is up to the driver to handle any driver operation's + * failure, some driver will roll back to a consistent state if proper + * transcation mechanism is implemented. Current version of clovis driver + * simply reports the error back to application. This will be re-visited + * after DTM is in place. + * + * An implementation of mio_driver_op::mdo_post_process() should follow the + * general rules below: + * - Return value: if it doesn't create a new op, MIO_DRV_OP_FINAL + * is returned, otherwise a new next function is set and + * MIO_DRV_OP_NEXT is returned. + * + * mio_driver_op::mdo_post_process is invoked when: + * - mio_op_poll() checks if post processing action is set for an op + * when mio_op_ops::mopo_wait() returns. If post processing is set + * and called and new driver's op is created, mio_op_poll() will + * keep polling if not yet timed out. + * - if an application has set the callback functions, the callback + * functions must check and call the post processing action if set. + * - So, an application can't poll an op whose callback functions have + * been set to avoid double entries to the post processing action. + */ +enum { + MIO_DRV_OP_NEXT = 0, + MIO_DRV_OP_FINAL, +}; + +typedef int (*mio_driver_op_postprocess)(struct mio_op *op); +struct mio_driver_op { + /** + * The function and data for post-processing. + */ + mio_driver_op_postprocess mdo_post_proc; + void *mdo_post_proc_data; + + /** Pointers to driver specific op. */ + void *mdo_op; + + struct mio_driver_op *mdo_next; +}; + +struct mio_driver_op_chain { + struct mio_driver_op *mdoc_head; +}; + +int mio_driver_op_add(struct mio_op *op, mio_driver_op_postprocess post_proc, + void *post_proc_data, void *drv_op); +void mio_driver_op_invoke_real_cb(struct mio_op *op, int rc); + +struct mio_driver* mio_driver_get(enum mio_driver_id driver_id); + +/** Register a driver. */ +void mio_driver_register(enum mio_driver_id driver_id, + struct mio_driver_sys_ops *drv_ops, + struct mio_op_ops *op_ops, + struct mio_obj_ops *obj_ops, + struct mio_kvs_ops *kvs_ops, + struct mio_comp_obj_ops *comp_obj_ops); + +/** Register all drivers when initialising MIO instance. */ +void mio_drivers_register(); + +void mio_clovis_driver_register(); + +/** + * mio_mero_config contains configuration parameters to setup an + * Mero Clovis instance. + */ +struct mio_mero_config { + /** oostore mode is set when 'is_oostore' is TRUE. */ + bool mc_is_oostore; + /** + * Flag for verify-on-read. Parity is checked when doing + * READ's if this flag is set. + */ + bool mc_is_read_verify; + + /** Local endpoint.*/ + char *mc_clovis_local_addr; + /** HA service's endpoint.*/ + char *mc_ha_addr; + /** Process fid for rmservice@clovis. */ + char *mc_process_fid; + char *mc_profile; + + /** + * The minimum length of the 'tm' receive queue, + * use M0_NET_TM_RECV_QUEUE_DEF_LEN if unsure. + */ + uint32_t mc_tm_recv_queue_min_len; + /** + * The maximum rpc message size, use M0_RPC_DEF_MAX_RPC_MSG_SIZE + * if unsure. + */ + uint32_t mc_max_rpc_msg_size; + + /** + * Default parity group data unit size of an object. As Clovis + * internally uses layout id instead of unit size, the layout id + * will be computed from unit size. + */ + int mc_unit_size; + int mc_default_layout_id; +}; + +/** + * A simple map implementation for hints in which key is of type `int` + * and value is of type `uint64_t`. As there are usually small number + * of hints for each object, arrays are used to store keys and values. + * The overhead of looking up entries in arrays is low. + */ +struct mio_hint_map { + int mhm_nr_entries; + int mhm_nr_set; + int *mhm_keys; + uint64_t *mhm_values; +}; + +enum { + MIO_OBJ_HINT_NUM = 32 +}; +int mio_hint_map_init(struct mio_hint_map *map, int nr_entries); +void mio_hint_map_fini(struct mio_hint_map *map); +int mio_hint_map_copy(struct mio_hint_map *, struct mio_hint_map *from); +int mio_hint_map_set(struct mio_hint_map *map, int key, uint64_t value); +int mio_hint_map_get(struct mio_hint_map *map, int key, uint64_t *value); + +void *mio_mem_alloc(size_t size); +void mio_mem_free(void *p); +void mio_memset(void *p, int c, size_t size); +void mio_mem_copy(void *to, void *from, size_t size); + +uint64_t mio_now(); + +uint64_t mio_byteorder_cpu_to_be64(uint64_t cpu_64bits); +uint64_t mio_byteorder_be64_to_cpu(uint64_t big_endian_64bits); + +int mio_conf_init(const char *config_file); +void mio_conf_fini(); + +void mio_obj_op_init(struct mio_op *op, struct mio_obj *obj, + enum mio_obj_opcode opcode); + +void mio_op_cb_failed(struct mio_op *op); +void mio_op_cb_complete(struct mio_op *op); +#endif + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/src/parser.c b/deps/mio/src/parser.c new file mode 100644 index 0000000000000000000000000000000000000000..c57417466bebfffc60dd81234ea5de21a391802c --- /dev/null +++ b/deps/mio/src/parser.c @@ -0,0 +1,403 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <errno.h> +#include <stdarg.h> +#include <assert.h> +#include <yaml.h> + +#include "clovis/clovis.h" + +#include "logger.h" +#include "mio_internal.h" +#include "mio.h" + +enum { + YAML_MAX_KEY_LEN = 128 +}; + +enum conf_type { + MIO = 0, + MERO, + CEPH, +}; + +enum conf_key { + MIO_CONF_INVALID = -1, + + /* MIO */ + MIO_CONFIG = 0, + MIO_LOG_LEVEL, + MIO_LOG_FILE, + MIO_DRIVER, + + /* Mero driver. "MERO_CONFIG" is the key for Mero section. */ + MERO_CONFIG, + MERO_CLOVIS_INST_ADDR, + MERO_HA_ADDR, + MERO_PROFILE, + MERO_PROCESS_FID, + MERO_IS_OOSTORE, + MERO_IS_READ_VERIFY, + MERO_TM_RECV_QUEUE_MIN_LEN, + MERO_MAX_RPC_MSG_SIZE, + MERO_DEFAULT_UNIT_SIZE, + + /* Other drivers such as Ceph defined here. */ +}; + +struct conf_entry { + char *name; + enum conf_type type; +}; + +/** + * Currently MIO put all configuration entries into one big table defined + * below, which is not too difficult to manage considering MIO only + * support Mero driver and has limited configurations. But this will become + * a problem when more drivers are implemented. A better solution is to + * seperate the big table into driver specific ones and to define driver's + * configuration operations to parse its entries. + * + * TODO: driver specific configuration table and operations. + */ +struct conf_entry conf_table[] = { + /* MIO */ + [MIO_CONFIG] = { + .name = "MIO_CONFIG", + .type = MIO + }, + [MIO_LOG_FILE] = { + .name = "MIO_LOG_FILE", + .type = MIO + }, + [MIO_LOG_LEVEL] = { + .name = "MIO_LOG_LEVEL", + .type = MIO + }, + [MIO_DRIVER] = { + .name = "MIO_DRIVER", + .type = MIO + }, + + /* Mero driver. */ + [MERO_CONFIG] = { + .name = "MERO_CONFIG", + .type = MERO + }, + [MERO_CLOVIS_INST_ADDR] = { + .name = "MERO_CLOVIS_INST_ADDR", + .type = MERO + }, + [MERO_HA_ADDR] = { + .name = "MERO_HA_ADDR", + .type = MERO + }, + [MERO_PROFILE] = { + .name = "MERO_PROFILE", + .type = MERO + }, + [MERO_PROCESS_FID] = { + .name = "MERO_PROCESS_FID", + .type = MERO + }, + [MERO_IS_OOSTORE] = { + .name = "MERO_IS_OOSTORE", + .type = MERO + }, + [MERO_IS_READ_VERIFY] = { + .name = "MERO_IS_READ_VERIFY", + .type = MERO + }, + [MERO_TM_RECV_QUEUE_MIN_LEN] = { + .name = "MERO_TM_RECV_QUEUE_MIN_LEN", + .type = MERO + }, + [MERO_MAX_RPC_MSG_SIZE] = { + .name = "MERO_MAX_RPC_MSG_SIZE", + .type = MERO + }, + [MERO_DEFAULT_UNIT_SIZE] = { + .name = "MERO_DEFAULT_UNIT_SIZE", + .type = MERO + }, +}; + +static enum mio_driver_id mio_inst_drv_id; +static void *mio_driver_confs[MIO_DRIVER_NUM]; +static struct mio_mero_config *mero_conf; + +#define NKEYS (sizeof(conf_table)/sizeof(struct conf_entry)) + +static int conf_token_to_key(char *token, enum conf_key *key) +{ + int rc = 0; + int i; + char *s1; + + for(i = 0; i < NKEYS; i++) { + s1 = strstr(token, conf_table[i].name); + if (s1 != NULL && !strcmp(s1, conf_table[i].name)) { + *key = i; + break; + } + } + if (i == NKEYS) + rc = MIO_CONF_INVALID; + return rc; +} + +static enum mio_driver_id conf_get_driver_id(const char *str) +{ + enum mio_driver_id drv_id = MIO_DRIVER_INVALID; + + assert(str != NULL); + if (!strcmp(str, "MERO")) + drv_id = MIO_MERO; + + return drv_id; +} + +static enum mio_log_level conf_get_log_level(const char *str) +{ + assert(str != NULL); + if (!strcmp(str, "MIO_ERROR")) + return MIO_ERROR; + else if (!strcmp(str, "MIO_WARN")) + return MIO_WARN; + else if (!strcmp(str, "MIO_INFO")) + return MIO_INFO; + else if (!strcmp(str, "MIO_TRACE")) + return MIO_TRACE; + else if (!strcmp(str, "MIO_DEBUG")) + return MIO_DEBUG; + else + return MIO_LOG_INVALID; +} + +static int conf_copy_str(char **to, char *from) +{ + int len = strlen(from) + 1; + + *to = mio_mem_alloc(len); + if (*to == NULL) + return -ENOMEM; + + strncpy(*to, from, len); + return 0; +} + +static int conf_alloc_driver(int key) +{ + int rc = 0; + int type; + + /* Allocate driver's configuration structure if it hasn't been. */ + type = conf_table[key].type; + switch(type) { + case MERO: + if (mero_conf != NULL) + break; + + mero_conf = malloc(sizeof(struct mio_mero_config)); + mio_driver_confs[MIO_MERO] = mero_conf; + if (mero_conf == NULL) + rc = -ENOMEM; + break; + case CEPH: + fprintf(stderr, "Ceph driver is not supported yet!"); + rc = -EINVAL; + break; + default: + break; + } + + return rc; +} + +static void conf_free_drivers() +{ + if (mero_conf) { + mio_mem_free(mero_conf->mc_clovis_local_addr); + mio_mem_free(mero_conf->mc_ha_addr); + mio_mem_free(mero_conf->mc_process_fid); + mio_mem_free(mero_conf->mc_profile); + free(mero_conf); + mio_driver_confs[MIO_MERO] = NULL; + } +} + +static int conf_extract_key(enum conf_key *key, char *token) +{ + int rc; + + rc = conf_token_to_key(token, key); + if (rc < 0) { + fprintf(stderr, "Invalid token name: %s\n", token); + return rc; + } + + rc = conf_alloc_driver(*key); + if (rc < 0) + fprintf(stderr, "Can't allocate memory for driver!"); + + return rc; +} + +static int conf_extract_value(enum conf_key key, char *value) +{ + int rc = 0; + + /* Extract configuration value. */ + switch(key) { + case MIO_DRIVER: + mio_inst_drv_id = conf_get_driver_id(value); + if (mio_inst_drv_id == MIO_DRIVER_INVALID) + rc = -EINVAL; + break; + case MIO_LOG_LEVEL: + assert(mio_instance != NULL); + mio_instance->m_log_level = conf_get_log_level(value); + if (mio_instance->m_log_level == MIO_LOG_INVALID) + rc = -EINVAL; + break; + case MIO_LOG_FILE: + assert(mio_instance != NULL && value != NULL); + rc = conf_copy_str(&mio_instance->m_log_file, value); + break; + case MERO_CLOVIS_INST_ADDR: + rc = conf_copy_str(&mero_conf->mc_clovis_local_addr, value); + break; + case MERO_HA_ADDR: + rc = conf_copy_str(&mero_conf->mc_ha_addr, value); + break; + case MERO_PROFILE: + rc = conf_copy_str(&mero_conf->mc_profile, value); + break; + case MERO_PROCESS_FID: + rc = conf_copy_str(&mero_conf->mc_process_fid, value); + break; + case MERO_TM_RECV_QUEUE_MIN_LEN: + mero_conf->mc_tm_recv_queue_min_len = atoi(value); + break; + case MERO_MAX_RPC_MSG_SIZE: + mero_conf->mc_max_rpc_msg_size = atoi(value); + break; + case MERO_DEFAULT_UNIT_SIZE: + mero_conf->mc_unit_size = atoi(value); + mero_conf->mc_default_layout_id = + m0_clovis_obj_unit_size_to_layout_id(mero_conf->mc_unit_size); + break; + case MERO_IS_OOSTORE: + mero_conf->mc_is_oostore = atoi(value); + break; + case MERO_IS_READ_VERIFY: + mero_conf->mc_is_read_verify = atoi(value); + break; + default: + break; + } + + return rc; +} + +int mio_conf_init(const char *config_file) +{ + int rc; + FILE *fh; + bool is_key = true; + enum conf_key key = MIO_CONF_INVALID; + char *scalar_value; + bool eof; + yaml_parser_t parser; + yaml_token_t token; + + if (!yaml_parser_initialize(&parser)) { + /* MIO logger has not been initialised yet, so use fprintf. */ + fprintf(stderr, "Failed to initialize parser!\n"); + return -1; + } + + fh = fopen(config_file, "r"); + if (fh == NULL) { + fprintf(stderr, "Failed to open file!\n"); + return -1; + } + + /* Scan the yaml file and retrieve configuration values. */ + rc = 0; + eof = false; + yaml_parser_set_input_file(&parser, fh); + + while(!eof) { + yaml_parser_scan(&parser, &token); + + switch (token.type) { + case YAML_KEY_TOKEN: + is_key = true; + break; + case YAML_VALUE_TOKEN: + is_key = false; + break; + case YAML_SCALAR_TOKEN: + scalar_value = (char *)token.data.scalar.value; + if (is_key) + rc = conf_extract_key(&key, scalar_value); + else + rc = conf_extract_value(key, scalar_value); + break; + case YAML_STREAM_END_TOKEN: + eof = true; + break; + default: + break; + } + + yaml_token_delete(&token); + + if (rc < 0) + break; + } + if (rc < 0) { + conf_free_drivers(); + goto exit; + } + + /* Set driver properly. */ + mio_instance->m_driver_id = mio_inst_drv_id; + mio_instance->m_driver = mio_driver_get(mio_inst_drv_id); + mio_instance->m_driver_confs = mio_driver_confs[mio_inst_drv_id]; + +exit: + yaml_parser_delete(&parser); + fclose(fh); + return rc; +} + +void mio_conf_fini() +{ + conf_free_drivers(); +} + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/src/utils.c b/deps/mio/src/utils.c new file mode 100644 index 0000000000000000000000000000000000000000..cb7ab412db601e9a8a333293b7f6d0e24177d677 --- /dev/null +++ b/deps/mio/src/utils.c @@ -0,0 +1,77 @@ +/* -*- C -*- */ +/* + * Copyright: (c) 2020 - 2021 Seagate Technology LLC and/or its its Affiliates, + * All Rights Reserved + * + * This software is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <stdlib.h> +#include <sys/time.h> +#include <asm/byteorder.h> + +#include "mio_internal.h" + +void *mio_mem_alloc(size_t size) +{ + void *p; + + p = malloc(size); + if (p != NULL) + memset(p, 0, size); + + return p; +} + +void mio_mem_free(void *p) +{ + free(p); +} + +void mio_memset(void *p, int c, size_t size) +{ + memset(p, c, size); +} + +void mio_mem_copy(void *to, void *from, size_t size) +{ + memcpy(to, from, size); +} + +enum { + TIME_ONE_SECOND = 1000000000ULL, + TIME_ONE_MSEC = TIME_ONE_SECOND / 1000 +}; + +uint64_t mio_now() +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + return tv.tv_sec * TIME_ONE_SECOND + tv.tv_usec * 1000; +} + +uint64_t mio_byteorder_cpu_to_be64(uint64_t cpu_64bits) +{ + return __cpu_to_be64(cpu_64bits); +} + +uint64_t mio_byteorder_be64_to_cpu(uint64_t big_endian_64bits) +{ + return __be64_to_cpu(big_endian_64bits); +} + +/* + * Local variables: + * c-indentation-style: "K&R" + * c-basic-offset: 8 + * tab-width: 8 + * fill-column: 80 + * scroll-step: 1 + * End: + */ +/* + * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap + */ diff --git a/deps/mio/tests/mio_config.yaml b/deps/mio/tests/mio_config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..362ed73fc229d5f64c04c44d73d88540d7f91121 --- /dev/null +++ b/deps/mio/tests/mio_config.yaml @@ -0,0 +1,18 @@ +# Sample MIO configuration Yaml file. + +#MIO_Config_Sections: [MIO_CONFIG, MERO_CONFIG] +MIO_CONFIG: + MIO_LOG_FILE: + MIO_LOG_LEVEL: MIO_DEBUG + MIO_DRIVER: MERO + +MERO_CONFIG: + MERO_CLOVIS_INST_ADDR: 192.168.0.23@tcp:12345:34:101 + MERO_HA_ADDR: 192.168.0.23@tcp:12345:34:1 + MERO_PROFILE: <0x7000000000000001:0> + MERO_PROCESS_FID: <0x7200000000000000:0> + MERO_DEFAULT_UNIT_SIZE: 1048576 + MERO_IS_OOSTORE: 1 + MERO_IS_READ_VERIFY: 0 + MERO_TM_RECV_QUEUE_MIN_LEN: 2 + MERO_MAX_RPC_MSG_SIZE: 131072