├── .gitignore ├── CMakeLists.txt ├── CONTRIBUTORS.txt ├── CONTRIBUTOR_AGREEMENT.txt ├── COPYING ├── README.md ├── examples ├── CMakeLists.txt ├── README.md ├── listener.c └── node │ ├── CMakeLists.txt │ ├── README.md │ ├── ctx.h │ ├── log.c │ ├── log.h │ ├── main.c │ ├── node.sh │ ├── options.c │ ├── options.h │ ├── socket.c │ ├── socket.h │ ├── sst.c │ ├── sst.h │ ├── stats.c │ ├── stats.h │ ├── store.c │ ├── store.h │ ├── trx.c │ ├── trx.h │ ├── worker.c │ ├── worker.h │ ├── wsrep.c │ └── wsrep.h ├── wsrep.xcf ├── wsrep_allowlist_service.h ├── wsrep_api.h ├── wsrep_config_service.h ├── wsrep_connection_monitor_service.h ├── wsrep_dummy.c ├── wsrep_event_service.h ├── wsrep_gtid.c ├── wsrep_loader.c ├── wsrep_membership_service.h ├── wsrep_node_isolation.h ├── wsrep_thread_service.h ├── wsrep_tls_service.h └── wsrep_uuid.c /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.o 3 | *.a 4 | *.diff 5 | listener 6 | CMakeFiles 7 | CMakeCache.txt 8 | cmake_install.cmake 9 | Makefile 10 | examples/node/node 11 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018, Codership Oy. All rights reserved. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; version 2 of the License. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | 16 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8) 17 | 18 | INCLUDE_DIRECTORIES(".") 19 | 20 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror -Wconversion") 21 | 22 | IF (NOT CMAKE_BUILD_TYPE) 23 | SET(CMAKE_BUILD_TYPE Release) 24 | ENDIF() 25 | 26 | SET(WSREP_SOURCES wsrep_gtid.c wsrep_uuid.c wsrep_loader.c wsrep_dummy.c) 27 | 28 | ADD_LIBRARY(wsrep ${WSREP_SOURCES}) 29 | 30 | ADD_SUBDIRECTORY(examples) 31 | -------------------------------------------------------------------------------- /CONTRIBUTORS.txt: -------------------------------------------------------------------------------- 1 | All contributors are required to add their name and [Github username/email] 2 | to this file in connection with their first contribution. If you are making 3 | a contribution on behalf of a company, you should add the said company name. 4 | 5 | By adding your name and [Github username/email] to this file you agree that 6 | your contribution is a contribution under a contributor agreement between 7 | you and Codership Oy. To the extent that you are an employee of a company and 8 | contribute in that role, you confirm that your contribution is a contribution 9 | under the contribution license agreement between your employer and Codership 10 | Oy; and that you have the authorization to give such confirmation. You confirm 11 | that you have read, understood and signed the contributor license agreement 12 | applicable to you. 13 | 14 | For the individual contributor agreement see file CONTRIBUTOR_AGREEMENT.txt 15 | in the same directory as this file. 16 | 17 | Authors from Codership Oy: 18 | 19 | * Seppo Jaakola , Codership Oy 20 | * Teemu Ollakka , Codership Oy 21 | * Alexey Yurchenko , Codership Oy 22 | * Mario Karuza , Codership Oy 23 | * Daniele Sciascia , Codership Oy 24 | * Jan Lindström , Codership Oy 25 | [Codership employees, add name and email/username above this line, but leave this line intact] 26 | 27 | Other contributors: 28 | 29 | [add name and email/username above this line, but leave this line intact] 30 | -------------------------------------------------------------------------------- /CONTRIBUTOR_AGREEMENT.txt: -------------------------------------------------------------------------------- 1 | Codership 2 | Contributor License Agreement 3 | Codership CLA 4 | 5 | Thank you for your interest in contributing to Galera Cluster, a project 6 | managed by Codership Oy, a legal entity established under Finnish laws, with 7 | its principal address at Pohjolankatu 64 A, 00600 Helsinki Finland ("We", "Us" 8 | or "Our"). 9 | 10 | This contributor agreement ("Agreement") documents the rights granted by 11 | contributors to Us. To make this document effective, please either accept it 12 | in an electronic service such as clahub.com or sign and scan it and send it to 13 | Us by email. This is a legally binding document, so please read it carefully 14 | before agreeing to it. This Agreement covers the Galera Cluster project: the 15 | Galera library, the wsrep-lib library, the wsrep-API library, the Wsrep patch 16 | for MySQL and other eventual patches to MySQL or other technologies. 17 | 18 | 1. Definitions 19 | 20 | "You" means the individual who Submits a Contribution to Us or the Legal 21 | Entity on behalf of whom a Contribution has been Submitted to Us. "Legal 22 | Entity" means an entity which is not a natural person. "Affiliates" means 23 | other Legal Entities that control, are controlled by, or under common control 24 | with that Legal Entity. For the purposes of this definition, "control" means 25 | (i) the power, direct or indirect, to cause the direction or management of 26 | such Legal Entity, whether by contract or otherwise, (ii) ownership of fifty 27 | percent (50%) or more of the outstanding shares or securities which vote to 28 | elect the management or other persons who direct such Legal Entity or (iii) 29 | beneficial ownership of such entity. 30 | 31 | "Contribution" means any work of authorship that is Submitted by You to Us in 32 | which You own or assert ownership of the Copyright. If You do not own the 33 | Copyright in the entire work of authorship, you need to have a separate 34 | permission from Us. 35 | 36 | "Copyright" means all rights protecting works of authorship owned or 37 | controlled by You, including copyright, moral and neighboring rights, as 38 | appropriate, for the full term of their existence including any extensions by 39 | You. 40 | 41 | "Material" means the work of authorship which is made available by Us to third 42 | parties, i.e. the Galera library, the Wsrep patch for MySQL; other eventual 43 | patches to MySQL; other eventual patches to other database technologies; all 44 | these together with a database technology, such as MySQL, or its 45 | derivatives. After You Submit the Contribution, it may be included in the 46 | Material. 47 | 48 | "Submit" means any form of electronic, verbal, or written communication sent 49 | to Us or our representatives, including but not limited to electronic mailing 50 | lists, source code control systems, and issue tracking systems that are 51 | managed by, or on behalf of, Us for the purpose of discussing and improving 52 | the Material, provided that such communication is (i) conspicuously marked or 53 | otherwise designated in writing by You or Your employee as a "Contribution" or 54 | (ii) submitted in source code control system pursuant to Section 3 (e). 55 | 56 | "Submission Date" means the date on which You Submit a Contribution to Us. 57 | 58 | "Effective Date" means the date You execute this Agreement or the date You 59 | first Submit a Contribution to Us, whichever is earlier. 60 | 61 | "Media" means any portion of a Contribution which is not software. 62 | 63 | 2. Grant of Rights 64 | 65 | 2.1 Copyright License 66 | 67 | (a) You retain ownership of the Copyright in Your Contribution and have the 68 | same rights to use or license the Contribution which You would have had 69 | without entering into the Agreement. In case we have in writing permitted 70 | submitting a sublicense to licensed rights, You will not transfer the original 71 | license, but grant us a sublicense in accordance with this Agreement. 72 | 73 | (b) To the maximum extent permitted by the relevant law, You grant to Us a 74 | perpetual, worldwide, non-exclusive, transferable, royalty-free, irrevocable 75 | license under the Copyright covering the Contribution, with the right to 76 | sublicense such rights through multiple tiers of sublicensees, to reproduce, 77 | modify, display, perform and distribute the Contribution as part of the 78 | Material; provided that this license is conditioned upon compliance with 79 | Section 2.3. 80 | 81 | 2.2 Patent License 82 | 83 | For patent claims including, without limitation, method, process, and 84 | apparatus claims which You, or in case You are a Legal Entity, You or Your 85 | Affiliates, own, control or have the right to grant, now or in the future, You 86 | grant to Us a perpetual, worldwide, non-exclusive, transferable, royalty-free, 87 | irrevocable patent license, with the right to sublicense these rights to 88 | multiple tiers of sublicensees, to make, have made, use, sell, offer for sale, 89 | import and otherwise transfer the Contribution and the Contribution in 90 | combination with the Material (and portions of such combination). This license 91 | is granted only to the extent that the exercise of the licensed rights 92 | infringes such patent claims; and provided that this license is conditioned 93 | upon compliance with Section 2.3. 94 | 95 | 2.3 Outbound License 96 | 97 | As a condition on the grant of rights in Sections 2.1 and 2.2, to the extent 98 | we include Your Contribution or a part of it in a Material, we agree to 99 | license the Contribution under the terms of the license or licenses which We 100 | are using on the Submission Date for the Material or any licenses which are 101 | approved by the Open Source Initiative ("OSI") on or after the Effective Date, 102 | including both permissive and copyleft licenses, whether or not such licenses 103 | are subsequently disapproved (including any right to adopt any future version 104 | of a license if approved by the OSI). For clarity, this entitles us to license 105 | Your Contribution also under a permissive open source license, such as the MIT 106 | license, and include binaries created under the MIT license in a proprietary 107 | licensed whole. 108 | 109 | In addition to above defined licenses, We may use the following licenses for 110 | Media in the Contribution: Creative Commons BY 3.0 or Creative Commons BY-SA 111 | 3.0 (including the right to adopt any future version of a license). 112 | 113 | 2.4 Moral Rights. 114 | 115 | If moral rights apply to the Contribution, to the maximum extent permitted by 116 | law, You waive and agree not to assert such moral rights against Us or our 117 | successors in interest, or any of our licensees, either direct or indirect. 118 | 119 | 2.5 Enforcement. 120 | 121 | You, as a copyright holder to Your Contribution, hereby authorize us to 122 | enforce the OSI approved license applied by Us to a Material, but only to the 123 | extent Your Contribution has been included in a Material and always subject to 124 | Our free discretion on whether such enforcement is necessary or not. 125 | 126 | 2.6 Our Rights. 127 | 128 | You acknowledge that We are not obligated to use Your Contribution as part of 129 | the Material and may decide to include any Contribution We consider 130 | appropriate. 131 | 132 | 2.7 Reservation of Rights. 133 | 134 | Any rights not expressly licensed under this section are expressly reserved by 135 | You. 136 | 137 | 3. Agreement 138 | 139 | You confirm that: 140 | 141 | (a) You have the legal authority to enter into this Agreement. 142 | 143 | (b) You or Your Affiliates, own the Copyright and patent claims covering the 144 | Contribution which are required to grant the rights under Section 2. 145 | 146 | (c) The grant of rights under Section 2 does not violate any grant of rights 147 | which You or Your Affiliates have made to third parties, including Your 148 | employer. If You are an employee, You have had Your employer approve this 149 | Agreement or sign the Entity version of this document. If You are less 150 | than eighteen years old, please have Your parents or guardian sign the 151 | Agreement. 152 | 153 | (d) You have not Submitted any Code You do not own without written permission 154 | from US. 155 | 156 | (e) All pull or merge requests issued under usernames confirmed by You in 157 | writing are issued by You; and all such pull or merge requests contain 158 | Your Contributions under this Agreement. You will notify Us in writing in 159 | the event of You no longer control such usernames. 160 | 161 | 4. Disclaimer 162 | 163 | EXCEPT FOR THE EXPRESS WARRANTIES IN SECTION 3, THE CONTRIBUTION IS PROVIDED 164 | "AS IS". MORE PARTICULARLY, ALL EXPRESS OR IMPLIED WARRANTIES INCLUDING, 165 | WITHOUT LIMITATION, ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A 166 | PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE EXPRESSLY DISCLAIMED BY YOU TO 167 | US. TO THE EXTENT THAT ANY SUCH WARRANTIES CANNOT BE DISCLAIMED, SUCH WARRANTY 168 | IS LIMITED IN DURATION TO THE MINIMUM PERIOD PERMITTED BY LAW. 169 | 170 | 5. Consequential Damage Waiver 171 | 172 | TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL YOU BE 173 | LIABLE FOR ANY LOSS OF PROFITS, LOSS OF ANTICIPATED SAVINGS, LOSS OF DATA, 174 | INDIRECT, SPECIAL, INCIDENTAL, CONSEQUENTIAL AND EXEMPLARY DAMAGES ARISING OUT 175 | OF THIS AGREEMENT REGARDLESS OF THE LEGAL OR EQUITABLE THEORY (CONTRACT, TORT 176 | OR OTHERWISE) UPON WHICH THE CLAIM IS BASED. 177 | 178 | THIS WAIVER DOES NOT APPLY TO GROSS NEGLIGENT OR MALICIOUS ACTS OR FRAUD. 179 | 180 | 6. Miscellaneous 181 | 182 | 6.1 This Agreement will be governed by and construed in accordance with the 183 | laws of Finland excluding its conflicts of law provisions. Under certain 184 | circumstances, the governing law in this section might be superseded by the 185 | United Nations Convention on Contracts for the International Sale of Goods 186 | ("UN Convention") and the parties intend to avoid the application of the UN 187 | Convention to this Agreement and, thus, exclude the application of the UN 188 | Convention in its entirety to this Agreement. 189 | 190 | 6.2 Any and all Submissions done by You prior to execution of this Agreement 191 | shall be nonetheless covered by this Agreement. 192 | 193 | 6.3 This Agreement sets out the entire agreement between You and Us for Your 194 | Contributions to Us and overrides all other agreements or understandings. 195 | 196 | 6.4 If You or We assign the rights or obligations received through this 197 | Agreement to a third party, as a condition of the assignment, that third party 198 | must agree in writing to abide by all the rights and obligations in the 199 | Agreement. 200 | 201 | 6.5 The failure of either party to require performance by the other party of 202 | any provision of this Agreement in one situation shall not affect the right of 203 | a party to require such performance at any time in the future. A waiver of 204 | performance under a provision in one situation shall not be considered a 205 | waiver of the performance of the provision in the future or a waiver of the 206 | provision in its entirety. 207 | 208 | 6.6 If any provision of this Agreement is found void and unenforceable, such 209 | provision will be replaced to the extent possible with a provision that comes 210 | closest to the meaning of the original provision and which is enforceable. 211 | The terms and conditions set forth in this Agreement shall apply 212 | notwithstanding any failure of essential purpose of this Agreement or any 213 | limited remedy to the maximum extent possible under law. 214 | 215 | This document has been drafted based on Harmony Inividual Contributor License 216 | Agreement (HA-CLA-I) Version 1.0 July 4, 2011. HA-CLA-I is available from 217 | harmonyagreements.org and is licensed by under Creative Commons Attribution 218 | 3.0 Unported License. 219 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Write Set Replication API specification 2 | 3 | Building: 4 | ``` 5 | cmake [-DCMAKE_BUILD_TYPE=Debug|Release] . && make [VERBOSE=1] 6 | ``` 7 | in top directory. 8 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019, Codership Oy. All rights reserved. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; version 2 of the License. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | 16 | ADD_EXECUTABLE(listener listener.c) 17 | TARGET_LINK_LIBRARIES(listener wsrep dl pthread) 18 | 19 | ADD_SUBDIRECTORY(node) 20 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | ## wsrep API usage examples 2 | 3 | ### 1. Listener 4 | Is a simple program that connects and listens to replication events in 5 | an existing cluster. 6 | 7 | Usage example (starting listener on the same host as the rest of the cluster): 8 | ``` 9 | $ ./listener /path_to/libgalera_smm.so gcomm://localhost:4567?gmcast.listen_addr=tcp://127.0.0.1:9999 cluster_name 10 | ``` 11 | 12 | ### 2. Node 13 | Is a more complex program which implements most of wsrep node functionality 14 | and can form clusters in itself. 15 | -------------------------------------------------------------------------------- /examples/listener.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2012 Codership Oy 2 | 3 | This program is free software; you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation; version 2 of the License. 6 | 7 | This program is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | 12 | You should have received a copy of the GNU General Public License 13 | along with this program; if not, write to the Free Software 14 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | /*! @file Example of wsrep event listener. Outputs description of received 18 | * events to stdout. To get a general picture you should start with 19 | * main() function. */ 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | /*! This is global application context, it will be used by wsrep callbacks */ 31 | struct application_context 32 | {}; 33 | 34 | static struct application_context global_ctx; 35 | 36 | /*! This is receiving thread context, it will be used by wsrep callbacks */ 37 | struct receiver_context 38 | { 39 | char msg[4096]; 40 | }; 41 | 42 | /* wsrep provider handle (global for simplicty) */ 43 | static wsrep_t* wsrep = NULL; 44 | 45 | /*! This is a logger callback which library will be using to log events. */ 46 | static void 47 | logger_cb (wsrep_log_level_t level __attribute__((unused)), const char* msg) 48 | { 49 | fprintf (stderr, "WSREP: %s\n", msg); 50 | } 51 | 52 | /*! This will be called on cluster view change (nodes joining, leaving, etc.). 53 | * Each view change is the point where application may be pronounced out of 54 | * sync with the current cluster view and need state transfer. 55 | * It is guaranteed that no other callbacks are called concurrently with it. */ 56 | static wsrep_cb_status_t 57 | view_cb (void* app_ctx __attribute__((unused)), 58 | void* recv_ctx __attribute__((unused)), 59 | const wsrep_view_info_t* view, 60 | const char* state __attribute__((unused)), 61 | size_t state_len __attribute__((unused))) 62 | { 63 | printf ("New cluster membership view: %d nodes, my index is %d, " 64 | "global seqno: %lld\n", 65 | view->memb_num, view->my_idx, (long long)view->state_id.seqno); 66 | 67 | return WSREP_CB_SUCCESS; 68 | } 69 | 70 | /*! This will be called on cluster view change (nodes joining, leaving, etc.). 71 | * Each view change is the point where application may be pronounced out of 72 | * sync with the current cluster view and need state transfer. 73 | * It is guaranteed that no other callbacks are called concurrently with it. */ 74 | static wsrep_cb_status_t 75 | sst_request_cb (void* app_ctx __attribute__((unused)), 76 | void** sst_req, 77 | size_t* sst_req_len) 78 | { 79 | /* For simplicity we're skipping state transfer by using magic string 80 | * as a state transfer request. 81 | * This node will not be considered JOINED (having full state) 82 | * by other cluster members. */ 83 | *sst_req = strdup(WSREP_STATE_TRANSFER_NONE); 84 | 85 | if (*sst_req) 86 | *sst_req_len = strlen(*sst_req) + 1; 87 | else 88 | *sst_req_len = 0; 89 | 90 | return WSREP_CB_SUCCESS; 91 | } 92 | 93 | /*! This is called to "apply" writeset. 94 | * If writesets don't conflict on keys, it may be called concurrently to 95 | * utilize several CPU cores. */ 96 | static wsrep_cb_status_t 97 | apply_cb (void* recv_ctx, 98 | const wsrep_ws_handle_t* ws_handle __attribute__((unused)), 99 | uint32_t flags __attribute__((unused)), 100 | const wsrep_buf_t* ws __attribute__((unused)), 101 | const wsrep_trx_meta_t* meta, 102 | wsrep_bool_t* exit_loop __attribute__((unused))) 103 | { 104 | struct receiver_context* ctx = (struct receiver_context*)recv_ctx; 105 | 106 | snprintf (ctx->msg, sizeof(ctx->msg), 107 | "Got writeset %lld, size %zu", (long long)meta->gtid.seqno, 108 | ws->len); 109 | 110 | bool const commit = flags & (WSREP_FLAG_TRX_END | WSREP_FLAG_ROLLBACK); 111 | 112 | wsrep->commit_order_enter(wsrep, ws_handle, meta); 113 | if (commit) puts(ctx->msg); 114 | wsrep->commit_order_leave(wsrep, ws_handle, meta, NULL); 115 | 116 | return WSREP_CB_SUCCESS; 117 | } 118 | 119 | /* The following callbacks are stubs and not used in this example. */ 120 | static wsrep_cb_status_t 121 | unordered_cb(void* recv_ctx __attribute__((unused)), 122 | const wsrep_buf_t* data __attribute__((unused))) 123 | { 124 | return WSREP_CB_SUCCESS; 125 | } 126 | 127 | static wsrep_cb_status_t 128 | sst_donate_cb (void* app_ctx __attribute__((unused)), 129 | void* recv_ctx __attribute__((unused)), 130 | const wsrep_buf_t* msg __attribute__((unused)), 131 | const wsrep_gtid_t* state_id __attribute__((unused)), 132 | const wsrep_buf_t* state __attribute__((unused)), 133 | wsrep_bool_t bypass __attribute__((unused))) 134 | { 135 | return WSREP_CB_SUCCESS; 136 | } 137 | 138 | static wsrep_cb_status_t synced_cb (void* app_ctx __attribute__((unused))) 139 | { 140 | return WSREP_CB_SUCCESS; 141 | } 142 | 143 | /* This is the listening thread. It blocks in wsrep::recv() call until 144 | * disconnect from cluster. It will apply and commit writesets through the 145 | * callbacks defined avbove. */ 146 | static void* 147 | recv_thread (void* arg) 148 | { 149 | struct receiver_context* ctx = (struct receiver_context*)arg; 150 | 151 | wsrep_status_t rc = wsrep->recv(wsrep, ctx); 152 | 153 | fprintf (stderr, "Receiver exited with code %d", rc); 154 | 155 | return NULL; 156 | } 157 | 158 | /* This is a signal handler to demonstrate graceful cluster leave. */ 159 | static void 160 | graceful_leave (int signum) 161 | { 162 | printf ("Got signal %d, exiting...\n", signum); 163 | wsrep->disconnect(wsrep); 164 | } 165 | 166 | int main (int const argc, char* argv[]) 167 | { 168 | if (argc < 4 || argc > 5) 169 | { 170 | fprintf (stderr, "Usage: %s " 171 | " [own address]\n", argv[0]); 172 | exit (EXIT_FAILURE); 173 | } 174 | 175 | const char* const wsrep_provider = argv[1]; 176 | const char* const wsrep_uri = argv[2]; 177 | const char* const cluster_name = argv[3]; 178 | const char* const own_address = argc == 5 ? argv[4] : "localhost"; 179 | 180 | /* Now let's load and initialize provider */ 181 | wsrep_status_t rc = wsrep_load (wsrep_provider, &wsrep, logger_cb); 182 | if (WSREP_OK != rc) 183 | { 184 | fprintf (stderr, "Failed to load wsrep provider '%s'\n",wsrep_provider); 185 | exit (EXIT_FAILURE); 186 | } 187 | 188 | wsrep_gtid_t state_id = { WSREP_UUID_UNDEFINED, WSREP_SEQNO_UNDEFINED }; 189 | 190 | /* wsrep provider initialization arguments */ 191 | struct wsrep_init_args wsrep_args = 192 | { 193 | .app_ctx = &global_ctx, 194 | 195 | .node_name = "example listener", 196 | .node_address = own_address, 197 | .node_incoming = "", 198 | .data_dir = ".", // working directory 199 | .options = "", 200 | .proto_ver = 127, // maximum supported application event protocol 201 | 202 | .state_id = &state_id, 203 | .state = NULL, 204 | 205 | .logger_cb = logger_cb, 206 | .view_cb = view_cb, 207 | .sst_request_cb = sst_request_cb, 208 | .encrypt_cb = NULL, 209 | .apply_cb = apply_cb, 210 | .unordered_cb = unordered_cb, 211 | .sst_donate_cb = sst_donate_cb, 212 | .synced_cb = synced_cb 213 | }; 214 | 215 | rc = wsrep->init(wsrep, &wsrep_args); 216 | if (WSREP_OK != rc) 217 | { 218 | fprintf (stderr, "wsrep::init() failed: %d\n", rc); 219 | exit (EXIT_FAILURE); 220 | } 221 | 222 | /* Connect to cluster */ 223 | rc = wsrep->connect(wsrep, cluster_name, wsrep_uri, "", 0); 224 | if (0 != rc) 225 | { 226 | if (rc < 0) 227 | fprintf (stderr, "wsrep::connect(%s, %s) failed: %d (%s)\n", 228 | cluster_name, wsrep_uri, rc, strerror(-(int)rc)); 229 | else 230 | fprintf (stderr, "wsrep::connect() failed: %d\n", rc); 231 | 232 | exit (EXIT_FAILURE); 233 | } 234 | 235 | /* Now let's start several listening threads*/ 236 | int const num_threads = 4; 237 | struct receiver_context thread_ctx[num_threads]; 238 | pthread_t threads[num_threads]; 239 | 240 | int i; 241 | for (i = 0; i < num_threads; i++) 242 | { 243 | int err = pthread_create ( 244 | &threads[i], NULL, recv_thread, &thread_ctx[i]); 245 | 246 | if (err) 247 | { 248 | fprintf (stderr, "Failed to start thread %d: %d (%s)", 249 | i, err, strerror(err)); 250 | exit (EXIT_FAILURE); 251 | } 252 | } 253 | 254 | signal (SIGTERM, graceful_leave); 255 | signal (SIGINT, graceful_leave); 256 | 257 | /* Listening threads are now running and receiving writesets. Wait for them 258 | * to join. Threads will join after signal handler closes wsrep connection*/ 259 | for (i = 0; i < num_threads; i++) 260 | { 261 | pthread_join (threads[i], NULL); 262 | } 263 | 264 | /* Unload provider after nobody uses it any more. */ 265 | wsrep_unload (wsrep); 266 | 267 | return 0; 268 | } 269 | -------------------------------------------------------------------------------- /examples/node/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019, Codership Oy. All rights reserved. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; version 2 of the License. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | 16 | FILE(GLOB SRC 17 | "*.h" 18 | "*.c" 19 | ) 20 | 21 | ADD_EXECUTABLE(node ${SRC}) 22 | 23 | TARGET_LINK_LIBRARIES(node wsrep dl pthread) 24 | 25 | CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/node.sh 26 | ${CMAKE_CURRENT_BINARY_DIR}/node.sh COPYONLY) 27 | -------------------------------------------------------------------------------- /examples/node/README.md: -------------------------------------------------------------------------------- 1 | # wsrep API node application 2 | 3 | ## Overview 4 | 5 | This is a simple application to demonstrate the usage of wsrep API. It 6 | deliberately does nothing useful in order to present as concentrated and 7 | concise API usage as possible. 8 | 9 | The program is deliberately written in C to demonstrate the naked API usage. 10 | For C++ example see a much more advanced integration library at 11 | https://github.com/codership/wsrep-lib 12 | 13 | ## High level architecture 14 | 15 | Process-wise the program consists of an endless main loop that periodically 16 | samples and prints performance stats and a configurable number of "master" and 17 | "slave" threads, with master threads loop executing "transactions" and 18 | replicating resulting "write sets" and slave threads receiving and processing 19 | the write sets from other nodes. 20 | 21 | Object-wise the program is composed of two main objects: `store` and `wsrep`. 22 | 'store' object contains application "state" and generates and commits changes 23 | to the state. `wsrep` object contains cluster context and provides interface 24 | to it. Changes generated by `store` are replicated and certified through 25 | `wsrep` and then committed to `store`. 26 | 27 | ## Unit descriptions (in alphabetical order) 28 | 29 | #### ctx.h 30 | A small header to declare the application context structure. 31 | 32 | #### log.* 33 | Implements logging functionality for the application AND 34 | **a logging callback** for the wsrep provider. 35 | 36 | #### main.c 37 | Defines `main()` routine that initializes storage and wsrep provider, starts 38 | the worker threads and loops in a statistics collection loop. Even though it is 39 | not designed to return it still shows the deinitialization order. 40 | 41 | #### options.* 42 | Implements reading configuration options from the command line, does not have 43 | anything related to wsrep API, but shows which additional parameters must be 44 | configured for the program to make use of wsrep clustering. 45 | 46 | #### socket.* 47 | Network sockets boilerplate code for setting TCP connections between processes 48 | (for SST). Has nothing wsrep-related and can be ignored. 49 | 50 | #### sst.* 51 | Defines **SST callbacks** for the wsrep provider and shows how to asynchronously 52 | implement state snapshot transfer (yes, you don't want to spend eternity in 53 | callbacks). 54 | 55 | #### stats.* 56 | Implements performance stats collecting function for the main loop. While it is 57 | an absolutely optional provider functionality, still it shows how to use that. 58 | 59 | #### store.* 60 | Defines the `store` object that pretends to store and modify some data in a 61 | "transactional" manner. It provides the caller that intends to do a change with 62 | a *change data* and a *key* for replication and certification. 63 | 64 | #### trx.* 65 | Defines routines to process local and replicated transactions. 66 | 67 | #### worker.* 68 | Implements worker thread pool functinality. Worker threads run routines defined 69 | in 'trx.*'. Also implements **apply callback** for the wsrep provider. 70 | 71 | #### wsrep.* 72 | Maintains wsrep cluster context: provider instance and cluster membership view. 73 | While there is little use for the latter in this primitive application, still 74 | it shows **connected and view callbacks** usage. But mostly, for this 75 | application its purpose is to initialize the provider, connect to the cluster 76 | and offer access to initialized provider for other parts of the program. 77 | 78 | ## Example usage 79 | ``` 80 | ./node -f /tmp/galera/0 -v /tmp/galera/0/galera/lib/libgalera_smm.so -o 'pc.weight=2;evs.send_window=2;evs.user_send_window=1;gcache.recover=no' -s 8 -m 16 81 | ``` 82 | -------------------------------------------------------------------------------- /examples/node/ctx.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019, Codership Oy. All rights reserved. 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; version 2 of the License. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program; if not, write to the Free Software 14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | */ 16 | 17 | /** 18 | * @file This unit defines application context for wsrep provider 19 | */ 20 | 21 | #ifndef NODE_CTX_H 22 | #define NODE_CTX_H 23 | 24 | #include "store.h" 25 | #include "wsrep.h" 26 | 27 | struct node_ctx 28 | { 29 | node_wsrep_t* wsrep; 30 | node_store_t* store; 31 | const struct node_options* opts; 32 | }; 33 | 34 | #endif /* NODE_CTX_H */ 35 | -------------------------------------------------------------------------------- /examples/node/log.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019, Codership Oy. All rights reserved. 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; version 2 of the License. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program; if not, write to the Free Software 14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | */ 16 | 17 | #include "log.h" 18 | 19 | #include // fprintf(), fflush() 20 | #include // gettimeofday() 21 | #include // localtime_r() 22 | #include // va_start(), va_end() 23 | 24 | wsrep_log_level_t node_log_max_level = WSREP_LOG_INFO; 25 | 26 | static const char* log_level_str[WSREP_LOG_DEBUG + 2] = 27 | { 28 | "FATAL: ", 29 | "ERROR: ", 30 | " WARN: ", 31 | " INFO: ", 32 | "DEBUG: ", 33 | "XXXXX: " 34 | }; 35 | 36 | static inline void 37 | log_timestamp_and_log(const char* const prefix, // source of msg 38 | int const severity, 39 | const char* const msg) 40 | { 41 | struct tm date; 42 | struct timeval time; 43 | 44 | gettimeofday(&time, NULL); 45 | localtime_r (&time.tv_sec, &date); 46 | 47 | FILE* log_file = stderr; 48 | fprintf(log_file, 49 | "%04d-%02d-%02d %02d:%02d:%02d.%03d " /* timestamp fmt */ 50 | "[%s] %s%s\n", /* [prefix] severity msg */ 51 | date.tm_year + 1900, date.tm_mon + 1, date.tm_mday, 52 | date.tm_hour, date.tm_min, date.tm_sec, 53 | (int)time.tv_usec / 1000, 54 | prefix, log_level_str[severity], msg 55 | ); 56 | 57 | fflush (log_file); 58 | } 59 | 60 | void 61 | node_log_cb(wsrep_log_level_t const severity, const char* const msg) 62 | { 63 | /* REPLICATION: let provider log messages be prefixed with 'wsrep'*/ 64 | log_timestamp_and_log("wsrep", severity, msg); 65 | } 66 | 67 | void 68 | node_log(wsrep_log_level_t const severity, 69 | const char* const file, 70 | const char* const function, 71 | int const line, 72 | ...) 73 | { 74 | va_list ap; 75 | 76 | char string[2048]; 77 | int max_string = sizeof(string); 78 | char* str = string; 79 | 80 | /* provide file:func():line info only if debug logging is on */ 81 | if (NODE_DO_LOG_DEBUG) { 82 | int const len = snprintf(str, (size_t)max_string, "%s:%s():%d: ", 83 | file, function, line); 84 | str += len; 85 | max_string -= len; 86 | } 87 | 88 | va_start(ap, line); 89 | { 90 | const char* format = va_arg (ap, const char*); 91 | 92 | if (max_string > 0 && NULL != format) { 93 | vsnprintf (str, (size_t)max_string, format, ap); 94 | } 95 | } 96 | va_end(ap); 97 | 98 | /* actual logging */ 99 | log_timestamp_and_log(" node", severity, string); 100 | } 101 | -------------------------------------------------------------------------------- /examples/node/log.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019, Codership Oy. All rights reserved. 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; version 2 of the License. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program; if not, write to the Free Software 14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | */ 16 | 17 | /** 18 | * @file This unit defines logging macros for the application and 19 | * a logger callback for the wsrep provider. 20 | */ 21 | 22 | #ifndef NODE_LOG_H 23 | #define NODE_LOG_H 24 | 25 | #include "../../wsrep_api.h" 26 | 27 | /** 28 | * REPLICATION: a logger callback for wsrep provider 29 | */ 30 | extern void 31 | node_log_cb(wsrep_log_level_t severity, const char* message); 32 | 33 | /** 34 | * Applicaton log function intended to be used through the macros defined below. 35 | * For simplicity it uses log levels defined by wsrep API, but it does not have 36 | * to. */ 37 | extern void 38 | node_log (wsrep_log_level_t level, 39 | const char* file, 40 | const char* function, 41 | const int line, 42 | ...); 43 | 44 | /** 45 | * This variable made global to avoid calling node_log() when debug logging 46 | * is disabled. */ 47 | extern wsrep_log_level_t node_log_max_level; 48 | #define NODE_DO_LOG_DEBUG (WSREP_LOG_DEBUG <= node_log_max_level) 49 | 50 | /** 51 | * Base logging macro that records current file, function and line number */ 52 | #define NODE_LOG(level, ...)\ 53 | node_log(level, __FILE__, __func__, __LINE__, __VA_ARGS__, NULL) 54 | 55 | /** 56 | * @name Logging macros. 57 | * Must be implemented as macros to report the location of the code where 58 | * they are called. 59 | */ 60 | /*@{*/ 61 | #define NODE_FATAL(...) NODE_LOG(WSREP_LOG_FATAL, __VA_ARGS__, NULL) 62 | #define NODE_ERROR(...) NODE_LOG(WSREP_LOG_ERROR, __VA_ARGS__, NULL) 63 | #define NODE_WARN(...) NODE_LOG(WSREP_LOG_WARN, __VA_ARGS__, NULL) 64 | #define NODE_INFO(...) NODE_LOG(WSREP_LOG_INFO, __VA_ARGS__, NULL) 65 | #define NODE_DEBUG(...) if (NODE_DO_LOG_DEBUG) \ 66 | { NODE_LOG(WSREP_LOG_DEBUG, __VA_ARGS__, NULL); } 67 | /*@}*/ 68 | 69 | #endif /* NODE_LOG_H */ 70 | -------------------------------------------------------------------------------- /examples/node/main.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019, Codership Oy. All rights reserved. 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; version 2 of the License. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program; if not, write to the Free Software 14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | */ 16 | 17 | #include "ctx.h" 18 | #include "log.h" 19 | #include "options.h" 20 | #include "stats.h" 21 | #include "worker.h" 22 | #include "wsrep.h" 23 | 24 | #include 25 | #include // sigaction() 26 | #include // strerror() 27 | 28 | static void 29 | signal_handler(int const signum) 30 | { 31 | NODE_INFO("Got signal %d. Terminating.", signum); 32 | } 33 | 34 | static void 35 | install_signal_handler(void) 36 | { 37 | sigset_t sa_mask; 38 | sigemptyset(&sa_mask); 39 | 40 | struct sigaction const act = 41 | { 42 | .sa_handler = signal_handler, 43 | .sa_mask = sa_mask, 44 | .sa_flags = (int)SA_RESETHAND 45 | }; 46 | 47 | if (sigaction(SIGINT /* Ctrl-C */, &act, NULL)) 48 | { 49 | NODE_INFO("sigaction() failed: %d (%s)", errno, strerror(errno)); 50 | abort(); 51 | } 52 | } 53 | 54 | int main(int argc, char* argv[]) 55 | { 56 | install_signal_handler(); 57 | 58 | struct node_options opts; 59 | int err = node_options_read(argc, argv, &opts); 60 | if (err) 61 | { 62 | NODE_FATAL("Failed to read command line opritons: %d (%s)", 63 | err, strerror(err)); 64 | return err; 65 | } 66 | 67 | struct node_ctx node; 68 | node.opts = &opts; 69 | 70 | /* REPLICATION: before connecting to cluster we need to initialize our 71 | * storage to know our current position (GTID) */ 72 | node.store = node_store_open(&opts); 73 | if (!node.store) 74 | { 75 | NODE_FATAL("Failed to open node store"); 76 | return 1; 77 | } 78 | 79 | wsrep_gtid_t current_gtid; 80 | node_store_gtid(node.store, ¤t_gtid); 81 | 82 | /* REPLICATION: complete initialization of application context 83 | * (including provider itself) */ 84 | node.wsrep = node_wsrep_init(&opts, ¤t_gtid, &node); 85 | if (!node.wsrep) 86 | { 87 | NODE_FATAL("Failed to initialize wsrep provider"); 88 | return 1; 89 | } 90 | 91 | /* REPLICATION: now we can connect to the cluster and start receiving 92 | * replication events */ 93 | if (node_wsrep_connect(node.wsrep, opts.address, opts.bootstrap) != 94 | WSREP_OK) 95 | { 96 | NODE_FATAL("Failed to connect to primary component"); 97 | return 1; 98 | } 99 | 100 | /* REPLICATION: and start processing replicaiton events */ 101 | struct node_worker_pool* slave_pool = 102 | node_worker_start(&node, NODE_WORKER_SLAVE, (size_t)opts.slaves); 103 | if (!slave_pool) 104 | { 105 | NODE_FATAL("Failed to create slave worker pool"); 106 | return 1; 107 | } 108 | 109 | /* REPLICATION: now that replicaton events are being processed we can 110 | * wait to sync with the cluster */ 111 | if (!node_wsrep_wait_synced(node.wsrep)) 112 | { 113 | NODE_ERROR("Failed to wait fir SYNCED event"); 114 | return 1; 115 | } 116 | 117 | NODE_INFO("Synced with cluster"); 118 | 119 | /* REPLICATION: now we can start replicate own events */ 120 | struct node_worker_pool* master_pool = 121 | node_worker_start(&node, NODE_WORKER_MASTER, (size_t)opts.masters); 122 | if (opts.masters > 0 && !master_pool) 123 | { 124 | NODE_FATAL("Failed to create master worker pool"); 125 | return 1; 126 | } 127 | 128 | node_stats_loop(&node, (int)opts.period); 129 | 130 | /* REPLICATON: to shut down we go in the opposite order: 131 | * first - disconnect from the cluster to signal master threads 132 | * to exit loop, 133 | * second - join master and slave threads, 134 | * third - close provider once not in use */ 135 | node_wsrep_disconnect(node.wsrep); 136 | 137 | node_worker_stop(master_pool); 138 | node_worker_stop(slave_pool); 139 | 140 | node_wsrep_close(node.wsrep); 141 | 142 | /* and finally, when the storage can no longer be disturbed, close it */ 143 | node_store_close(node.store); 144 | 145 | return 0; 146 | } 147 | -------------------------------------------------------------------------------- /examples/node/node.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -eu 2 | 3 | NODE_ID=$1 4 | 5 | NODE_NAME=${NODE_NAME:-$NODE_ID} 6 | 7 | NODE_DIR=${NODE_DIR:-/tmp/node/$NODE_NAME} 8 | rm -rf $NODE_DIR/* 9 | mkdir -p $NODE_DIR 10 | 11 | NODE_OPT=${NODE_OPT:-} 12 | 13 | NODE_HOST=${NODE_HOST:-localhost} 14 | NODE_PORT=${NODE_PORT:-$((10000 + $NODE_ID))} 15 | 16 | NODE_CLIENTS=${NODE_CLIENTS:-1} 17 | NODE_APPLIERS=${NODE_APPLIERS:-1} 18 | 19 | NODE_ADDR=${NODE_ADDR:-} 20 | 21 | NODE_BIN=${NODE_BIN:-$(dirname $0)/node} 22 | 23 | # convert possible relative path to absolute path 24 | NODE_PROVIDER=$(realpath $NODE_PROVIDER) 25 | 26 | set -x 27 | 28 | $NODE_BIN \ 29 | -v "$NODE_PROVIDER" \ 30 | -n "$NODE_NAME" \ 31 | -f "$NODE_DIR" \ 32 | -o "$NODE_OPT" \ 33 | -t "$NODE_HOST" \ 34 | -p $NODE_PORT \ 35 | -s $NODE_APPLIERS \ 36 | -m $NODE_CLIENTS \ 37 | -d 10 \ 38 | -a "$NODE_ADDR" 39 | 40 | set +x 41 | -------------------------------------------------------------------------------- /examples/node/options.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019-2020, Codership Oy. All rights reserved. 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; version 2 of the License. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program; if not, write to the Free Software 14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | */ 16 | 17 | #include "options.h" 18 | 19 | #include // isspace() 20 | #include 21 | #include 22 | #include 23 | #include // strtol() 24 | #include // strcmp() 25 | 26 | /* 27 | * getopt_long() declarations begin 28 | */ 29 | 30 | #define OPTS_NA no_argument 31 | #define OPTS_RA required_argument 32 | #define OPTS_OA optional_argument 33 | 34 | typedef enum opt 35 | { 36 | OPTS_NOOPT = 0, 37 | OPTS_ADDRESS = 'a', 38 | OPTS_BOOTSTRAP = 'b', 39 | OPTS_DELAY = 'd', 40 | OPTS_DATA_DIR = 'f', 41 | OPTS_HELP = 'h', 42 | OPTS_PERIOD = 'i', 43 | OPTS_MASTERS = 'm', 44 | OPTS_NAME = 'n', 45 | OPTS_OPTIONS = 'o', 46 | OPTS_BASE_PORT = 'p', 47 | OPTS_RECORDS = 'r', 48 | OPTS_SLAVES = 's', 49 | OPTS_BASE_HOST = 't', 50 | OPTS_PROVIDER = 'v', 51 | OPTS_WS_SIZE = 'w', 52 | OPTS_OPS = 'x' 53 | } 54 | opt_t; 55 | 56 | static struct option s_opts[] = 57 | { 58 | { "address", OPTS_RA, NULL, OPTS_ADDRESS }, 59 | { "bootstrap", OPTS_NA, NULL, OPTS_BOOTSTRAP }, 60 | { "delay", OPTS_RA, NULL, OPTS_DELAY }, 61 | { "storage", OPTS_RA, NULL, OPTS_DATA_DIR }, 62 | { "help", OPTS_NA, NULL, OPTS_HELP }, 63 | { "period", OPTS_RA, NULL, OPTS_PERIOD }, 64 | { "masters", OPTS_RA, NULL, OPTS_MASTERS }, 65 | { "name", OPTS_RA, NULL, OPTS_NAME }, 66 | { "options", OPTS_RA, NULL, OPTS_OPTIONS, }, 67 | { "base-port", OPTS_RA, NULL, OPTS_BASE_PORT }, 68 | { "records", OPTS_RA, NULL, OPTS_RECORDS }, 69 | { "slaves", OPTS_RA, NULL, OPTS_SLAVES }, 70 | { "base-host", OPTS_RA, NULL, OPTS_BASE_HOST }, 71 | { "provider", OPTS_RA, NULL, OPTS_PROVIDER }, 72 | { "size", OPTS_RA, NULL, OPTS_WS_SIZE }, 73 | { "ops", OPTS_RA, NULL, OPTS_OPS }, 74 | { NULL, 0, NULL, 0 } 75 | }; 76 | 77 | static const char* opts_string = "a:d:f:hi:m:n:o:p:r:s:t:v:w:x:"; 78 | 79 | /* 80 | * getopt_long() declarations end 81 | */ 82 | 83 | static const struct node_options opts_defaults = 84 | { 85 | .provider = "none", 86 | .address = "", 87 | .options = "", 88 | .name = "unnamed", 89 | .data_dir = ".", 90 | .base_host = "localhost", 91 | .masters = 0, 92 | .slaves = 1, 93 | .ws_size = 1024, 94 | .records = 1024*1024, 95 | .delay = 0, 96 | .base_port = 4567, 97 | .period = 10, 98 | .operations= 1, 99 | .bootstrap = true 100 | }; 101 | 102 | static void 103 | opts_print_help(FILE* out, const char* prog_name) 104 | { 105 | fprintf( 106 | out, 107 | "Usage: %s [OPTION...]\n" 108 | "\n" 109 | " -h, --help this thing.\n" 110 | " -v, --provider=PATH a path to wsrep provider library file.\n" 111 | " -a, --address=STRING list of node addresses in the group.\n" 112 | " If not set the node assumes that it is the first\n" 113 | " node in the group (default)\n" 114 | " -o, --options=STRING a string of wsrep provider options.\n" 115 | " -n, --name=STRING human-readable node name.\n" 116 | " -f, --data-dir=PATH a directory to save working data in.\n" 117 | " Should be private to the process.\n" 118 | " -t, --base-host=ADDRESS address of this node at which other members can\n" 119 | " connect to it\n" 120 | " -p, --base-port=NUM base port which the node shall listen for\n" 121 | " connections from other members. This port will be\n" 122 | " used for replication, port+1 for IST and port+2\n" 123 | " for SST. Default: 4567\n" 124 | " -m, --masters=NUM number of concurrent master workers.\n" 125 | " -s, --slaves=NUM number of concurrent slave workers.\n" 126 | " (can't be less than 1)\n" 127 | " -w, --size=NUM desirable size of the resulting writesets\n" 128 | " (approximate lower boundary). Default: 1K\n" 129 | " -r, --records=NUM number of records in the store. Default: 1M\n" 130 | " -x, --ops=NUM number of operations per transaction. Default: 1\n" 131 | " -d, --delay=NUM delay in milliseconds between \"commits\"\n" 132 | " (per master thread).\n" 133 | " -b, --bootstrap bootstrap the cluster with this node.\n" 134 | " Default: 'Yes' if --address is not given, 'No'\n" 135 | " otherwise.\n" 136 | " -i, --period period in seconds between performance stats output\n" 137 | "\n" 138 | , prog_name); 139 | } 140 | 141 | static void 142 | opts_print_config(FILE* out, const struct node_options* opts) 143 | { 144 | fprintf( 145 | out, 146 | "Continuing with the following configuration:\n" 147 | "provider: %s\n" 148 | "address: %s\n" 149 | "options: %s\n" 150 | "name: %s\n" 151 | "data dir: %s\n" 152 | "base addr: %s:%ld\n" 153 | "masters: %ld\n" 154 | "slaves: %ld\n" 155 | "writeset size: %ld bytes\n" 156 | "records: %ld\n" 157 | "operations: %ld\n" 158 | "commit delay: %ld ms\n" 159 | "stats period: %ld s\n" 160 | "bootstrap: %s\n" 161 | , 162 | opts->provider, opts->address, opts->options, opts->name, opts->data_dir, 163 | opts->base_host, opts->base_port, 164 | opts->masters, opts->slaves, opts->ws_size, opts->records, 165 | opts->operations, 166 | opts->delay, opts->period, opts->bootstrap ? "Yes" : "No" 167 | ); 168 | } 169 | 170 | static int 171 | opts_check_conversion(int cond, const char* ptr, int idx) 172 | { 173 | if (!cond || errno || (*ptr != '\0' && !isspace(*ptr))) 174 | { 175 | fprintf(stderr, "Bad value for %s option.\n", s_opts[idx].name); 176 | return EINVAL; 177 | } 178 | return 0; 179 | } 180 | 181 | int 182 | node_options_read(int argc, char* argv[], struct node_options* opts) 183 | { 184 | *opts = opts_defaults; 185 | 186 | int opt = 0; 187 | int opt_idx = 0; 188 | char* endptr; 189 | int ret = 0; 190 | 191 | bool address_given = false; 192 | bool bootstrap_given = false; 193 | 194 | while ((opt = getopt_long(argc, argv, opts_string, s_opts, &opt_idx)) != -1) 195 | { 196 | switch (opt) 197 | { 198 | case OPTS_ADDRESS: 199 | address_given = strcmp(opts->address, optarg); 200 | opts->address = optarg; 201 | break; 202 | case OPTS_BOOTSTRAP: 203 | bootstrap_given = true; 204 | opts->bootstrap = true; 205 | break; 206 | case OPTS_DELAY: 207 | opts->delay = strtol(optarg, &endptr, 10); 208 | if ((ret = opts_check_conversion(opts->delay >= 0, endptr, opt_idx))) 209 | goto err; 210 | break; 211 | case OPTS_DATA_DIR: 212 | opts->data_dir = optarg; 213 | break; 214 | case OPTS_HELP: 215 | ret = 1; 216 | goto help; 217 | case OPTS_PERIOD: 218 | opts->period = strtol(optarg, &endptr, 10); 219 | if ((ret = opts_check_conversion(opts->period > 0, endptr, opt_idx))) 220 | goto err; 221 | break; 222 | case OPTS_MASTERS: 223 | opts->masters = strtol(optarg, &endptr, 10); 224 | if ((ret = opts_check_conversion(opts->masters >= 0, endptr, 225 | opt_idx))) 226 | goto err; 227 | break; 228 | case OPTS_NAME: 229 | opts->name = optarg; 230 | break; 231 | case OPTS_OPTIONS: 232 | opts->options = optarg; 233 | break; 234 | case OPTS_BASE_PORT: 235 | opts->base_port = strtol(optarg, &endptr, 10); 236 | if ((ret = opts_check_conversion( 237 | opts->base_port > 0 && opts->base_port < 65536, 238 | endptr, opt_idx))) 239 | goto err; 240 | break; 241 | case OPTS_RECORDS: 242 | opts->records = strtol(optarg, &endptr, 10); 243 | if ((ret = opts_check_conversion(opts->records >= 0, endptr, 244 | opt_idx))) 245 | goto err; 246 | break; 247 | case OPTS_SLAVES: 248 | opts->slaves = strtol(optarg, &endptr, 10); 249 | if ((ret = opts_check_conversion(opts->slaves > 0, endptr, opt_idx))) 250 | goto err; 251 | break; 252 | case OPTS_BASE_HOST: 253 | opts->base_host = optarg; 254 | break; 255 | case OPTS_PROVIDER: 256 | opts->provider = optarg; 257 | break; 258 | case OPTS_WS_SIZE: 259 | opts->ws_size = strtol(optarg, &endptr, 10); 260 | if ((ret = opts_check_conversion(opts->ws_size > 0, endptr, 261 | opt_idx))) 262 | goto err; 263 | break; 264 | case OPTS_OPS: 265 | opts->operations = strtol(optarg, &endptr, 10); 266 | if ((ret = opts_check_conversion(opts->operations >= 1, endptr, 267 | opt_idx))) 268 | goto err; 269 | break; 270 | default: 271 | ret = EINVAL; 272 | } 273 | } 274 | 275 | help: 276 | if (ret) { 277 | opts_print_help(stderr, argv[0]); 278 | } 279 | else 280 | { 281 | if (!bootstrap_given) 282 | { 283 | opts->bootstrap = !address_given; 284 | } 285 | opts_print_config(stdout, opts); 286 | opts->delay *= 1000; /* convert to microseconds for usleep() */ 287 | } 288 | 289 | err: 290 | return ret; 291 | } 292 | -------------------------------------------------------------------------------- /examples/node/options.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019-2020, Codership Oy. All rights reserved. 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; version 2 of the License. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program; if not, write to the Free Software 14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | */ 16 | 17 | /** 18 | * @file This unit defines options interface 19 | */ 20 | 21 | #ifndef NODE_OPTIONS_H 22 | #define NODE_OPTIONS_H 23 | 24 | #include 25 | 26 | struct node_options 27 | { 28 | const char* provider; // path to wsrep provider 29 | const char* address; // wsrep cluster address string 30 | const char* options; // wsrep option string 31 | const char* name; // node name (for logging purposes) 32 | const char* data_dir; // name of the storage file 33 | const char* base_host;// host own address 34 | long masters; // number of master threads 35 | long slaves; // number of slave threads 36 | long ws_size; // desired writeset size 37 | long records; // total number of records 38 | long delay; // delay between commits 39 | long base_port;// base port to use 40 | long period; // statistics output interval 41 | long operations;// number of "statements" in a "transaction" 42 | bool bootstrap;// bootstrap the cluster with this node 43 | }; 44 | 45 | extern int 46 | node_options_read(int argc, char* argv[], struct node_options* opts); 47 | 48 | #endif /* NODE_OPTIONS_H */ 49 | -------------------------------------------------------------------------------- /examples/node/socket.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019, Codership Oy. All rights reserved. 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; version 2 of the License. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program; if not, write to the Free Software 14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | */ 16 | 17 | #include "socket.h" 18 | 19 | #include "log.h" 20 | 21 | #include 22 | #include // isspace() 23 | #include 24 | #include // USHRT_MAX 25 | #include // struct addrinfo 26 | #include // snprintf() 27 | #include // strerror() 28 | #include // bind(), connect(), accept(), send(), recv() 29 | 30 | struct node_socket 31 | { 32 | int fd; 33 | }; 34 | 35 | /** 36 | * Initializes addrinfo from the separate host address and port arguments 37 | * 38 | * Requires calling freeaddrinfo() later 39 | * 40 | * @param[in] host - if NULL, will be initialized for listening 41 | * @param[in] port 42 | * 43 | * @return struct addrinfo* or NULL in case of error 44 | */ 45 | static struct addrinfo* 46 | socket_get_addrinfo2(const char* const host, 47 | uint16_t const port) 48 | { 49 | struct addrinfo const hints = 50 | { 51 | .ai_flags = AI_PASSIVE | /** will be ignored if host is not NULL */ 52 | AI_NUMERICSERV, /** service is a numeric port */ 53 | .ai_family = AF_UNSPEC, /** either IPv4 or IPv6 */ 54 | .ai_socktype = SOCK_STREAM, /** STREAM or DGRAM */ 55 | .ai_protocol = 0, 56 | .ai_addrlen = 0, 57 | .ai_addr = NULL, 58 | .ai_canonname = NULL, 59 | .ai_next = NULL 60 | }; 61 | 62 | char service[6]; 63 | snprintf(service, sizeof(service), "%hu", port); 64 | 65 | struct addrinfo* info; 66 | int err = getaddrinfo(host, service, &hints, &info); 67 | if (err) 68 | { 69 | NODE_ERROR("Failed to resolve '%s': %d (%s)", 70 | host, err, gai_strerror(err)); 71 | return NULL; 72 | } 73 | 74 | return info; 75 | } 76 | 77 | /** 78 | * Initializes addrinfo from single address and port string 79 | * The port is expected to be in numerical form and appended to the host address 80 | * via colon. 81 | * 82 | * Requires calling freeaddrinfo() later 83 | * 84 | * @param[in] addr full address specification, including port 85 | * 86 | * @return struct addrinfo* or NULL in case of error 87 | */ 88 | static struct addrinfo* 89 | socket_get_addrinfo1(const char* const addr) 90 | { 91 | int const addr_len = (int)strlen(addr); 92 | char* const addr_buf = strdup(addr); 93 | if (!addr_buf) 94 | { 95 | NODE_ERROR("strdup(%s) failed: %d (%s)", addr, errno, strerror(errno)); 96 | return NULL; 97 | } 98 | 99 | struct addrinfo* res = NULL; 100 | long port; 101 | char* endptr; 102 | 103 | int i; 104 | for (i = addr_len - 1; i >= 0; i--) 105 | { 106 | if (addr_buf[i] == ':') break; 107 | } 108 | 109 | if (addr_buf[i] != ':') 110 | { 111 | NODE_ERROR("Malformed address:port string: '%s'", addr); 112 | goto end; 113 | } 114 | 115 | addr_buf[i] = '\0'; 116 | port = strtol(addr_buf + i + 1, &endptr, 10); 117 | 118 | if (port <= 0 || port > USHRT_MAX || errno || 119 | (*endptr != '\0' && !isspace(*endptr))) 120 | { 121 | NODE_ERROR("Malformed/invalid port: '%s'. Errno: %d (%s)", 122 | addr_buf + i + 1, errno, strerror(errno)); 123 | goto end; 124 | } 125 | 126 | res = socket_get_addrinfo2(strlen(addr_buf) > 0 ? addr_buf : NULL, 127 | (uint16_t)port); 128 | end: 129 | free(addr_buf); 130 | return res; 131 | } 132 | 133 | static struct node_socket* 134 | socket_create(int const fd) 135 | { 136 | assert(fd > 0); 137 | 138 | struct node_socket* res = calloc(1, sizeof(struct node_socket)); 139 | if (res) 140 | { 141 | res->fd = fd; 142 | } 143 | else 144 | { 145 | NODE_ERROR("Failed to allocate struct node_socket: %d (%s)", 146 | errno, strerror(errno)); 147 | close(fd); 148 | } 149 | 150 | return res; 151 | } 152 | 153 | /** 154 | * Definition of function type with the signature of bind() and connect() 155 | */ 156 | typedef int (*socket_act_fun_t) (int sfd, 157 | const struct sockaddr* addr, 158 | socklen_t addrlen); 159 | 160 | static int 161 | socket_bind_and_listen(int const sfd, 162 | const struct sockaddr* const addr, 163 | socklen_t const addrlen) 164 | { 165 | int ret = bind(sfd, addr, addrlen); 166 | 167 | if (!ret) 168 | ret = listen(sfd, SOMAXCONN); 169 | 170 | return ret; 171 | } 172 | 173 | /** 174 | * A "template" method to do the "right thing" with the addrinfo and create a 175 | * socket from it. The "right thing" would normally be bind and listen for 176 | * a server socket OR connect for a client socket. 177 | * 178 | * @param[in] info addrinfo list, swallowed and deallocated 179 | * @param[in] action_fun the "right thing" to do on socket and struct sockaddr 180 | * @param[in] action_str action description to be printed in the error message 181 | * @param[in] orig_host host address to be pronted in the error message 182 | * @param[in] orig_port port to be printed in the error message, if orig_host 183 | * string contains the port, this parameter should be 0 184 | * 185 | * The last three parameters are for diagnostic puposes only. orig_host and 186 | * orig_port are supposed to be what were used to obtain addrinfo. 187 | * 188 | * @return new struct node_socket. 189 | */ 190 | static struct node_socket* 191 | socket_from_addrinfo(struct addrinfo* const info, 192 | socket_act_fun_t const action_fun, 193 | const char* const action_str, 194 | const char* const orig_host, 195 | uint16_t const orig_port) 196 | { 197 | int sfd; 198 | int err = 0; 199 | 200 | /* Iterate over addrinfo list and try to apply action_fun on the resulting 201 | * socket. Once successful, break loop. */ 202 | struct addrinfo* addr; 203 | for (addr = info; addr != NULL; addr = addr->ai_next) 204 | { 205 | sfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); 206 | if (sfd == -1) 207 | { 208 | err = errno; 209 | continue; 210 | } 211 | 212 | if (action_fun(sfd, addr->ai_addr, addr->ai_addrlen) == 0) break; 213 | 214 | err = errno; 215 | close(sfd); 216 | } 217 | 218 | freeaddrinfo(info); /* no longer needed */ 219 | 220 | if (!addr) 221 | { 222 | NODE_ERROR("Failed to %s to '%s%s%.0hu': %d (%s)", 223 | action_str, 224 | orig_host ? orig_host : "", orig_port > 0 ? ":" : "", 225 | orig_port > 0 ? orig_port : 0, /* won't be printed if 0 */ 226 | err, strerror(err)); 227 | return NULL; 228 | } 229 | 230 | assert(sfd > 0); 231 | return socket_create(sfd); 232 | } 233 | 234 | struct node_socket* 235 | node_socket_listen(const char* const host, uint16_t const port) 236 | { 237 | struct addrinfo* const info = socket_get_addrinfo2(host, port); 238 | if (!info) return NULL; 239 | 240 | return socket_from_addrinfo(info, socket_bind_and_listen, 241 | "bind a listening socket", host, port); 242 | } 243 | 244 | struct node_socket* 245 | node_socket_connect(const char* const addr_str) 246 | { 247 | struct addrinfo* const info = socket_get_addrinfo1(addr_str); 248 | if (!info) return NULL; 249 | 250 | return socket_from_addrinfo(info, connect, "connect", addr_str, 0); 251 | } 252 | 253 | struct node_socket* 254 | node_socket_accept(struct node_socket* socket) 255 | { 256 | int sfd = accept(socket->fd, NULL, NULL); 257 | 258 | if (sfd < 0) 259 | { 260 | NODE_ERROR("Failed to accept connection: %d (%s)", 261 | errno, strerror(errno)); 262 | return NULL; 263 | } 264 | 265 | return socket_create(sfd); 266 | } 267 | 268 | int 269 | node_socket_send_bytes(node_socket_t* socket, const void* buf, size_t len) 270 | { 271 | ssize_t const ret = send(socket->fd, buf, len, MSG_NOSIGNAL); 272 | 273 | if (ret != (ssize_t)len) 274 | { 275 | NODE_ERROR("Failed to send %zu bytes: %d (%s)", errno, strerror(errno)); 276 | return -1; 277 | } 278 | 279 | return 0; 280 | } 281 | 282 | int 283 | node_socket_recv_bytes(node_socket_t* socket, void* buf, size_t len) 284 | { 285 | ssize_t const ret = recv(socket->fd, buf, len, MSG_WAITALL); 286 | 287 | if (ret != (ssize_t)len) 288 | { 289 | NODE_ERROR("Failed to recv %zu bytes: %d (%s)", errno, strerror(errno)); 290 | return -1; 291 | } 292 | 293 | return 0; 294 | } 295 | 296 | void 297 | node_socket_close(node_socket_t* socket) 298 | { 299 | if (!socket) return; 300 | 301 | if (socket->fd > 0) close(socket->fd); 302 | 303 | free(socket); 304 | } 305 | -------------------------------------------------------------------------------- /examples/node/socket.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019, Codership Oy. All rights reserved. 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; version 2 of the License. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program; if not, write to the Free Software 14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | */ 16 | 17 | /** 18 | * @file This unit implements auxiliary networking functions (for SST purposes) 19 | * It has nothing wsrep related and is not of general purpose. 20 | */ 21 | 22 | #ifndef NODE_SOCKET_H 23 | #define NODE_SOCKET_H 24 | 25 | #include // size_t 26 | #include // uint16_t 27 | 28 | typedef struct node_socket node_socket_t; 29 | 30 | /** 31 | * Open listening socket at a given address 32 | * 33 | * @return listening socket 34 | */ 35 | extern node_socket_t* 36 | node_socket_listen(const char* host, uint16_t port); 37 | 38 | /** 39 | * Connect to a given address. 40 | * 41 | * @return connected socket 42 | */ 43 | extern node_socket_t* 44 | node_socket_connect(const char* addr); 45 | 46 | /** 47 | * Wait for connection on a listening socket 48 | * @return connected socket 49 | */ 50 | extern node_socket_t* 51 | node_socket_accept(node_socket_t* s); 52 | 53 | /** 54 | * Send a given number of bytes 55 | * @return 0 or a negative error code 56 | */ 57 | extern int 58 | node_socket_send_bytes(node_socket_t* s, const void* buf, size_t len); 59 | 60 | /** 61 | * Receive a given number of bytes 62 | * @return 0 or a negative error code 63 | */ 64 | extern int 65 | node_socket_recv_bytes(node_socket_t* s, void* buf, size_t len); 66 | 67 | /** 68 | * Release all recources associated with the socket */ 69 | extern void 70 | node_socket_close(node_socket_t* s); 71 | 72 | #endif /* NODE_SOCKET_H */ 73 | -------------------------------------------------------------------------------- /examples/node/sst.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019, Codership Oy. All rights reserved. 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; version 2 of the License. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program; if not, write to the Free Software 14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | */ 16 | 17 | #include "sst.h" 18 | 19 | #include "ctx.h" 20 | #include "log.h" 21 | #include "socket.h" 22 | 23 | #include // htonl() 24 | #include 25 | #include 26 | #include 27 | #include // snprintf() 28 | #include // abort() 29 | #include // strdup() 30 | #include // usleep() 31 | 32 | /** 33 | * Helper: creates detached thread */ 34 | static int 35 | sst_create_thread(void* (*thread_routine) (void*), 36 | void* const thread_arg) 37 | { 38 | pthread_t thr; 39 | pthread_attr_t attr; 40 | int ret = pthread_attr_init(&attr); 41 | ret = ret ? ret : pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); 42 | ret = ret ? ret : pthread_create(&thr, &attr, thread_routine, thread_arg); 43 | return ret; 44 | } 45 | 46 | /** 47 | * Helper: creates detached thread and waits for it to call 48 | * sst_sync_with_parent() */ 49 | static void 50 | sst_create_and_sync(const char* const role, 51 | pthread_mutex_t* const mtx, 52 | pthread_cond_t* const cond, 53 | void* (*thread_routine) (void*), 54 | void* const thread_arg) 55 | { 56 | int ret = pthread_mutex_lock(mtx); 57 | if (ret) 58 | { 59 | NODE_FATAL("Failed to lock %s mutex: %d (%s)", role, ret, strerror(ret)); 60 | abort(); 61 | } 62 | 63 | ret = sst_create_thread(thread_routine, thread_arg); 64 | if (ret) 65 | { 66 | NODE_FATAL("Failed to create detached %s thread: %d (%s)", 67 | role, ret, strerror(ret)); 68 | abort(); 69 | } 70 | 71 | ret = pthread_cond_wait(cond, mtx); 72 | if (ret) 73 | { 74 | NODE_FATAL("Failed to synchronize with %s thread: %d (%s)", 75 | role, ret, strerror(ret)); 76 | abort(); 77 | } 78 | 79 | pthread_mutex_unlock(mtx); 80 | } 81 | 82 | /** 83 | * Helper: syncs with parent thread and allows it to continue and return 84 | * asynchronously */ 85 | static void 86 | sst_sync_with_parent(const char* role, 87 | pthread_mutex_t* mtx, 88 | pthread_cond_t* cond) 89 | { 90 | int ret = pthread_mutex_lock(mtx); 91 | if (ret) 92 | { 93 | NODE_FATAL("Failed to lock %s mutex: %d (%s)", role, ret, strerror(ret)); 94 | abort(); 95 | } 96 | 97 | NODE_INFO("Initialized %s thread", role); 98 | 99 | pthread_cond_signal(cond); 100 | pthread_mutex_unlock(mtx); 101 | } 102 | 103 | static pthread_mutex_t sst_joiner_mtx = PTHREAD_MUTEX_INITIALIZER; 104 | static pthread_cond_t sst_joiner_cond = PTHREAD_COND_INITIALIZER; 105 | 106 | struct sst_joiner_ctx 107 | { 108 | struct node_ctx* node; 109 | node_socket_t* socket; 110 | }; 111 | 112 | /** 113 | * waits for SST completion and signals the provider to continue */ 114 | static void* 115 | sst_joiner_thread(void* ctx) 116 | { 117 | assert(ctx); 118 | 119 | struct node_ctx* const node = ((struct sst_joiner_ctx*)ctx)->node; 120 | node_socket_t* const listen = ((struct sst_joiner_ctx*)ctx)->socket; 121 | ctx = NULL; /* may be unusable after next statement */ 122 | 123 | /* this allows parent callback to return */ 124 | sst_sync_with_parent("JOINER", &sst_joiner_mtx, &sst_joiner_cond); 125 | 126 | wsrep_gtid_t state_gtid = WSREP_GTID_UNDEFINED; 127 | int err = -1; 128 | 129 | /* REPLICATION: wait for donor to connect and send the state snapshot */ 130 | node_socket_t* const connected = node_socket_accept(listen); 131 | if (!connected) goto end; 132 | 133 | uint32_t state_len; 134 | err = node_socket_recv_bytes(connected, &state_len, sizeof(state_len)); 135 | if (err) goto end; 136 | 137 | state_len = ntohl(state_len); 138 | if (state_len > 0) 139 | { 140 | /* REPLICATION: get the state of state_len size */ 141 | void* state = malloc(state_len); 142 | if (state) 143 | { 144 | err = node_socket_recv_bytes(connected, state, state_len); 145 | if (err) 146 | { 147 | free(state); 148 | goto end; 149 | } 150 | 151 | /* REPLICATION: install the newly received state. */ 152 | err = node_store_init_state(node->store, state, state_len); 153 | free(state); 154 | if (err) goto end; 155 | } 156 | else 157 | { 158 | NODE_ERROR("Failed to allocate %zu bytes for state snapshot.", 159 | state_len); 160 | err = -ENOMEM; 161 | goto end; 162 | } 163 | } 164 | else 165 | { 166 | /* REPLICATION: it was a bypass, the node will receive missing data via 167 | * IST. It starts with the state it currently has. */ 168 | } 169 | 170 | /* REPLICATION: find gtid of the received state to report to provider */ 171 | node_store_gtid(node->store, &state_gtid); 172 | 173 | end: 174 | assert(err <= 0); 175 | node_socket_close(connected); 176 | node_socket_close(listen); 177 | 178 | /* REPLICATION: tell provider that SST is received */ 179 | wsrep_status_t sst_ret; 180 | wsrep_t* const wsrep = node_wsrep_provider(node->wsrep); 181 | sst_ret = wsrep->sst_received(wsrep, &state_gtid, NULL, err); 182 | 183 | if (WSREP_OK != sst_ret) 184 | { 185 | NODE_FATAL("Failed to report completion of SST: %d", sst_ret); 186 | abort(); 187 | } 188 | 189 | return NULL; 190 | } 191 | 192 | enum wsrep_cb_status 193 | node_sst_request_cb (void* const app_ctx, 194 | void** const sst_req, 195 | size_t* const sst_req_len) 196 | { 197 | static int const SST_PORT_OFFSET = 2; 198 | 199 | assert(app_ctx); 200 | struct node_ctx* const node = app_ctx; 201 | const struct node_options* const opts = node->opts; 202 | 203 | char* sst_str = NULL; 204 | 205 | /* REPLICATION: 1. prepare the node to receive SST */ 206 | uint16_t const sst_port = (uint16_t)(opts->base_port + SST_PORT_OFFSET); 207 | size_t const sst_len = strlen(opts->base_host) 208 | + 1 /* ':' */ + 5 /* max port len */ + 1 /* \0 */; 209 | sst_str = malloc(sst_len); 210 | if (!sst_str) 211 | { 212 | NODE_ERROR("Failed to allocate %zu bytes for SST request", sst_len); 213 | goto end; 214 | } 215 | 216 | /* write in request the address at which we listen */ 217 | int ret = snprintf(sst_str, sst_len, "%s:%hu", opts->base_host, sst_port); 218 | if (ret < 0 || (size_t)ret >= sst_len) 219 | { 220 | free(sst_str); 221 | sst_str = NULL; 222 | NODE_ERROR("Failed to write a SST request"); 223 | goto end; 224 | } 225 | 226 | node_socket_t* const socket = node_socket_listen(NULL, sst_port); 227 | if (!socket) 228 | { 229 | free(sst_str); 230 | sst_str = NULL; 231 | NODE_ERROR("Failed to listen at %s", sst_str); 232 | goto end; 233 | } 234 | 235 | /* REPLICATION 2. start the "joiner" thread that will wait for SST and 236 | * report its success to provider, and syncronize with it. */ 237 | struct sst_joiner_ctx ctx = 238 | { 239 | .node = node, 240 | .socket = socket 241 | }; 242 | sst_create_and_sync("JOINER", &sst_joiner_mtx, &sst_joiner_cond, 243 | sst_joiner_thread, &ctx); 244 | 245 | NODE_INFO("Waiting for SST at %s", sst_str); 246 | 247 | end: 248 | if (sst_str) 249 | { 250 | *sst_req = sst_str; 251 | *sst_req_len = strlen(sst_str) + 1; 252 | } 253 | else 254 | { 255 | *sst_req = NULL; 256 | *sst_req_len = 0; 257 | return WSREP_CB_FAILURE; 258 | } 259 | 260 | /* REPLICATION 3. return SST request to provider */ 261 | return WSREP_CB_SUCCESS; 262 | } 263 | 264 | static pthread_mutex_t sst_donor_mtx = PTHREAD_MUTEX_INITIALIZER; 265 | static pthread_cond_t sst_donor_cond = PTHREAD_COND_INITIALIZER; 266 | 267 | struct sst_donor_ctx 268 | { 269 | wsrep_gtid_t state; 270 | struct node_ctx* node; 271 | node_socket_t* socket; 272 | wsrep_bool_t bypass; 273 | }; 274 | 275 | /** 276 | * donates SST and signals provider that it is done. */ 277 | static void* 278 | sst_donor_thread(void* const args) 279 | { 280 | struct sst_donor_ctx const ctx = *(struct sst_donor_ctx*)args; 281 | 282 | int err = 0; 283 | const void* state; 284 | size_t state_len; 285 | 286 | if (ctx.bypass) 287 | { 288 | /* REPLICATION: if bypass is true, there is no need to send snapshot, 289 | * just signal the joiner that snapshot is not needed and 290 | * it can proceed to apply IST. We'll do it by sending 0 291 | * for the size of snapshot */ 292 | state = NULL; 293 | state_len = 0; 294 | } 295 | else 296 | { 297 | /* REPLICATION: if bypass is false, we need to send a full state snapshot 298 | * Get hold of the state, which is currently just GTID 299 | * NOTICE that while parent is waiting, the store is in a 300 | * quiescent state, provider blocking any modifications. */ 301 | err = node_store_acquire_state(ctx.node->store, &state, &state_len); 302 | if (state_len > UINT32_MAX) err = -ERANGE; 303 | } 304 | 305 | /* REPLICATION: after getting hold of the state we can allow parent callback 306 | * to return and the node to resume its normal operation */ 307 | sst_sync_with_parent("DONOR", &sst_donor_mtx, &sst_donor_cond); 308 | 309 | if (err >= 0) 310 | { 311 | uint32_t tmp = htonl((uint32_t)state_len); 312 | err = node_socket_send_bytes(ctx.socket, &tmp, sizeof(tmp)); 313 | } 314 | 315 | if (state_len != 0) 316 | { 317 | if (err >= 0) 318 | { 319 | assert(state); 320 | err = node_socket_send_bytes(ctx.socket, state, state_len); 321 | } 322 | 323 | node_store_release_state(ctx.node->store); 324 | } 325 | 326 | node_socket_close(ctx.socket); 327 | 328 | /* REPLICATION: signal provider the success of the operation */ 329 | wsrep_t* const wsrep = node_wsrep_provider(ctx.node->wsrep); 330 | wsrep->sst_sent(wsrep, &ctx.state, err); 331 | 332 | return NULL; 333 | } 334 | 335 | enum wsrep_cb_status 336 | node_sst_donate_cb (void* const app_ctx, 337 | void* const recv_ctx, 338 | const wsrep_buf_t* const str_msg, 339 | const wsrep_gtid_t* const state_id, 340 | const wsrep_buf_t* const state, 341 | wsrep_bool_t const bypass) 342 | { 343 | (void)recv_ctx; 344 | (void)state; 345 | 346 | struct sst_donor_ctx ctx = 347 | { 348 | .node = app_ctx, 349 | .state = *state_id, 350 | .bypass = bypass 351 | }; 352 | 353 | /* we are expecting a human-readable 0-terminated string */ 354 | void* p = memchr(str_msg->ptr, '\0', str_msg->len); 355 | if (!p) 356 | { 357 | NODE_ERROR("Received a badly formed State Transfer Request."); 358 | /* REPLICATION: in case of a failure we return the status to provider, so 359 | * that the joining node can be notified of it by cluster */ 360 | return WSREP_CB_FAILURE; 361 | } 362 | 363 | const char* addr = str_msg->ptr; 364 | ctx.socket = node_socket_connect(addr); 365 | 366 | if (!ctx.socket) return WSREP_CB_FAILURE; 367 | 368 | sst_create_and_sync("DONOR", &sst_donor_mtx, &sst_donor_cond, 369 | sst_donor_thread, &ctx); 370 | 371 | return WSREP_CB_SUCCESS; 372 | } 373 | -------------------------------------------------------------------------------- /examples/node/sst.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019, Codership Oy. All rights reserved. 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; version 2 of the License. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program; if not, write to the Free Software 14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | */ 16 | 17 | /** 18 | * @file This unit defines SST interface 19 | */ 20 | 21 | #ifndef NODE_SST_H 22 | #define NODE_SST_H 23 | 24 | #include "../../wsrep_api.h" 25 | 26 | extern enum wsrep_cb_status 27 | node_sst_request_cb (void* app_ctx, 28 | void** sst_req, 29 | size_t* sst_req_len); 30 | 31 | extern enum wsrep_cb_status 32 | node_sst_donate_cb (void* app_ctx, 33 | void* recv_ctx, 34 | const wsrep_buf_t* str_msg, 35 | const wsrep_gtid_t* state_id, 36 | const wsrep_buf_t* state, 37 | wsrep_bool_t bypass); 38 | 39 | #endif /* NODE_SST_H */ 40 | -------------------------------------------------------------------------------- /examples/node/stats.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019-2020, Codership Oy. All rights reserved. 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; version 2 of the License. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program; if not, write to the Free Software 14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | */ 16 | 17 | #include "stats.h" 18 | 19 | #include "log.h" 20 | 21 | #include 22 | #include 23 | #include // snprintf() 24 | #include // abort() 25 | #include // strcmp() 26 | #include // usleep() 27 | 28 | enum 29 | { 30 | STATS_REPL_BYTE, 31 | STATS_REPL_WS, 32 | STATS_RECV_BYTE, 33 | STATS_RECV_WS, 34 | STATS_TOTAL_BYTE, 35 | STATS_TOTAL_WS, 36 | STATS_CERT_FAILS, 37 | STATS_STORE_FAILS, 38 | STATS_FC_PAUSED, 39 | STATS_MAX 40 | }; 41 | 42 | static const char* const stats_legend[STATS_MAX] = 43 | { 44 | " repl(B/s)", 45 | " repl(W/s)", 46 | " recv(B/s)", 47 | " recv(W/s)", 48 | "total(B/s)", 49 | "total(W/s)", 50 | " cert.fail", 51 | " stor.fail", 52 | " paused(%)" 53 | }; 54 | 55 | /* stats IDs in provider output - provider dependent, here we use Galera's */ 56 | static const char* const galera_ids[STATS_MAX] = 57 | { 58 | "replicated_bytes", /**< STATS_REPL_BYTE */ 59 | "replicated", /**< STATS_REPL_WS */ 60 | "received_bytes", /**< STATS_RECV_BYTE */ 61 | "received", /**< STATS_RECV_WS */ 62 | "", /**< STATS_TOTAL_BYTE */ 63 | "", /**< STATS_TOTAL_WS */ 64 | "local_cert_failures", /**< STATS_CERT_FAILS */ 65 | "", /**< STATS_STORE_FAILS */ 66 | "flow_control_paused_ns" /**< STATS_FC_PAUSED */ 67 | }; 68 | 69 | /* maps local stats IDs to provider stat IDs */ 70 | static int stats_galera_map[STATS_MAX]; 71 | 72 | /** 73 | * Helper to map provider stats to own stats set */ 74 | static void 75 | stats_establish_mapping(wsrep_t* const wsrep) 76 | { 77 | int const magic_map = -1; 78 | size_t i; 79 | for (i = 0; i < sizeof(stats_galera_map)/sizeof(stats_galera_map[0]); i++) 80 | { 81 | stats_galera_map[i] = magic_map; /* initialize map array */ 82 | } 83 | 84 | struct wsrep_stats_var* const stats = wsrep->stats_get(wsrep); 85 | 86 | /* to compensate for STATS_TOTAL_* and STATS_STORE_FAILS having no 87 | * counterparts */ 88 | int mapped = 3; 89 | 90 | i = 0; 91 | while (stats[i].name) /* stats array is terminated by Null name */ 92 | { 93 | int j; 94 | for (j = 0; j < STATS_MAX; j++) 95 | { 96 | if (magic_map == stats_galera_map[j] /* j-th member still unset */ 97 | && 98 | !strcmp(stats[i].name, galera_ids[j])) 99 | { 100 | stats_galera_map[j] = (int)i; 101 | mapped++; 102 | if (STATS_MAX == mapped) /* all mapped */ goto out; 103 | } 104 | } 105 | 106 | i++; 107 | } 108 | 109 | out: 110 | wsrep->stats_free(wsrep, stats); 111 | } 112 | 113 | static void 114 | stats_get(node_store_t* const store, wsrep_t* const wsrep, long long stats[]) 115 | { 116 | stats[STATS_STORE_FAILS] = node_store_read_view_failures(store); 117 | 118 | struct wsrep_stats_var* const ret = wsrep->stats_get(wsrep); 119 | if (!ret) 120 | { 121 | NODE_FATAL("wsrep::stats_get() call failed."); 122 | abort(); 123 | } 124 | 125 | int i; 126 | for (i = 0; i < STATS_MAX; i++) 127 | { 128 | int j = stats_galera_map[i]; 129 | if (j >= 0) 130 | { 131 | assert(WSREP_VAR_INT64 == ret[j].type); 132 | stats[i] = ret[j].value._int64; 133 | } 134 | } 135 | 136 | wsrep->stats_free(wsrep, ret); 137 | 138 | // totals are just sums 139 | stats[STATS_TOTAL_BYTE] = stats[STATS_REPL_BYTE] + stats[STATS_RECV_BYTE]; 140 | stats[STATS_TOTAL_WS ] = stats[STATS_REPL_WS ] + stats[STATS_RECV_WS ]; 141 | } 142 | 143 | static void 144 | stats_print(long long bef[], long long aft[], double period) 145 | { 146 | double rate[STATS_MAX]; 147 | int i; 148 | for (i = 0; i < STATS_MAX; i++) 149 | { 150 | rate[i] = (double)(aft[i] - bef[i])/period; 151 | } 152 | rate[STATS_FC_PAUSED] /= 1.0e+07; // nanoseconds to % of seconds 153 | 154 | char str[256]; 155 | int written = 0; 156 | 157 | /* first line write legend */ 158 | for (i = 0; i < STATS_MAX; i++) 159 | { 160 | size_t const space_left = sizeof(str) - (size_t)written; 161 | written += snprintf(&str[written], space_left, "%s", stats_legend[i]); 162 | } 163 | 164 | str[written] = '\n'; 165 | written++; 166 | 167 | /* second line write values */ 168 | for (i = 0; i < STATS_MAX; i++) 169 | { 170 | size_t const space_left = sizeof(str) - (size_t)written; 171 | long long const value = (long long)rate[i]; 172 | written += snprintf(&str[written], space_left, " %9lld", value); 173 | } 174 | 175 | str[written] = '\0'; 176 | 177 | /* use logging macro for timestamp */ 178 | NODE_INFO("\n%s", str); 179 | } 180 | 181 | void 182 | node_stats_loop(const struct node_ctx* const node, int const period) 183 | { 184 | double const period_sec = period; 185 | useconds_t const period_usec = (useconds_t)period * 1000000; 186 | 187 | wsrep_t* const wsrep = node_wsrep_provider(node->wsrep); 188 | stats_establish_mapping(wsrep); 189 | 190 | long long stats1[STATS_MAX]; 191 | long long stats2[STATS_MAX]; 192 | 193 | stats_get(node->store, wsrep, stats1); 194 | 195 | while (1) 196 | { 197 | if (usleep(period_usec)) break; 198 | stats_get(node->store, wsrep, stats2); 199 | stats_print(stats1, stats2, period_sec); 200 | 201 | if (usleep(period_usec)) break; 202 | stats_get(node->store, wsrep, stats1); 203 | stats_print(stats2, stats1, period_sec); 204 | } 205 | 206 | if (EINTR != errno) 207 | { 208 | NODE_ERROR("Unexpected usleep(%lld) error: %d (%s)", 209 | (long long)period_usec, errno, strerror(errno)); 210 | } 211 | else 212 | { 213 | /* interrupted by signal */ 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /examples/node/stats.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019, Codership Oy. All rights reserved. 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; version 2 of the License. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program; if not, write to the Free Software 14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | */ 16 | 17 | /** 18 | * @file This unit defines performance statistics loop 19 | */ 20 | 21 | #ifndef NODE_STATS_H 22 | #define NODE_STATS_H 23 | 24 | #include "ctx.h" 25 | 26 | /** 27 | * Prints out statistics with a given period. 28 | * 29 | * @param[in] node node context 30 | * @param[in] period in seconds 31 | */ 32 | extern void 33 | node_stats_loop(const struct node_ctx* node, int period); 34 | 35 | #endif /* NODE_STATS_H */ 36 | -------------------------------------------------------------------------------- /examples/node/store.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019-2020, Codership Oy. All rights reserved. 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; version 2 of the License. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program; if not, write to the Free Software 14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | */ 16 | 17 | /** 18 | * @file This unit defines simple "transactional storage engine" interface 19 | */ 20 | 21 | #ifndef NODE_STORE_H 22 | #define NODE_STORE_H 23 | 24 | #include "options.h" 25 | 26 | #include "../../wsrep_api.h" 27 | 28 | typedef struct node_store node_store_t; 29 | 30 | /** 31 | * open a store and optionally assocoate a file with it */ 32 | extern node_store_t* 33 | node_store_open(const struct node_options* opts); 34 | 35 | /** 36 | * close store and deallocate associated resources */ 37 | extern void 38 | node_store_close(node_store_t* store); 39 | 40 | /** 41 | * initialize store with a state */ 42 | extern int 43 | node_store_init_state(node_store_t* store, const void* state, size_t state_len); 44 | 45 | /** 46 | * Return a pointer to state snapshot that is guaranteed to be unchanged 47 | * until node_store_release_state() is called. 48 | * 49 | * @param[out] state pointer to state snapshot 50 | * @param[out] state_len soze of state snapshot 51 | */ 52 | extern int 53 | node_store_acquire_state(node_store_t* store, 54 | const void** state, size_t* state_len); 55 | 56 | /** 57 | * release state */ 58 | extern void 59 | node_store_release_state(node_store_t* store); 60 | 61 | /** 62 | * inform store about new membership */ 63 | extern int 64 | node_store_update_membership(node_store_t* store, const wsrep_view_info_t* v); 65 | 66 | /** 67 | * get the current GTID (last committed) */ 68 | extern void 69 | node_store_gtid(node_store_t* store, wsrep_gtid_t* gtid); 70 | 71 | /** 72 | * execute and prepare local transaction in store and return its key and write 73 | * set. 74 | * 75 | * This operation allocates resources that must be freed with either 76 | * node_store_commit() or node_store_rollback() 77 | * 78 | * @param[in] wsrep provider handle 79 | * @param[out] ws_handle reference to the resulting write set in the provider 80 | */ 81 | extern int 82 | node_store_execute(node_store_t* store, 83 | wsrep_t* wsrep, 84 | wsrep_ws_handle_t* ws_handle); 85 | 86 | /** 87 | * apply and prepare foreign write set received from replication 88 | * 89 | * This operation allocates resources that must be freed with either 90 | * node_store_commit() or node_store_rollback() 91 | * 92 | * @param[out] trx_id locally unique transaction ID 93 | * @param[in] ws foreign transaction write set 94 | */ 95 | extern int 96 | node_store_apply(node_store_t* store, 97 | wsrep_trx_id_t* trx_id, 98 | const wsrep_buf_t* ws); 99 | 100 | /** 101 | * commit prepared transaction identified by trx_id */ 102 | extern void 103 | node_store_commit(node_store_t* store, 104 | wsrep_trx_id_t trx_id, 105 | const wsrep_gtid_t* ws_gtid); 106 | 107 | /** 108 | * rollback prepared transaction identified by trx_id */ 109 | extern void 110 | node_store_rollback(node_store_t* store, 111 | wsrep_trx_id_t trx_id); 112 | 113 | /** 114 | * update storage GTID for transactions that had to be skipped/rolled back */ 115 | extern void 116 | node_store_update_gtid(node_store_t* store, 117 | const wsrep_gtid_t* ws_gtid); 118 | 119 | /** 120 | * @return the number of store read view snapshot check failures at commit time. 121 | * (should be zero if provider implements assign_read_view() call) */ 122 | extern long 123 | node_store_read_view_failures(node_store_t* store); 124 | 125 | #endif /* NODE_STORE_H */ 126 | -------------------------------------------------------------------------------- /examples/node/trx.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019-2020, Codership Oy. All rights reserved. 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; version 2 of the License. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program; if not, write to the Free Software 14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | */ 16 | 17 | #include "trx.h" 18 | #include "log.h" 19 | 20 | #include 21 | #include // ENOMEM, etc. 22 | #include 23 | 24 | wsrep_status_t 25 | node_trx_execute(node_store_t* const store, 26 | wsrep_t* const wsrep, 27 | wsrep_conn_id_t const conn_id, 28 | int ops_num) 29 | { 30 | wsrep_status_t cert = WSREP_OK; // for cleanup 31 | 32 | static unsigned int const ws_flags = 33 | WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END; // atomic trx 34 | wsrep_trx_meta_t ws_meta; 35 | wsrep_status_t ret = WSREP_OK; 36 | 37 | /* prepare simple transaction and obtain a writeset handle for it */ 38 | wsrep_ws_handle_t ws_handle = { 0, NULL }; 39 | while (ops_num--) 40 | { 41 | if (0 != (ret = node_store_execute(store, wsrep, &ws_handle))) 42 | { 43 | #if 0 44 | NODE_INFO("master [%d]: node_store_execute() returned %d", 45 | conn_id, ret); 46 | #endif 47 | ret = WSREP_TRX_FAIL; 48 | goto cleanup; 49 | } 50 | } 51 | 52 | /* REPLICATION: (replicate and) certify the writeset (pointed to by 53 | * ws_handle) with the cluster */ 54 | cert = wsrep->certify(wsrep, conn_id, &ws_handle, ws_flags, &ws_meta); 55 | 56 | if (WSREP_BF_ABORT == cert) 57 | { 58 | /* REPLICATION: transaction was signaled to abort due to multi-master 59 | * conflict. It must rollback immediately: it blocks 60 | * transaction that was ordered earlier and will never 61 | * be able to enter commit order. */ 62 | node_store_rollback(store, ws_handle.trx_id); 63 | } 64 | 65 | /* REPLICATION: writeset was totally ordered, need to enter commit order */ 66 | if (ws_meta.gtid.seqno > 0) 67 | { 68 | ret = wsrep->commit_order_enter(wsrep, &ws_handle, &ws_meta); 69 | if (ret) 70 | { 71 | NODE_ERROR("master [%d]: wsrep::commit_order_enter(%lld) failed: " 72 | "%d", (long long)(ws_meta.gtid.seqno), ret); 73 | goto cleanup; 74 | } 75 | 76 | /* REPLICATION: inside commit monitor 77 | * Note: we commit transaction only if certification succeded */ 78 | if (WSREP_OK == cert) 79 | node_store_commit(store, ws_handle.trx_id, &ws_meta.gtid); 80 | else 81 | node_store_update_gtid(store, &ws_meta.gtid); 82 | 83 | ret = wsrep->commit_order_leave(wsrep, &ws_handle, &ws_meta, NULL); 84 | if (ret) 85 | { 86 | NODE_ERROR("master [%d]: wsrep::commit_order_leave(%lld) failed: " 87 | "%d", (long long)(ws_meta.gtid.seqno), ret); 88 | goto cleanup; 89 | } 90 | } 91 | else 92 | { 93 | assert(cert); 94 | } 95 | 96 | cleanup: 97 | /* REPLICATION: if wsrep->certify() returned anything else but WSREP_OK 98 | * transaction must roll back. BF aborted trx already did it. */ 99 | if (cert && WSREP_BF_ABORT != cert) 100 | node_store_rollback(store, ws_handle.trx_id); 101 | 102 | /* NOTE: this application follows the approach that resources must be freed 103 | * at the same level where they were allocated, so it is assumed that 104 | * ws_key and ws were deallocated in either commit or rollback calls.*/ 105 | 106 | /* REPLICATION: release provider resources associated with the trx */ 107 | wsrep->release(wsrep, &ws_handle); 108 | 109 | return ret ? ret : cert; 110 | } 111 | 112 | wsrep_status_t 113 | node_trx_apply(node_store_t* const store, 114 | wsrep_t* const wsrep, 115 | const wsrep_ws_handle_t* const ws_handle, 116 | const wsrep_trx_meta_t* const ws_meta, 117 | const wsrep_buf_t* const ws) 118 | { 119 | /* no business being here if event was not ordered */ 120 | assert(ws_meta->gtid.seqno > 0); 121 | 122 | wsrep_trx_id_t trx_id; 123 | wsrep_buf_t err_buf = { NULL, 0 }; 124 | int app_err; 125 | if (ws) 126 | { 127 | app_err = node_store_apply(store, &trx_id, ws); 128 | if (app_err) 129 | { 130 | /* REPLICATION: if applying failed, prepare an error buffer with 131 | * sufficient error specification */ 132 | err_buf.ptr = &app_err; // suppose error code is enough 133 | err_buf.len = sizeof(app_err); 134 | } 135 | } 136 | else /* ws failed certification and should be skipped */ 137 | { 138 | /* just some non-0 code to choose node_store_update_gtid() below */ 139 | app_err = 1; 140 | } 141 | 142 | wsrep_status_t ret; 143 | ret = wsrep->commit_order_enter(wsrep, ws_handle, ws_meta); 144 | if (ret) { 145 | node_store_rollback(store, trx_id); 146 | return ret; 147 | } 148 | 149 | if (!app_err) node_store_commit(store, trx_id, &ws_meta->gtid); 150 | else node_store_update_gtid(store, &ws_meta->gtid); 151 | 152 | ret = wsrep->commit_order_leave(wsrep, ws_handle, ws_meta, &err_buf); 153 | 154 | return ret; 155 | } 156 | -------------------------------------------------------------------------------- /examples/node/trx.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019-2020, Codership Oy. All rights reserved. 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; version 2 of the License. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program; if not, write to the Free Software 14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | */ 16 | 17 | /** 18 | * @file This unit defines "transaction" interface 19 | */ 20 | 21 | #ifndef NODE_TRX_H 22 | #define NODE_TRX_H 23 | 24 | #include "store.h" 25 | 26 | #include "../../wsrep_api.h" 27 | 28 | /** 29 | * executes and replicates local transaction 30 | */ 31 | extern wsrep_status_t 32 | node_trx_execute(node_store_t* store, 33 | wsrep_t* wsrep, 34 | wsrep_conn_id_t conn_id, 35 | int ops_num); 36 | 37 | /** 38 | * applies and commits slave write set 39 | * 40 | * @param ws replicated event writeset. NULL if it failed certification (and so 41 | * must be skipped, but it was ordered, so store GTID must be updated) 42 | */ 43 | extern wsrep_status_t 44 | node_trx_apply(node_store_t* store, 45 | wsrep_t* wsrep, 46 | const wsrep_ws_handle_t* ws_handle, 47 | const wsrep_trx_meta_t* ws_meta, 48 | const wsrep_buf_t* ws); 49 | 50 | #endif /* NODE_TRX_H */ 51 | -------------------------------------------------------------------------------- /examples/node/worker.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019-2020, Codership Oy. All rights reserved. 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; version 2 of the License. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program; if not, write to the Free Software 14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | */ 16 | 17 | #include "worker.h" 18 | 19 | #include "log.h" 20 | #include "options.h" 21 | #include "trx.h" 22 | #include "wsrep.h" 23 | 24 | #include 25 | #include 26 | #include 27 | #include // strerror() 28 | 29 | struct node_worker 30 | { 31 | struct node_ctx* node; 32 | pthread_t thread_id; 33 | size_t id; 34 | bool exit; 35 | }; 36 | 37 | enum wsrep_cb_status 38 | node_worker_apply_cb(void* const recv_ctx, 39 | const wsrep_ws_handle_t* const ws_handle, 40 | uint32_t const ws_flags, 41 | const wsrep_buf_t* const ws, 42 | const wsrep_trx_meta_t* const ws_meta, 43 | wsrep_bool_t* const exit_loop) 44 | { 45 | assert(recv_ctx); 46 | 47 | struct node_worker* const worker = recv_ctx; 48 | 49 | wsrep_status_t const ret = node_trx_apply( 50 | worker->node->store, 51 | node_wsrep_provider(worker->node->wsrep), 52 | ws_handle, 53 | ws_meta, 54 | ws_flags & WSREP_FLAG_ROLLBACK ? NULL : ws); 55 | 56 | *exit_loop = worker->exit; 57 | 58 | return WSREP_OK == ret ? WSREP_CB_SUCCESS : WSREP_CB_FAILURE; 59 | } 60 | 61 | 62 | static void* 63 | worker_slave(void* recv_ctx) 64 | { 65 | struct node_worker* const worker = recv_ctx; 66 | wsrep_t* const wsrep = node_wsrep_provider(worker->node->wsrep); 67 | 68 | wsrep_status_t const ret = wsrep->recv(wsrep, worker); 69 | 70 | if (WSREP_OK != ret) 71 | { 72 | NODE_ERROR("slave worker [%zu] exited with error %d.", worker->id, ret); 73 | } 74 | 75 | return NULL; 76 | } 77 | 78 | static void* 79 | worker_master(void* send_ctx) 80 | { 81 | struct node_worker* const worker = send_ctx; 82 | struct node_ctx* const node = worker->node; 83 | wsrep_t* const wsrep = node_wsrep_provider(node->wsrep); 84 | 85 | assert(node->opts->ws_size > 0); 86 | 87 | wsrep_status_t ret; 88 | 89 | do 90 | { 91 | /* REPLICATION: we should not perform any local writes until the node 92 | * is synced with the cluster. */ 93 | if (!node_wsrep_wait_synced(node->wsrep)) 94 | { 95 | NODE_ERROR("master worker [%zu] failed waiting for SYNCED state.", 96 | worker->id); 97 | break; 98 | } 99 | 100 | /* REPLICATION: the node is now synced */ 101 | 102 | do 103 | { 104 | ret = node_trx_execute(node->store, 105 | wsrep, 106 | worker->id, 107 | (int)node->opts->operations); 108 | } 109 | while(WSREP_OK == ret // success 110 | || (WSREP_TRX_FAIL == ret // certification failed, trx rolled back 111 | && (usleep(10000),true)) // retry after short sleep 112 | ); 113 | } 114 | while (WSREP_CONN_FAIL == ret); // provider in bad state (e.g. non-Primary) 115 | 116 | return NULL; 117 | } 118 | 119 | struct node_worker_pool 120 | { 121 | size_t size; // size of the pool (nu,ber of nodes) 122 | struct node_worker worker[1]; // worker context array; 123 | }; 124 | 125 | struct node_worker_pool* 126 | node_worker_start(struct node_ctx* const ctx, 127 | node_worker_type_t const type, 128 | size_t const size) 129 | { 130 | assert(ctx); 131 | 132 | if (0 == size) return NULL; 133 | 134 | const char* const type_str = type == NODE_WORKER_SLAVE ? "slave" : "master"; 135 | 136 | size_t const alloc_size = 137 | sizeof(struct node_worker_pool) + 138 | sizeof(struct node_worker) * (size - 1); 139 | 140 | struct node_worker_pool* const ret = malloc(alloc_size); 141 | 142 | if (ret) 143 | { 144 | void* (* const routine) (void*) = 145 | type == NODE_WORKER_SLAVE ? worker_slave : worker_master; 146 | 147 | size_t i; 148 | for (i = 0; i < size; i++) 149 | { 150 | struct node_worker* const worker = &ret->worker[i]; 151 | worker->node = ctx; 152 | worker->id = i; 153 | worker->exit = false; 154 | 155 | int const err = pthread_create(&worker->thread_id, 156 | NULL, 157 | routine, 158 | worker); 159 | if (err) 160 | { 161 | NODE_ERROR("Failed to start %s worker[%zu]: %d (%s)", 162 | type_str, i, err, strerror(err)); 163 | if (0 == i) 164 | { 165 | free(ret); 166 | return NULL; 167 | } 168 | else 169 | { 170 | break; // some threads have started, 171 | // need to return to close them first 172 | } 173 | } 174 | } 175 | 176 | ret->size = i; 177 | } 178 | else 179 | { 180 | NODE_ERROR("Failed to allocate %zu bytes for the %s worker pool", 181 | alloc_size, type_str); 182 | } 183 | 184 | return ret; 185 | } 186 | 187 | void 188 | node_worker_stop(struct node_worker_pool* pool) 189 | { 190 | size_t i; 191 | for (i = 0; pool && i < pool->size; i++) 192 | { 193 | pthread_join(pool->worker[i].thread_id, NULL); 194 | } 195 | 196 | free(pool); 197 | } 198 | -------------------------------------------------------------------------------- /examples/node/worker.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019, Codership Oy. All rights reserved. 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; version 2 of the License. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program; if not, write to the Free Software 14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | */ 16 | 17 | /** 18 | * @file This unit defines worker thread interface 19 | */ 20 | 21 | #ifndef NODE_WORKER_H 22 | #define NODE_WORKER_H 23 | 24 | #include "ctx.h" 25 | 26 | #include "../../wsrep_api.h" 27 | 28 | /** 29 | * REPLICATION: a callback to apply and commit slave replication events */ 30 | extern enum wsrep_cb_status 31 | node_worker_apply_cb(void* recv_ctx, 32 | const wsrep_ws_handle_t* ws_handle, 33 | uint32_t ws_flags, 34 | const wsrep_buf_t* ws, 35 | const wsrep_trx_meta_t* ws_meta, 36 | wsrep_bool_t* exit_loop); 37 | 38 | typedef enum node_worker_type 39 | { 40 | NODE_WORKER_SLAVE, 41 | NODE_WORKER_MASTER 42 | } 43 | node_worker_type_t; 44 | 45 | struct node_worker_pool; 46 | 47 | /** 48 | * Starts the required number of workier threads of a given type 49 | * 50 | * @param[in] ctx application context 51 | * @param[in] type of a worker 52 | * @param[in] number of workers 53 | * 54 | * @return worker pool handle 55 | */ 56 | extern struct node_worker_pool* 57 | node_worker_start(struct node_ctx* ctx, 58 | node_worker_type_t type, 59 | size_t number); 60 | 61 | /** 62 | * Stops workers in a pool and deallocates respective resources */ 63 | extern void 64 | node_worker_stop(struct node_worker_pool* pool); 65 | 66 | #endif /* NODE_WORKER_H */ 67 | -------------------------------------------------------------------------------- /examples/node/wsrep.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019, Codership Oy. All rights reserved. 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; version 2 of the License. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program; if not, write to the Free Software 14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | */ 16 | 17 | #include "wsrep.h" 18 | 19 | #include "log.h" 20 | #include "sst.h" 21 | #include "store.h" 22 | #include "worker.h" 23 | 24 | #include 25 | #include // snprintf() 26 | #include // abort() 27 | #include // strcasecmp() 28 | 29 | struct node_wsrep 30 | { 31 | wsrep_t* instance; // wsrep provider instance 32 | 33 | struct wsrep_view 34 | { 35 | pthread_mutex_t mtx; 36 | wsrep_gtid_t state_id; 37 | wsrep_view_status_t status; 38 | wsrep_cap_t capabilities; 39 | int proto_ver; 40 | int memb_num; 41 | int my_idx; 42 | wsrep_member_info_t* members; 43 | } 44 | view; 45 | 46 | struct 47 | { 48 | pthread_mutex_t mtx; 49 | pthread_cond_t cond; 50 | int value; 51 | } 52 | synced; 53 | 54 | bool bootstrap; // shall this node bootstrap a primary view? 55 | }; 56 | 57 | static struct node_wsrep s_wsrep = 58 | { 59 | .instance = NULL, 60 | .view = 61 | { 62 | .mtx = PTHREAD_MUTEX_INITIALIZER, 63 | .state_id = {{{ 0, }}, WSREP_SEQNO_UNDEFINED }, 64 | .status = WSREP_VIEW_DISCONNECTED, 65 | .capabilities = 0, 66 | .proto_ver = -1, 67 | .memb_num = 0, 68 | .my_idx = -1, 69 | .members = NULL 70 | }, 71 | .synced = 72 | { 73 | .mtx = PTHREAD_MUTEX_INITIALIZER, 74 | .cond = PTHREAD_COND_INITIALIZER, 75 | .value = 0 76 | }, 77 | .bootstrap = false 78 | }; 79 | 80 | static const char* wsrep_view_status_str[WSREP_VIEW_MAX] = 81 | { 82 | "PRIMARY", 83 | "NON-PRIMARY", 84 | "DISCONNECTED" 85 | }; 86 | 87 | #define WSREP_CAPABILITIES_MAX ((int)sizeof(wsrep_cap_t) * 8) // bitmask 88 | static const char* wsrep_capabilities_str[WSREP_CAPABILITIES_MAX] = 89 | { 90 | "MULTI-MASTER", 91 | "CERTIFICATION", 92 | "PA", 93 | "REPLAY", 94 | "TOI", 95 | "PAUSE", 96 | "CAUSAL-READS", 97 | "CAUSAL-TRX", 98 | "INCREMENTAL", 99 | "SESSION-LOCKS", 100 | "DISTRIBUTED-LOCKS", 101 | "CONSISTENCY-CHECK", 102 | "UNORDERED", 103 | "ANNOTATION", 104 | "PREORDERED", 105 | "STREAMING", 106 | "SNAPSHOT", 107 | "NBO", 108 | NULL, 109 | }; 110 | 111 | /** 112 | * REPLICATION: callback is called by provider when the node connects to group. 113 | * This happens out-of-order, before the node receives a state 114 | * transfer and syncs with the cluster. Unless application requires 115 | * it it can be empty. We however want to know the GTID of the 116 | * group out of order for SST tricks, so we record it out of order. 117 | */ 118 | static enum wsrep_cb_status 119 | wsrep_connected_cb(void* const x, 120 | const wsrep_view_info_t* const v) 121 | { 122 | char gtid_str[WSREP_GTID_STR_LEN + 1]; 123 | wsrep_gtid_print(&v->state_id, gtid_str, sizeof(gtid_str)); 124 | 125 | NODE_INFO("connect_cb(): Connected at %s to %s group of %d member(s)", 126 | gtid_str, wsrep_view_status_str[v->status], v->memb_num); 127 | 128 | struct node_wsrep* const wsrep = ((struct node_ctx*)x)->wsrep; 129 | 130 | if (pthread_mutex_lock(&wsrep->view.mtx)) 131 | { 132 | NODE_FATAL("Failed to lock VIEW mutex"); 133 | abort(); 134 | } 135 | 136 | wsrep->view.state_id = v->state_id; 137 | 138 | pthread_mutex_unlock(&wsrep->view.mtx); 139 | 140 | return WSREP_CB_SUCCESS; 141 | } 142 | 143 | /** 144 | * logs view data */ 145 | static void 146 | wsrep_log_view(const struct wsrep_view* v) 147 | { 148 | char gtid[WSREP_GTID_STR_LEN + 1]; 149 | wsrep_gtid_print(&v->state_id, gtid, sizeof(gtid)); 150 | gtid[WSREP_GTID_STR_LEN] = '\0'; 151 | 152 | char caps[256]; 153 | int written = 0; 154 | size_t space_left = sizeof(caps); 155 | int i; 156 | for (i = 0; i < WSREP_CAPABILITIES_MAX && space_left > 0; i++) 157 | { 158 | wsrep_cap_t const f = 1u << i; 159 | 160 | if (!(f & v->capabilities)) continue; 161 | 162 | if (wsrep_capabilities_str[i]) 163 | { 164 | written += snprintf(&caps[written], space_left, "%s|", 165 | wsrep_capabilities_str[i]); 166 | } 167 | else 168 | { 169 | written += snprintf(&caps[written], space_left, "%d|", i); 170 | } 171 | 172 | space_left = sizeof(caps) - (size_t)written; 173 | } 174 | caps[written ? written - 1 : 0] = '\0'; // overwrite last '|' 175 | 176 | char members_list[1024]; 177 | written = 0; 178 | space_left = sizeof(members_list); 179 | for (i = 0; i < v->memb_num && space_left > 0; i++) 180 | { 181 | wsrep_member_info_t* m = &v->members[i]; 182 | char uuid[WSREP_UUID_STR_LEN + 1]; 183 | wsrep_uuid_print(&m->id, uuid, sizeof(uuid)); 184 | uuid[WSREP_UUID_STR_LEN] = '\0'; 185 | 186 | written += snprintf(&members_list[written], space_left, 187 | "%s%d: %s '%s' incoming:'%s'\n", 188 | v->my_idx == i ? " * " : " ", i, 189 | uuid, m->name, m->incoming); 190 | 191 | space_left = sizeof(members_list) - (size_t)written; 192 | } 193 | members_list[written ? written - 1 : 0] = '\0'; // overwrite the last '\n' 194 | 195 | NODE_INFO( 196 | "New view received:\n" 197 | "state: %s (%s)\n" 198 | "capabilities: %s\n" 199 | "protocol version: %d\n" 200 | "members(%d)%s%s", 201 | gtid, wsrep_view_status_str[v->status], 202 | caps, 203 | v->proto_ver, 204 | v->memb_num, v->memb_num ? ":\n" : "", members_list); 205 | } 206 | 207 | /** 208 | * REPLICATION: callback is called when the node needs to process cluster 209 | * view change. The callback is called in "total order isolation", 210 | * so all the preceding replication events will be processed 211 | * strictly before the call and all subsequent - striclty after. 212 | */ 213 | static enum wsrep_cb_status 214 | wsrep_view_cb(void* const x, 215 | void* const r, 216 | const wsrep_view_info_t* const v, 217 | const char* const state, 218 | size_t const state_len) 219 | { 220 | (void)r; 221 | (void)state; 222 | (void)state_len; 223 | 224 | struct node_ctx* const node = x; 225 | 226 | if (WSREP_VIEW_PRIMARY == v->status) 227 | { 228 | /* REPLICATION: membership change is a totally ordered event and as such 229 | * should be a part of the state, like changes to the 230 | * database. */ 231 | int err = node_store_update_membership(node->store, v); 232 | if (err) 233 | { 234 | NODE_FATAL("Failed to update membership in store: %d (%s)", 235 | err, strerror(-err)); 236 | abort(); 237 | } 238 | } 239 | 240 | enum wsrep_cb_status ret = WSREP_CB_SUCCESS; 241 | struct node_wsrep* const wsrep = ((struct node_ctx*)x)->wsrep; 242 | 243 | if (pthread_mutex_lock(&wsrep->view.mtx)) 244 | { 245 | NODE_FATAL("Failed to lock VIEW mutex"); 246 | abort(); 247 | } 248 | 249 | /* below we'll just copy the data for future reference (if need be): */ 250 | 251 | size_t const memb_size = (size_t)v->memb_num * sizeof(wsrep_member_info_t); 252 | void* const tmp = realloc(wsrep->view.members, memb_size); 253 | if (memb_size > 0 && !tmp) 254 | { 255 | NODE_ERROR("Could not allocate memory for a new view: %zu bytes", 256 | memb_size); 257 | ret = WSREP_CB_FAILURE; 258 | goto cleanup; 259 | } 260 | else 261 | { 262 | wsrep->view.members = tmp; 263 | if (memb_size) memcpy(wsrep->view.members, &v->members[0], memb_size); 264 | } 265 | 266 | wsrep->view.state_id = v->state_id; 267 | wsrep->view.status = v->status; 268 | wsrep->view.capabilities = v->capabilities; 269 | wsrep->view.proto_ver = v->proto_ver; 270 | wsrep->view.memb_num = v->memb_num; 271 | wsrep->view.my_idx = v->my_idx; 272 | 273 | /* and now log the info */ 274 | 275 | wsrep_log_view(&wsrep->view); 276 | 277 | cleanup: 278 | pthread_mutex_unlock(&wsrep->view.mtx); 279 | 280 | return ret; 281 | } 282 | 283 | /** 284 | * REPLICATION: callback is called by provider when the node becomes SYNCED */ 285 | static enum wsrep_cb_status 286 | wsrep_synced_cb(void* const x) 287 | { 288 | struct node_wsrep* const wsrep = ((struct node_ctx*)x)->wsrep; 289 | 290 | if (pthread_mutex_lock(&wsrep->synced.mtx)) 291 | { 292 | NODE_FATAL("Failed to lock SYNCED mutex"); 293 | abort(); 294 | } 295 | 296 | if (wsrep->synced.value == 0) 297 | { 298 | NODE_INFO("become SYNCED"); 299 | wsrep->synced.value = 1; 300 | pthread_cond_broadcast(&wsrep->synced.cond); 301 | } 302 | 303 | pthread_mutex_unlock(&wsrep->synced.mtx); 304 | 305 | return WSREP_CB_SUCCESS; 306 | } 307 | 308 | struct node_wsrep* 309 | node_wsrep_init(const struct node_options* const opts, 310 | const wsrep_gtid_t* const current_gtid, 311 | void* const app_ctx) 312 | { 313 | if (s_wsrep.instance != NULL) return NULL; // already initialized 314 | 315 | wsrep_status_t err; 316 | err = wsrep_load(opts->provider, &s_wsrep.instance, node_log_cb); 317 | if (WSREP_OK != err) 318 | { 319 | if (strcasecmp(opts->provider, WSREP_NONE)) 320 | { 321 | NODE_ERROR("wsrep_load(%s) failed: %s (%d).", 322 | opts->provider, strerror(err), err); 323 | } 324 | else 325 | { 326 | NODE_ERROR("Initializing dummy provider failed: %s (%d).", 327 | strerror(err), err); 328 | } 329 | return NULL; 330 | } 331 | 332 | char base_addr[256]; 333 | snprintf(base_addr, sizeof(base_addr) - 1, "%s:%ld", 334 | opts->base_host, opts->base_port); 335 | 336 | struct wsrep_init_args args = 337 | { 338 | .app_ctx = app_ctx, 339 | 340 | .node_name = opts->name, 341 | .node_address = base_addr, 342 | .node_incoming = "", // we don't accept client connections 343 | .data_dir = opts->data_dir, 344 | .options = opts->options, 345 | .proto_ver = 0, // this is the first version of the application 346 | // so the first version of the writeset protocol 347 | .state_id = current_gtid, 348 | .state = NULL, // unused 349 | 350 | .logger_cb = node_log_cb, 351 | .connected_cb = wsrep_connected_cb, 352 | .view_cb = wsrep_view_cb, 353 | .synced_cb = wsrep_synced_cb, 354 | .encrypt_cb = NULL, // not implemented ATM 355 | 356 | .apply_cb = node_worker_apply_cb, 357 | .unordered_cb = NULL, // not needed now 358 | 359 | .sst_request_cb = node_sst_request_cb, 360 | .sst_donate_cb = node_sst_donate_cb 361 | }; 362 | 363 | wsrep_t* wsrep = s_wsrep.instance; 364 | 365 | err = wsrep->init(wsrep, &args); 366 | 367 | if (WSREP_OK != err) 368 | { 369 | NODE_ERROR("wsrep::init() failed: %d, must shutdown", err); 370 | node_wsrep_close(&s_wsrep); 371 | return NULL; 372 | } 373 | 374 | return &s_wsrep; 375 | } 376 | 377 | wsrep_status_t 378 | node_wsrep_connect(struct node_wsrep* const wsrep, 379 | const char* const address, 380 | bool const bootstrap) 381 | { 382 | wsrep->bootstrap = bootstrap; 383 | wsrep_status_t err = wsrep->instance->connect(wsrep->instance, 384 | "wsrep_cluster", 385 | address, 386 | NULL, 387 | wsrep->bootstrap); 388 | 389 | if (WSREP_OK != err) 390 | { 391 | NODE_ERROR("wsrep::connect(%s) failed: %d, must shutdown", 392 | address, err); 393 | node_wsrep_close(wsrep); 394 | } 395 | 396 | return err; 397 | } 398 | 399 | void 400 | node_wsrep_disconnect(struct node_wsrep* const wsrep) 401 | { 402 | if (pthread_mutex_lock(&wsrep->synced.mtx)) 403 | { 404 | NODE_FATAL("Failed to lock SYNCED mutex"); 405 | abort(); 406 | } 407 | wsrep->synced.value = -1; /* this will signal master threads to exit */ 408 | pthread_cond_broadcast(&wsrep->synced.cond); 409 | pthread_mutex_unlock(&wsrep->synced.mtx); 410 | 411 | wsrep_status_t const err = wsrep->instance->disconnect(wsrep->instance); 412 | 413 | if (err) 414 | { 415 | /* REPLICATION: unless connection is not closed, slave threads will 416 | * never return. */ 417 | NODE_FATAL("Failed to close wsrep connection: %d", err); 418 | abort(); 419 | } 420 | } 421 | 422 | void 423 | node_wsrep_close(struct node_wsrep* const wsrep) 424 | { 425 | if (pthread_mutex_lock(&wsrep->view.mtx)) 426 | { 427 | NODE_FATAL("Failed to lock VIEW mutex"); 428 | abort(); 429 | } 430 | assert(0 == wsrep->view.memb_num); // the node must be disconneted 431 | assert(NULL == wsrep->view.members); 432 | free(wsrep->view.members); 433 | wsrep->view.members = NULL; 434 | pthread_mutex_unlock(&wsrep->view.mtx); 435 | 436 | wsrep->instance->free(wsrep->instance); 437 | wsrep->instance = NULL; 438 | } 439 | 440 | bool 441 | node_wsrep_wait_synced(struct node_wsrep* const wsrep) 442 | { 443 | if (pthread_mutex_lock(&wsrep->synced.mtx)) 444 | { 445 | NODE_FATAL("Failed to lock SYNCED mutex"); 446 | abort(); 447 | } 448 | 449 | while (wsrep->synced.value == 0) 450 | { 451 | pthread_cond_wait(&wsrep->synced.cond, &wsrep->synced.mtx); 452 | } 453 | 454 | bool const ret = wsrep->synced.value > 0; 455 | 456 | pthread_mutex_unlock(&wsrep->synced.mtx); 457 | 458 | return ret; 459 | } 460 | 461 | void 462 | node_wsrep_connected_gtid(struct node_wsrep* wsrep, wsrep_gtid_t* gtid) 463 | { 464 | if (pthread_mutex_lock(&wsrep->view.mtx)) 465 | { 466 | NODE_FATAL("Failed to lock VIEW mutex"); 467 | abort(); 468 | } 469 | 470 | *gtid = wsrep->view.state_id; 471 | 472 | pthread_mutex_unlock(&wsrep->view.mtx); 473 | } 474 | 475 | wsrep_t* 476 | node_wsrep_provider(struct node_wsrep* wsrep) 477 | { 478 | return wsrep->instance; 479 | } 480 | -------------------------------------------------------------------------------- /examples/node/wsrep.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019, Codership Oy. All rights reserved. 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; version 2 of the License. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program; if not, write to the Free Software 14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | */ 16 | 17 | /** 18 | * @file This unit defines various helpers to manage wsrep provider 19 | */ 20 | 21 | #ifndef NODE_WSREP_H 22 | #define NODE_WSREP_H 23 | 24 | #include "options.h" 25 | 26 | #include "../../wsrep_api.h" 27 | 28 | #include 29 | #include 30 | 31 | typedef struct node_wsrep node_wsrep_t; 32 | 33 | /** 34 | * loads and initializes wsrep provider for further usage 35 | * 36 | * @param[in] opts program options 37 | * @param[in] current_gtid GTID corresponding to the current node state 38 | * @param[in] app_ctx application context to be passed to callbacks 39 | * 40 | * @return initialized object pointer 41 | */ 42 | extern node_wsrep_t* 43 | node_wsrep_init(const struct node_options* opts, 44 | const wsrep_gtid_t* current_gtid, 45 | void* app_ctx); 46 | 47 | /** 48 | * connects to primary component 49 | * 50 | * @param[in] wsrep wsrep context 51 | * @param[in] address address to connect at (provider specific) 52 | * @param[in] bootsstrap bootstrap primary component if there's none 53 | * 54 | * @return wsrep status code 55 | */ 56 | extern wsrep_status_t 57 | node_wsrep_connect(node_wsrep_t* wsrep, 58 | const char* address, 59 | bool bootstrap); 60 | 61 | /** 62 | * disconnects from primary component 63 | */ 64 | extern void 65 | node_wsrep_disconnect(node_wsrep_t* wsrep); 66 | 67 | /** 68 | * deinitializes and unloads wsrep provider 69 | */ 70 | extern void 71 | node_wsrep_close(node_wsrep_t* wsrep); 72 | 73 | /** 74 | * waits for the node to become SYNCED 75 | * 76 | * @return true if node is synced, false in any other event. 77 | */ 78 | extern bool 79 | node_wsrep_wait_synced(node_wsrep_t* wsrep); 80 | 81 | /** 82 | * @param[in] wsrep context 83 | * @param[out] gtid of the current view */ 84 | extern void 85 | node_wsrep_connected_gtid(node_wsrep_t* wsrep, wsrep_gtid_t* gtid); 86 | 87 | /** 88 | * @return wsrep provider instance */ 89 | extern wsrep_t* 90 | node_wsrep_provider(node_wsrep_t* wsrep); 91 | 92 | #endif /* NODE_WSREP_H */ 93 | -------------------------------------------------------------------------------- /wsrep.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codership/wsrep-API/795700ecd1864ca6cef9192531b77b374d2111f0/wsrep.xcf -------------------------------------------------------------------------------- /wsrep_allowlist_service.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Codership Oy 3 | * 4 | * This file is part of wsrep-API. 5 | * 6 | * Wsrep-API is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * Wsrep-API is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with wsrep-API. If not, see . 18 | */ 19 | 20 | /** @file wsrep_allowlist_service.h 21 | * 22 | * This file defines interface for connection allowlist checks. 23 | * 24 | * The provider which is capable of using the service interface v1 must 25 | * export the following functions. 26 | * 27 | * int wsrep_init_allowlist_service_v1(wsrep_allowlist_service_v1_t*) 28 | * void wsrep_deinit_allowlist_service_v1() 29 | * 30 | * which can be probed by the application. 31 | * 32 | * The application must initialize the service via above init function 33 | * before the provider is initialized via wsrep->init(). The deinit 34 | * function must be called after the provider side resources have been 35 | * released via wsrep->free(). 36 | */ 37 | 38 | #ifndef WSREP_ALLOWLIST_SERVICE_H 39 | #define WSREP_ALLOWLIST_SERVICE_H 40 | 41 | #include "wsrep_api.h" 42 | 43 | #ifdef __cplusplus 44 | extern "C" 45 | { 46 | #endif /* __cplusplus */ 47 | 48 | /** 49 | * Type tag for application defined allowlist processing context. 50 | * 51 | * Application may pass pointer to the context when initializing 52 | * the allowlist service. This pointer is passed a first parameter for 53 | * each service call. 54 | */ 55 | typedef struct wsrep_allowlist_context wsrep_allowlist_context_t; 56 | 57 | typedef enum 58 | { 59 | WSREP_ALLOWLIST_KEY_IP = 0, // IP allowlist check 60 | WSREP_ALLOWLIST_KEY_SSL // SSL certificate allowlist check 61 | } wsrep_allowlist_key_t; 62 | 63 | /* 64 | * Allowlist connection check callback. 65 | * 66 | * @retval WSREP_OK connection allowed 67 | * @retval WSREP_NOT_ALLOWED connection not allowed 68 | */ 69 | typedef wsrep_status_t (*wsrep_allowlist_cb_t)( 70 | wsrep_allowlist_context_t*, 71 | wsrep_allowlist_key_t key, 72 | const wsrep_buf_t* value); 73 | 74 | /** 75 | * Allowlist service struct. 76 | * 77 | * A pointer to this struct must be passed to the call to 78 | * wsrep_init_allowlist_service_v1. 79 | * 80 | * The application must provide implementation to all functions defined 81 | * in this struct. 82 | */ 83 | typedef struct wsrep_allowlist_service_v1_st 84 | { 85 | /* Allowlist check callback */ 86 | wsrep_allowlist_cb_t allowlist_cb; 87 | /* Pointer to application defined allowlist context. */ 88 | wsrep_allowlist_context_t* context; 89 | } wsrep_allowlist_service_v1_t; 90 | 91 | #ifdef __cplusplus 92 | } 93 | #endif /* __cplusplus */ 94 | 95 | 96 | #define WSREP_ALLOWLIST_SERVICE_INIT_FUNC_V1 "wsrep_init_allowlist_service_v1" 97 | #define WSREP_ALLOWLIST_SERVICE_DEINIT_FUNC_V1 "wsrep_deinit_allowlist_service_v1" 98 | 99 | #endif /* WSREP_ALLOWLIST_SERVICE_H */ 100 | 101 | -------------------------------------------------------------------------------- /wsrep_config_service.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Codership Oy 3 | * 4 | * This file is part of wsrep-API. 5 | * 6 | * Wsrep-API is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * Wsrep-API is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with wsrep-API. If not, see . 18 | */ 19 | 20 | /** @file wsrep_config_service.h 21 | * 22 | * This file defines interface to retrieve a complete list of configuration 23 | * parameters accepted by the provider. 24 | * * 25 | * The provider which is capable of using the service interface v1 must 26 | * export the following functions: 27 | * 28 | * int wsrep_init_config_service_v1(wsrep_config_service_v1_t*) 29 | * void wsrep_deinit_config_service_v1() 30 | * 31 | * which can be probed by the application. 32 | * 33 | */ 34 | 35 | #ifndef WSREP_CONFIG_SERVICE_H 36 | #define WSREP_CONFIG_SERVICE_H 37 | 38 | #include "wsrep_api.h" 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif 43 | 44 | /** 45 | * Flags to describe parameters. 46 | * By default, a parameter is dynamic and of type string, 47 | * unless flagged otherwise. 48 | */ 49 | #define WSREP_PARAM_DEPRECATED (1 << 0) 50 | #define WSREP_PARAM_READONLY (1 << 1) 51 | #define WSREP_PARAM_TYPE_BOOL (1 << 2) 52 | #define WSREP_PARAM_TYPE_INTEGER (1 << 3) 53 | #define WSREP_PARAM_TYPE_DOUBLE (1 << 4) 54 | 55 | #define WSREP_PARAM_TYPE_MASK ( \ 56 | WSREP_PARAM_TYPE_BOOL | \ 57 | WSREP_PARAM_TYPE_INTEGER | \ 58 | WSREP_PARAM_TYPE_DOUBLE \ 59 | ) 60 | 61 | typedef struct wsrep_parameter 62 | { 63 | int flags; 64 | const char* name; 65 | union { 66 | bool as_bool; 67 | int64_t as_integer; 68 | double as_double; 69 | const char* as_string; 70 | } value; 71 | } wsrep_parameter_t; 72 | 73 | /** 74 | * Callback called once for each parameter exposed by provider. 75 | * The callback should return WSREP_OK on success. Any other 76 | * return value causes get_parameters() to return WSREP_FATAL. 77 | * 78 | * @param p parameter 79 | * @param context application context 80 | * 81 | * @return WSREP_OK on success, otherwise application failure 82 | */ 83 | typedef wsrep_status_t (*wsrep_get_parameters_cb) (const wsrep_parameter_t* p, 84 | void* context); 85 | 86 | /** 87 | * Get configuration parameters exposed by the provider. 88 | * 89 | * @param wsrep pointer to provider handle 90 | * @param cb function pointer for callback 91 | * @param context application context passed to callback 92 | * 93 | * @return WSREP_OK on success, WSREP_FATAL on failure 94 | */ 95 | typedef wsrep_status_t (*wsrep_get_parameters_fn) (wsrep_t* wsrep, 96 | wsrep_get_parameters_cb cb, 97 | void* context); 98 | 99 | /** 100 | * Config service struct. 101 | * 102 | * A pointer to this struct must be passed to the call to 103 | * wsrep_init_config_service_v1. 104 | */ 105 | typedef struct wsrep_config_service_v1_st { 106 | wsrep_get_parameters_fn get_parameters; 107 | } wsrep_config_service_v1_t; 108 | 109 | #ifdef __cplusplus 110 | } 111 | #endif 112 | 113 | #define WSREP_CONFIG_SERVICE_INIT_FUNC_V1 "wsrep_init_config_service_v1" 114 | #define WSREP_CONFIG_SERVICE_DEINIT_FUNC_V1 "wsrep_deinit_config_service_v1" 115 | 116 | #endif /* WSREP_CONFIG_SERVICE */ 117 | -------------------------------------------------------------------------------- /wsrep_connection_monitor_service.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024-2025 Codership Oy 3 | * 4 | * This file is part of wsrep-API. 5 | * 6 | * Wsrep-API is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * Wsrep-API is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with wsrep-API. If not, see . 18 | */ 19 | 20 | /** @file wsrep_connection_monitor_service.h 21 | * 22 | * This file defines interface for connection monitor service 23 | * 24 | * The provider which is capable of using the service interface v1 must 25 | * export the following functions. 26 | * 27 | * int wsrep_init_connection_monitor_service_v1(wsrep_connection_monitor_service_v1_t*) 28 | * void wsrep_deinit_connection_monitor_service_v1() 29 | * 30 | * which can be probed by the application. 31 | * 32 | * The application must initialize the service via above init function 33 | * before the provider is initialized via wsrep->init(). The deinit 34 | * function must be called after the provider side resources have been 35 | * released via wsrep->free(). 36 | */ 37 | 38 | #ifndef WSREP_CONNECTION_MONITOR_SERVICE_H 39 | #define WSREP_CONNECTION_MONITOR_SERVICE_H 40 | 41 | #include "wsrep_api.h" 42 | 43 | #ifdef __cplusplus 44 | extern "C" 45 | { 46 | #endif /* __cplusplus */ 47 | 48 | /** 49 | * Type tag for application defined connection monitoring processing context. 50 | * 51 | * Application may pass pointer to the context when initializing 52 | * the connection monitor service. This pointer is passed a first parameter for 53 | * each service call. 54 | */ 55 | typedef struct wsrep_connection_monitor_context wsrep_connection_monitor_context_t; 56 | 57 | typedef const void* wsrep_connection_key_t; 58 | 59 | /* 60 | * Connection monitor connection update callbacks. 61 | * 62 | */ 63 | 64 | /* 65 | * Connection connect callback. 66 | * 67 | * @param id connection identifier 68 | * @param scheme connection scheme (tcp, ssl) 69 | * @param local_address local address string 70 | * @param remote_address remote address string 71 | */ 72 | typedef void (*wsrep_connection_monitor_connect_cb_t)( 73 | wsrep_connection_monitor_context_t*, 74 | wsrep_connection_key_t id, 75 | const wsrep_buf_t* scheme, 76 | const wsrep_buf_t* local_address, 77 | const wsrep_buf_t* remote_address); 78 | 79 | /* 80 | * Connection disconnect callback. 81 | * 82 | * @param id connection identifier 83 | */ 84 | typedef void (*wsrep_connection_monitor_disconnect_cb_t)( 85 | wsrep_connection_monitor_context_t*, 86 | wsrep_connection_key_t id); 87 | 88 | /* 89 | * Connection SSL/TLS info callback. 90 | * 91 | * @param id connection identifier 92 | * @param cipher cipher suite name 93 | * @param certificate_subject certificate subject name 94 | * @param certificate_issuer certificate issuer name 95 | * @param version SSL/TLS version string 96 | */ 97 | typedef void (*wsrep_connection_monitor_ssl_info_cb_t)( 98 | wsrep_connection_monitor_context_t*, 99 | wsrep_connection_key_t id, 100 | const wsrep_buf_t* cipher, 101 | const wsrep_buf_t* certificate_subject, 102 | const wsrep_buf_t* certificate_issuer, 103 | const wsrep_buf_t* version); 104 | 105 | /** 106 | * Connection monitor service struct. 107 | * 108 | * A pointer to this struct must be passed to the call to 109 | * wsrep_init_connection_monitor_service_v1. 110 | * 111 | * The application must provide implementation to all functions defined 112 | * in this struct. 113 | */ 114 | typedef struct wsrep_connection_monitor_service_v1_st 115 | { 116 | /* Connection monitor connect callback */ 117 | wsrep_connection_monitor_connect_cb_t connection_monitor_connect_cb; 118 | /* Connection monitor disconnect callback */ 119 | wsrep_connection_monitor_disconnect_cb_t connection_monitor_disconnect_cb; 120 | /* Connection monitor ssl info callback */ 121 | wsrep_connection_monitor_ssl_info_cb_t connection_monitor_ssl_info_cb; 122 | /* Pointer to application defined connection monitor context. */ 123 | wsrep_connection_monitor_context_t* context; 124 | } wsrep_connection_monitor_service_v1_t; 125 | 126 | #ifdef __cplusplus 127 | } 128 | #endif /* __cplusplus */ 129 | 130 | 131 | #define WSREP_CONNECTION_MONITOR_SERVICE_INIT_FUNC_V1 "wsrep_init_connection_monitor_service_v1" 132 | #define WSREP_CONNECTION_MONITOR_SERVICE_DEINIT_FUNC_V1 "wsrep_deinit_connection_monitor_service_v1" 133 | 134 | #endif /* WSREP_CONNECTION_MONITOR_SERVICE_H */ 135 | -------------------------------------------------------------------------------- /wsrep_dummy.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2009-2010 Codership Oy 2 | 3 | This program is free software; you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation; version 2 of the License. 6 | 7 | This program is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | 12 | You should have received a copy of the GNU General Public License 13 | along with this program; if not, write to the Free Software 14 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | /*! @file Dummy wsrep API implementation. */ 18 | 19 | #include "wsrep_api.h" 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | /*! Dummy backend context. */ 26 | typedef struct wsrep_dummy 27 | { 28 | wsrep_log_cb_t log_fn; 29 | char* options; 30 | } wsrep_dummy_t; 31 | 32 | /* Get pointer to wsrep_dummy context from wsrep_t pointer */ 33 | #define WSREP_DUMMY(_p) ((wsrep_dummy_t *) (_p)->ctx) 34 | 35 | /* Trace function usage a-la DBUG */ 36 | #define WSREP_DBUG_ENTER(_w) do { \ 37 | if (WSREP_DUMMY(_w)) { \ 38 | if (WSREP_DUMMY(_w)->log_fn) \ 39 | WSREP_DUMMY(_w)->log_fn(WSREP_LOG_DEBUG, __FUNCTION__); \ 40 | } \ 41 | } while (0) 42 | 43 | 44 | static void dummy_free(wsrep_t *w) 45 | { 46 | if (!w->ctx) return; 47 | 48 | WSREP_DBUG_ENTER(w); 49 | if (WSREP_DUMMY(w)->options) { 50 | free(WSREP_DUMMY(w)->options); 51 | WSREP_DUMMY(w)->options = NULL; 52 | } 53 | free(w->ctx); 54 | w->ctx = NULL; 55 | } 56 | 57 | static wsrep_status_t dummy_init (wsrep_t* w, 58 | const struct wsrep_init_args* args) 59 | { 60 | WSREP_DUMMY(w)->log_fn = args->logger_cb; 61 | WSREP_DBUG_ENTER(w); 62 | if (args->options) { 63 | WSREP_DUMMY(w)->options = strdup(args->options); 64 | } 65 | return WSREP_OK; 66 | } 67 | 68 | static wsrep_cap_t dummy_capabilities (wsrep_t* w __attribute__((unused))) 69 | { 70 | return 0; 71 | } 72 | 73 | static wsrep_status_t dummy_options_set( 74 | wsrep_t* w, 75 | const char* conf) 76 | { 77 | WSREP_DBUG_ENTER(w); 78 | if (WSREP_DUMMY(w)->options) { 79 | free(WSREP_DUMMY(w)->options); 80 | WSREP_DUMMY(w)->options = NULL; 81 | } 82 | if (conf) { 83 | WSREP_DUMMY(w)->options = strdup(conf); 84 | } 85 | return WSREP_OK; 86 | } 87 | 88 | static char* dummy_options_get (wsrep_t* w) 89 | { 90 | WSREP_DBUG_ENTER(w); 91 | return strdup(WSREP_DUMMY(w)->options); 92 | } 93 | 94 | static wsrep_status_t dummy_enc_set_key( 95 | wsrep_t* w, 96 | const wsrep_enc_key_t* key __attribute__((unused))) 97 | { 98 | WSREP_DBUG_ENTER(w); 99 | return WSREP_OK; 100 | } 101 | 102 | static wsrep_status_t dummy_connect( 103 | wsrep_t* w, 104 | const char* name __attribute__((unused)), 105 | const char* url __attribute__((unused)), 106 | const char* donor __attribute__((unused)), 107 | wsrep_bool_t bootstrap __attribute__((unused))) 108 | { 109 | WSREP_DBUG_ENTER(w); 110 | return WSREP_OK; 111 | } 112 | 113 | static wsrep_status_t dummy_disconnect(wsrep_t* w) 114 | { 115 | WSREP_DBUG_ENTER(w); 116 | return WSREP_OK; 117 | } 118 | 119 | static wsrep_status_t dummy_recv(wsrep_t* w, 120 | void* recv_ctx __attribute__((unused))) 121 | { 122 | WSREP_DBUG_ENTER(w); 123 | return WSREP_OK; 124 | } 125 | 126 | static wsrep_status_t dummy_assign_read_view( 127 | wsrep_t* w, 128 | wsrep_ws_handle_t* ws_handle __attribute__((unused)), 129 | const wsrep_gtid_t* rv __attribute__((unused))) 130 | { 131 | WSREP_DBUG_ENTER(w); 132 | return WSREP_OK; 133 | } 134 | 135 | static wsrep_status_t dummy_certify( 136 | wsrep_t* w, 137 | const wsrep_conn_id_t conn_id __attribute__((unused)), 138 | wsrep_ws_handle_t* ws_handle __attribute__((unused)), 139 | uint32_t flags __attribute__((unused)), 140 | wsrep_trx_meta_t* meta __attribute__((unused))) 141 | { 142 | WSREP_DBUG_ENTER(w); 143 | return WSREP_OK; 144 | } 145 | 146 | static wsrep_status_t dummy_commit_order_enter( 147 | wsrep_t* w, 148 | const wsrep_ws_handle_t* ws_handle __attribute__((unused)), 149 | const wsrep_trx_meta_t* meta __attribute__((unused))) 150 | { 151 | WSREP_DBUG_ENTER(w); 152 | return WSREP_OK; 153 | } 154 | 155 | static wsrep_status_t dummy_commit_order_leave( 156 | wsrep_t* w, 157 | const wsrep_ws_handle_t* ws_handle __attribute__((unused)), 158 | const wsrep_trx_meta_t* meta __attribute__((unused)), 159 | const wsrep_buf_t* error __attribute__((unused))) 160 | { 161 | WSREP_DBUG_ENTER(w); 162 | return WSREP_OK; 163 | } 164 | 165 | static wsrep_status_t dummy_release( 166 | wsrep_t* w, 167 | wsrep_ws_handle_t* ws_handle __attribute__((unused))) 168 | { 169 | WSREP_DBUG_ENTER(w); 170 | return WSREP_OK; 171 | } 172 | 173 | static wsrep_status_t dummy_replay_trx( 174 | wsrep_t* w, 175 | const wsrep_ws_handle_t* ws_handle __attribute__((unused)), 176 | void* trx_ctx __attribute__((unused))) 177 | { 178 | WSREP_DBUG_ENTER(w); 179 | return WSREP_OK; 180 | } 181 | 182 | static wsrep_status_t dummy_abort_certification( 183 | wsrep_t* w, 184 | const wsrep_seqno_t bf_seqno __attribute__((unused)), 185 | const wsrep_trx_id_t trx_id __attribute__((unused)), 186 | wsrep_seqno_t *victim_seqno __attribute__((unused))) 187 | { 188 | WSREP_DBUG_ENTER(w); 189 | return WSREP_OK; 190 | } 191 | 192 | static wsrep_status_t dummy_rollback( 193 | wsrep_t* w, 194 | const wsrep_trx_id_t trx __attribute__((unused)), 195 | const wsrep_buf_t* data __attribute__((unused))) 196 | { 197 | WSREP_DBUG_ENTER(w); 198 | return WSREP_OK; 199 | } 200 | 201 | static wsrep_status_t dummy_append_key( 202 | wsrep_t* w, 203 | wsrep_ws_handle_t* ws_handle __attribute__((unused)), 204 | const wsrep_key_t* key __attribute__((unused)), 205 | const size_t key_num __attribute__((unused)), 206 | const wsrep_key_type_t key_type __attribute__((unused)), 207 | const bool copy __attribute__((unused))) 208 | { 209 | WSREP_DBUG_ENTER(w); 210 | return WSREP_OK; 211 | } 212 | 213 | static wsrep_status_t dummy_append_data( 214 | wsrep_t* w, 215 | wsrep_ws_handle_t* ws_handle __attribute__((unused)), 216 | const struct wsrep_buf* data __attribute__((unused)), 217 | const size_t count __attribute__((unused)), 218 | const wsrep_data_type_t type __attribute__((unused)), 219 | const bool copy __attribute__((unused))) 220 | { 221 | WSREP_DBUG_ENTER(w); 222 | return WSREP_OK; 223 | } 224 | 225 | static wsrep_status_t dummy_sync_wait( 226 | wsrep_t* w, 227 | wsrep_gtid_t* upto __attribute__((unused)), 228 | int tout __attribute__((unused)), 229 | wsrep_gtid_t* gtid __attribute__((unused))) 230 | { 231 | WSREP_DBUG_ENTER(w); 232 | return WSREP_OK; 233 | } 234 | 235 | static wsrep_status_t dummy_last_committed_id( 236 | wsrep_t* w, 237 | wsrep_gtid_t* gtid __attribute__((unused))) 238 | { 239 | WSREP_DBUG_ENTER(w); 240 | return WSREP_OK; 241 | } 242 | 243 | static wsrep_status_t dummy_free_connection( 244 | wsrep_t* w, 245 | const wsrep_conn_id_t conn_id __attribute__((unused))) 246 | { 247 | WSREP_DBUG_ENTER(w); 248 | return WSREP_OK; 249 | } 250 | 251 | static wsrep_status_t dummy_to_execute_start( 252 | wsrep_t* w, 253 | const wsrep_conn_id_t conn_id __attribute__((unused)), 254 | const wsrep_key_t* key __attribute__((unused)), 255 | const size_t key_num __attribute__((unused)), 256 | const struct wsrep_buf* data __attribute__((unused)), 257 | const size_t count __attribute__((unused)), 258 | const uint32_t flags __attribute__((unused)), 259 | wsrep_trx_meta_t* meta __attribute__((unused))) 260 | { 261 | WSREP_DBUG_ENTER(w); 262 | return WSREP_OK; 263 | } 264 | 265 | static wsrep_status_t dummy_to_execute_end( 266 | wsrep_t* w, 267 | const wsrep_conn_id_t conn_id __attribute__((unused)), 268 | const wsrep_buf_t* err __attribute__((unused))) 269 | { 270 | WSREP_DBUG_ENTER(w); 271 | return WSREP_OK; 272 | } 273 | 274 | static wsrep_status_t dummy_preordered_collect( 275 | wsrep_t* w, 276 | wsrep_po_handle_t* handle __attribute__((unused)), 277 | const struct wsrep_buf* data __attribute__((unused)), 278 | size_t count __attribute__((unused)), 279 | wsrep_bool_t copy __attribute__((unused))) 280 | { 281 | WSREP_DBUG_ENTER(w); 282 | return WSREP_OK; 283 | } 284 | 285 | static wsrep_status_t dummy_preordered_commit( 286 | wsrep_t* w, 287 | wsrep_po_handle_t* handle __attribute__((unused)), 288 | const wsrep_uuid_t* source_id __attribute__((unused)), 289 | uint32_t flags __attribute__((unused)), 290 | int pa_range __attribute__((unused)), 291 | wsrep_bool_t commit __attribute__((unused))) 292 | { 293 | WSREP_DBUG_ENTER(w); 294 | return WSREP_OK; 295 | } 296 | 297 | static wsrep_status_t dummy_sst_sent( 298 | wsrep_t* w, 299 | const wsrep_gtid_t* state_id __attribute__((unused)), 300 | const int rcode __attribute__((unused))) 301 | { 302 | WSREP_DBUG_ENTER(w); 303 | return WSREP_OK; 304 | } 305 | 306 | static wsrep_status_t dummy_sst_received( 307 | wsrep_t* w, 308 | const wsrep_gtid_t* state_id __attribute__((unused)), 309 | const wsrep_buf_t* state __attribute__((unused)), 310 | const int rcode __attribute__((unused))) 311 | { 312 | WSREP_DBUG_ENTER(w); 313 | return WSREP_OK; 314 | } 315 | 316 | static wsrep_status_t dummy_snapshot( 317 | wsrep_t* w, 318 | const wsrep_buf_t* msg __attribute__((unused)), 319 | const char* donor_spec __attribute__((unused))) 320 | { 321 | WSREP_DBUG_ENTER(w); 322 | return WSREP_OK; 323 | } 324 | 325 | static struct wsrep_stats_var dummy_stats[] = { 326 | { NULL, WSREP_VAR_STRING, { 0 } } 327 | }; 328 | 329 | static struct wsrep_stats_var* dummy_stats_get (wsrep_t* w) 330 | { 331 | WSREP_DBUG_ENTER(w); 332 | return dummy_stats; 333 | } 334 | 335 | static void dummy_stats_free ( 336 | wsrep_t* w, 337 | struct wsrep_stats_var* stats __attribute__((unused))) 338 | { 339 | WSREP_DBUG_ENTER(w); 340 | } 341 | 342 | static void dummy_stats_reset (wsrep_t* w) 343 | { 344 | WSREP_DBUG_ENTER(w); 345 | } 346 | 347 | static wsrep_seqno_t dummy_pause (wsrep_t* w) 348 | { 349 | WSREP_DBUG_ENTER(w); 350 | return -ENOSYS; 351 | } 352 | 353 | static wsrep_status_t dummy_resume (wsrep_t* w) 354 | { 355 | WSREP_DBUG_ENTER(w); 356 | return WSREP_OK; 357 | } 358 | 359 | static wsrep_status_t dummy_desync (wsrep_t* w) 360 | { 361 | WSREP_DBUG_ENTER(w); 362 | return WSREP_NOT_IMPLEMENTED; 363 | } 364 | 365 | static wsrep_status_t dummy_resync (wsrep_t* w) 366 | { 367 | WSREP_DBUG_ENTER(w); 368 | return WSREP_OK; 369 | } 370 | 371 | static wsrep_status_t dummy_lock (wsrep_t* w, 372 | const char* s __attribute__((unused)), 373 | bool r __attribute__((unused)), 374 | uint64_t o __attribute__((unused)), 375 | int64_t t __attribute__((unused))) 376 | { 377 | WSREP_DBUG_ENTER(w); 378 | return WSREP_NOT_IMPLEMENTED; 379 | } 380 | 381 | static wsrep_status_t dummy_unlock (wsrep_t* w, 382 | const char* s __attribute__((unused)), 383 | uint64_t o __attribute__((unused))) 384 | { 385 | WSREP_DBUG_ENTER(w); 386 | return WSREP_OK; 387 | } 388 | 389 | static bool dummy_is_locked (wsrep_t* w, 390 | const char* s __attribute__((unused)), 391 | uint64_t* o __attribute__((unused)), 392 | wsrep_uuid_t* t __attribute__((unused))) 393 | { 394 | WSREP_DBUG_ENTER(w); 395 | return false; 396 | } 397 | 398 | static wsrep_t dummy_iface = { 399 | WSREP_INTERFACE_VERSION, 400 | &dummy_init, 401 | &dummy_capabilities, 402 | &dummy_options_set, 403 | &dummy_options_get, 404 | &dummy_enc_set_key, 405 | &dummy_connect, 406 | &dummy_disconnect, 407 | &dummy_recv, 408 | &dummy_assign_read_view, 409 | &dummy_certify, 410 | &dummy_commit_order_enter, 411 | &dummy_commit_order_leave, 412 | &dummy_release, 413 | &dummy_replay_trx, 414 | &dummy_abort_certification, 415 | &dummy_rollback, 416 | &dummy_append_key, 417 | &dummy_append_data, 418 | &dummy_sync_wait, 419 | &dummy_last_committed_id, 420 | &dummy_free_connection, 421 | &dummy_to_execute_start, 422 | &dummy_to_execute_end, 423 | &dummy_preordered_collect, 424 | &dummy_preordered_commit, 425 | &dummy_sst_sent, 426 | &dummy_sst_received, 427 | &dummy_snapshot, 428 | &dummy_stats_get, 429 | &dummy_stats_free, 430 | &dummy_stats_reset, 431 | &dummy_pause, 432 | &dummy_resume, 433 | &dummy_desync, 434 | &dummy_resync, 435 | &dummy_lock, 436 | &dummy_unlock, 437 | &dummy_is_locked, 438 | WSREP_NONE, 439 | WSREP_INTERFACE_VERSION, 440 | "Codership Oy ", 441 | &dummy_free, 442 | NULL, 443 | NULL 444 | }; 445 | 446 | int wsrep_dummy_loader(wsrep_t* w) 447 | { 448 | if (!w) 449 | return EINVAL; 450 | 451 | *w = dummy_iface; 452 | 453 | // allocate private context 454 | if (!(w->ctx = malloc(sizeof(wsrep_dummy_t)))) 455 | return ENOMEM; 456 | 457 | // initialize private context 458 | WSREP_DUMMY(w)->log_fn = NULL; 459 | WSREP_DUMMY(w)->options = NULL; 460 | 461 | return 0; 462 | } 463 | -------------------------------------------------------------------------------- /wsrep_event_service.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Codership Oy 3 | * 4 | * This file is part of wsrep-API. 5 | * 6 | * Wsrep-API is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * Wsrep-API is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with wsrep-API. If not, see . 18 | */ 19 | 20 | /** @file wsrep_event_service.h 21 | * 22 | * This file defines interface for various unordered events generated by the 23 | * cluster or the provider. 24 | * 25 | * An event has a name and a payload, both are null-terminated strings. 26 | * (It is intended that payload is a JSON encoded structure). 27 | * The name serves to distinguish the events to pass them to respective 28 | * handlers. 29 | * 30 | * The provider which is capable of using the service interface v1 must 31 | * export the following functions. 32 | * 33 | * int wsrep_init_event_service_v1(wsrep_event_service_v1_t*) 34 | * void wsrep_deinit_event_service_v1() 35 | * 36 | * which can be probed by the application. 37 | * 38 | * The application must initialize the service via above init function 39 | * before the provider is initialized via wsrep->init(). The deinit 40 | * function must be called after the provider side resources have been 41 | * released via wsrep->free(). 42 | */ 43 | 44 | #ifndef WSREP_EVENT_SERVICE_H 45 | #define WSREP_EVENT_SERVICE_H 46 | 47 | #include "wsrep_api.h" 48 | 49 | #include /* posix size_t */ 50 | 51 | #ifdef __cplusplus 52 | extern "C" 53 | { 54 | #endif /* __cplusplus */ 55 | 56 | /** 57 | * Type tag for application defined event processing context. 58 | * 59 | * Application may pass pointer to the context when initializing 60 | * the event service. This pointer is passed a first parameter for 61 | * each service call. 62 | */ 63 | typedef struct wsrep_event_context wsrep_event_context_t; 64 | 65 | 66 | /** 67 | * Process an event 68 | * 69 | * @param name event name 70 | * @param value JSON enconded event value 71 | * 72 | * @return void, it is up to the receiver to decide what to do about 73 | * possible error. 74 | */ 75 | typedef void (*wsrep_event_cb_t)(wsrep_event_context_t*, 76 | const char* name, const char* value); 77 | 78 | 79 | /** 80 | * Event service struct. 81 | * 82 | * A pointer to this struct must be passed to the call to 83 | * wsrep_init_event_service_v1. 84 | * 85 | * The application must provide implementation to all functions defined 86 | * in this struct. 87 | */ 88 | typedef struct wsrep_event_service_v1_st 89 | { 90 | /* Event receiver callback */ 91 | wsrep_event_cb_t event_cb; 92 | /* Pointer to application defined event context. */ 93 | wsrep_event_context_t* context; 94 | } wsrep_event_service_v1_t; 95 | 96 | #ifdef __cplusplus 97 | } 98 | #endif /* __cplusplus */ 99 | 100 | 101 | #define WSREP_EVENT_SERVICE_INIT_FUNC_V1 "wsrep_init_event_service_v1" 102 | #define WSREP_EVENT_SERVICE_DEINIT_FUNC_V1 "wsrep_deinit_event_service_v1" 103 | 104 | #endif /* WSREP_EVENT_SERVICE_H */ 105 | 106 | -------------------------------------------------------------------------------- /wsrep_gtid.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2013 Codership Oy 2 | 3 | This program is free software; you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation; version 2 of the License. 6 | 7 | This program is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | 12 | You should have received a copy of the GNU General Public License 13 | along with this program; if not, write to the Free Software 14 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | /*! @file Helper functions to deal with GTID string representations */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "wsrep_api.h" 26 | 27 | /*! 28 | * Read GTID from string 29 | * @return length of GTID string representation or -EINVAL in case of error 30 | */ 31 | int 32 | wsrep_gtid_scan(const char* str, size_t str_len, wsrep_gtid_t* gtid) 33 | { 34 | int offset; 35 | char* endptr; 36 | if (str_len > INT_MAX) return -EINVAL; 37 | 38 | if ((offset = wsrep_uuid_scan(str, str_len, >id->uuid)) > 0 && 39 | offset < (int)str_len && str[offset] == ':') { 40 | ++offset; 41 | if (offset < (int)str_len) 42 | { 43 | errno = 0; 44 | gtid->seqno = strtoll(str + offset, &endptr, 0); 45 | 46 | if (errno == 0) { 47 | return (int)(endptr - str); 48 | } 49 | } 50 | } 51 | *gtid = WSREP_GTID_UNDEFINED; 52 | return -EINVAL; 53 | } 54 | 55 | /*! 56 | * Write GTID to string 57 | * @return length of GTID string representation or -EMSGSIZE if string is too 58 | * short 59 | */ 60 | int 61 | wsrep_gtid_print(const wsrep_gtid_t* gtid, char* str, size_t str_len) 62 | { 63 | int offset, ret; 64 | if (str_len > INT_MAX) return -EINVAL; 65 | 66 | if ((offset = wsrep_uuid_print(>id->uuid, str, str_len)) > 0) 67 | { 68 | ret = snprintf(str + offset, (size_t)((int)str_len - offset), 69 | ":%" PRId64, gtid->seqno); 70 | if (ret <= ((int)str_len - offset)) { 71 | return (offset + ret); 72 | } 73 | 74 | } 75 | 76 | return -EMSGSIZE; 77 | } 78 | -------------------------------------------------------------------------------- /wsrep_loader.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2009-2011 Codership Oy 2 | 3 | This program is free software; you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation; version 2 of the License. 6 | 7 | This program is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | 12 | You should have received a copy of the GNU General Public License 13 | along with this program; if not, write to the Free Software 14 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | /*! @file wsrep implementation loader */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "wsrep_api.h" 25 | 26 | // Logging stuff for the loader 27 | static const char* log_levels[] = {"FATAL", "ERROR", "WARN", "INFO", "DEBUG"}; 28 | 29 | static void default_logger (wsrep_log_level_t lvl, const char* msg) 30 | { 31 | fprintf (stderr, "wsrep loader: [%s] %s\n", log_levels[lvl], msg); 32 | } 33 | 34 | static wsrep_log_cb_t logger = default_logger; 35 | 36 | /************************************************************************** 37 | * Library loader 38 | **************************************************************************/ 39 | 40 | static int wsrep_check_iface_version(const char* found, const char* iface_ver) 41 | { 42 | const size_t msg_len = 128; 43 | char msg[128]; 44 | 45 | if (strcmp(found, iface_ver)) { 46 | snprintf (msg, msg_len, 47 | "provider interface version mismatch: need '%s', found '%s'", 48 | iface_ver, found); 49 | logger (WSREP_LOG_ERROR, msg); 50 | return EINVAL; 51 | } 52 | 53 | return 0; 54 | } 55 | 56 | static int verify(const wsrep_t *wh, const char *iface_ver) 57 | { 58 | char msg[128]; 59 | const size_t msg_len = sizeof(msg); 60 | 61 | #define VERIFY(_p) if (!(_p)) { \ 62 | snprintf(msg, msg_len, "wsrep_load(): verify(): %s\n", # _p); \ 63 | logger (WSREP_LOG_ERROR, msg); \ 64 | return EINVAL; \ 65 | } 66 | 67 | VERIFY(wh); 68 | VERIFY(wh->version); 69 | 70 | if (wsrep_check_iface_version(wh->version, iface_ver)) 71 | return EINVAL; 72 | 73 | VERIFY(wh->init); 74 | VERIFY(wh->options_set); 75 | VERIFY(wh->options_get); 76 | VERIFY(wh->enc_set_key); 77 | VERIFY(wh->connect); 78 | VERIFY(wh->disconnect); 79 | VERIFY(wh->recv); 80 | VERIFY(wh->assign_read_view); 81 | VERIFY(wh->certify); 82 | VERIFY(wh->commit_order_enter); 83 | VERIFY(wh->commit_order_leave); 84 | VERIFY(wh->release); 85 | VERIFY(wh->replay_trx); 86 | VERIFY(wh->abort_certification); 87 | VERIFY(wh->append_key); 88 | VERIFY(wh->append_data); 89 | VERIFY(wh->free_connection); 90 | VERIFY(wh->to_execute_start); 91 | VERIFY(wh->to_execute_end); 92 | VERIFY(wh->preordered_collect); 93 | VERIFY(wh->preordered_commit); 94 | VERIFY(wh->sst_sent); 95 | VERIFY(wh->sst_received); 96 | VERIFY(wh->stats_get); 97 | VERIFY(wh->stats_free); 98 | VERIFY(wh->stats_reset); 99 | VERIFY(wh->pause); 100 | VERIFY(wh->resume); 101 | VERIFY(wh->desync); 102 | VERIFY(wh->resync); 103 | VERIFY(wh->lock); 104 | VERIFY(wh->unlock); 105 | VERIFY(wh->is_locked); 106 | VERIFY(wh->provider_name); 107 | VERIFY(wh->provider_version); 108 | VERIFY(wh->provider_vendor); 109 | VERIFY(wh->free); 110 | return 0; 111 | } 112 | 113 | typedef int (*wsrep_loader_fun)(wsrep_t*); 114 | 115 | static wsrep_loader_fun wsrep_dlf(void *dlh, const char *sym) 116 | { 117 | union { 118 | wsrep_loader_fun dlfun; 119 | void *obj; 120 | } alias; 121 | alias.obj = dlsym(dlh, sym); 122 | return alias.dlfun; 123 | } 124 | 125 | static int wsrep_check_version_symbol(void *dlh) 126 | { 127 | char** dlversion = NULL; 128 | dlversion = (char**) dlsym(dlh, "wsrep_interface_version"); 129 | if (dlversion == NULL) 130 | return 0; 131 | return wsrep_check_iface_version(*dlversion, WSREP_INTERFACE_VERSION); 132 | } 133 | 134 | extern int wsrep_dummy_loader(wsrep_t *w); 135 | 136 | int wsrep_load(const char *spec, wsrep_t **hptr, wsrep_log_cb_t log_cb) 137 | { 138 | int ret = 0; 139 | void *dlh = NULL; 140 | wsrep_loader_fun dlfun; 141 | char msg[1024]; 142 | const size_t msg_len = sizeof(msg) - 1; 143 | msg[msg_len] = 0; 144 | 145 | if (NULL != log_cb) 146 | logger = log_cb; 147 | 148 | if (!(spec && hptr)) 149 | return EINVAL; 150 | 151 | snprintf (msg, msg_len, 152 | "wsrep_load(): loading provider library '%s'", spec); 153 | logger (WSREP_LOG_INFO, msg); 154 | 155 | if (!(*hptr = malloc(sizeof(wsrep_t)))) { 156 | logger (WSREP_LOG_FATAL, "wsrep_load(): out of memory"); 157 | return ENOMEM; 158 | } 159 | 160 | if (!spec || strcmp(spec, WSREP_NONE) == 0) { 161 | if ((ret = wsrep_dummy_loader(*hptr)) != 0) { 162 | free (*hptr); 163 | *hptr = NULL; 164 | } 165 | return ret; 166 | } 167 | 168 | int open_flags = RTLD_NOW | RTLD_LOCAL; 169 | #ifdef __SANITIZE_ADDRESS__ 170 | /* Keep the shared object to allow ASAN resolve symbols and report 171 | * memleaks. This also suppresses some false positives. */ 172 | open_flags |= RTLD_NODELETE; 173 | #endif /* __SANITIZE_ADDRESS__ */ 174 | 175 | if (!(dlh = dlopen(spec, open_flags))) { 176 | snprintf(msg, msg_len, "wsrep_load(): dlopen(): %s", dlerror()); 177 | logger (WSREP_LOG_ERROR, msg); 178 | ret = EINVAL; 179 | goto out; 180 | } 181 | 182 | if (!(dlfun = wsrep_dlf(dlh, "wsrep_loader"))) { 183 | ret = EINVAL; 184 | goto out; 185 | } 186 | 187 | if (wsrep_check_version_symbol(dlh) != 0) { 188 | ret = EINVAL; 189 | goto out; 190 | } 191 | 192 | if ((ret = (*dlfun)(*hptr)) != 0) { 193 | snprintf(msg, msg_len, "wsrep_load(): loader failed: %s", 194 | strerror(ret)); 195 | logger (WSREP_LOG_ERROR, msg); 196 | goto out; 197 | } 198 | 199 | if ((ret = verify(*hptr, WSREP_INTERFACE_VERSION)) != 0) { 200 | snprintf (msg, msg_len, 201 | "wsrep_load(): interface version mismatch: my version %s, " 202 | "provider version %s", WSREP_INTERFACE_VERSION, 203 | (*hptr)->version); 204 | logger (WSREP_LOG_ERROR, msg); 205 | goto out; 206 | } 207 | 208 | (*hptr)->dlh = dlh; 209 | 210 | out: 211 | if (ret != 0) { 212 | if (dlh) dlclose(dlh); 213 | free(*hptr); 214 | *hptr = NULL; 215 | } else { 216 | snprintf (msg, msg_len, 217 | "wsrep_load(): %s %s by %s loaded successfully.", 218 | (*hptr)->provider_name, (*hptr)->provider_version, 219 | (*hptr)->provider_vendor); 220 | logger (WSREP_LOG_INFO, msg); 221 | } 222 | 223 | return ret; 224 | } 225 | 226 | void wsrep_unload(wsrep_t *hptr) 227 | { 228 | if (!hptr) { 229 | logger (WSREP_LOG_WARN, "wsrep_unload(): null pointer."); 230 | } else { 231 | if (hptr->free) 232 | hptr->free(hptr); 233 | if (hptr->dlh) 234 | { 235 | int err; 236 | if ((err = dlclose(hptr->dlh))) 237 | { 238 | char msg[1024]; 239 | snprintf(msg, sizeof(msg), "dlclose(): %s", dlerror()); 240 | msg[sizeof(msg) - 1] = '\0'; 241 | logger(WSREP_LOG_WARN, msg); 242 | } 243 | } 244 | free(hptr); 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /wsrep_membership_service.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 Codership Oy 3 | * 4 | * This file is part of wsrep-API. 5 | * 6 | * Wsrep-API is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * Wsrep-API is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with wsrep-API. If not, see . 18 | */ 19 | 20 | /** @file wsrep_membership_service.h 21 | * 22 | * This file defines interface for quering the immediate membership and 23 | * members' states of the current configuration. The information is provided 24 | * OUT OF ORDER to facilitate administrative tasks. 25 | * 26 | * The provider which is capable of using the service interface v1 must 27 | * export the following functions. 28 | * 29 | * int wsrep_init_membership_service_v1(struct wsrep_membership_service_v1*) 30 | * void wsrep_deinit_membership_service_v1() 31 | * 32 | * which can be probed by the application. 33 | * 34 | * The application must initialize the service via above init function 35 | * before the provider is initialized via wsrep->init(). The deinit 36 | * function must be called after the provider side resources have been 37 | * released via wsrep->free(). 38 | */ 39 | 40 | #ifndef WSREP_MEMBERSHIP_SERVICE_H 41 | #define WSREP_MEMBERSHIP_SERVICE_H 42 | 43 | #include "wsrep_api.h" 44 | 45 | #ifdef __cplusplus 46 | extern "C" 47 | { 48 | #endif /* __cplusplus */ 49 | 50 | /** 51 | * Member info structure extended to contain member state 52 | */ 53 | struct wsrep_member_info_ext 54 | { 55 | struct wsrep_member_info base; 56 | wsrep_seqno_t last_committed; 57 | enum wsrep_member_status status; 58 | }; 59 | 60 | /** 61 | * Extended membership structure 62 | */ 63 | struct wsrep_membership 64 | { 65 | /** 66 | * Epoch of the membership data (last time it was updated) 67 | */ 68 | wsrep_uuid_t group_uuid; 69 | /** 70 | * Sequence number of the last received (not processed) action 71 | */ 72 | wsrep_seqno_t last_received; 73 | /** 74 | * When the members' data was last updated 75 | */ 76 | wsrep_seqno_t updated; 77 | /** 78 | * Current group state 79 | */ 80 | enum wsrep_view_status state; 81 | /** 82 | * Number of members in the array 83 | */ 84 | size_t num; 85 | /** 86 | * Membership array 87 | */ 88 | struct wsrep_member_info_ext members[1]; 89 | }; 90 | 91 | /** 92 | * Member info structure extended to contain member state and flags 93 | */ 94 | struct wsrep_member_info_ext_v2 95 | { 96 | struct wsrep_member_info base; 97 | wsrep_seqno_t last_committed; 98 | enum wsrep_member_status status; 99 | uint8_t flags; 100 | }; 101 | 102 | /* Member flags */ 103 | #define WSREP_MEMBER_FLAGS_REP 0x01 // group representative 104 | #define WSREP_MEMBER_FLAGS_CLA 0x02 // count last applied (for JOINED node) 105 | #define WSREP_MEMBER_FLAGS_BOOTSTRAP 0x04 // part of prim bootstrap process 106 | #define WSREP_MEMBER_FLAGS_STATELESS 0x08 // arbitrator or otherwise stateless node 107 | 108 | /** 109 | * Extended membership structure v2 110 | */ 111 | struct wsrep_membership_v2 112 | { 113 | /** 114 | * Epoch of the membership data (last time it was updated) 115 | */ 116 | wsrep_uuid_t group_uuid; 117 | /** 118 | * Sequence number of the last received (not processed) action 119 | */ 120 | wsrep_seqno_t last_received; 121 | /** 122 | * When the members' data was last updated 123 | */ 124 | wsrep_seqno_t updated; 125 | /** 126 | * Current group state 127 | */ 128 | enum wsrep_view_status state; 129 | /** 130 | * Number of members in the array 131 | */ 132 | size_t num; 133 | /** 134 | * Membership array 135 | */ 136 | struct wsrep_member_info_ext_v2 members[1]; 137 | }; 138 | 139 | /** 140 | * Memory allocation callback for wsrep_get_mmebership_fn() below 141 | * 142 | * @param size of buffer to allocate 143 | * @return allocated buffer pointer or NULL in case of error 144 | */ 145 | typedef void* (*wsrep_allocator_cb) (size_t size); 146 | 147 | /** 148 | * Query membership 149 | * 150 | * @param wsrep provider handle 151 | * @param allocator to use for wsrep_membership struct allocation 152 | * @param membership pointer to pointer to the memebrship structure. 153 | * The structure is allocated by provider and must be freed 154 | * by the caller. 155 | * @return error code of the call 156 | */ 157 | typedef wsrep_status_t (*wsrep_get_membership_fn) ( 158 | wsrep_t* wsrep, 159 | wsrep_allocator_cb allocator, 160 | struct wsrep_membership** membership); 161 | 162 | /** 163 | * Query membership v2 164 | * 165 | * @param wsrep provider handle 166 | * @param allocator to use for wsrep_membership struct allocation 167 | * @param membership pointer to pointer to the memebrship structure. 168 | * The structure is allocated by provider and must be freed 169 | * by the caller. 170 | * @return error code of the call 171 | */ 172 | typedef wsrep_status_t (*wsrep_get_membership_v2_fn) ( 173 | wsrep_t* wsrep, 174 | wsrep_allocator_cb allocator, 175 | struct wsrep_membership_v2** membership); 176 | 177 | /** 178 | * Membership service struct. 179 | * Returned by WSREP_MEMBERSHIP_SERVICE_INIT_FUNC_V1 180 | */ 181 | struct wsrep_membership_service_v1 182 | { 183 | wsrep_get_membership_fn get_membership; 184 | }; 185 | 186 | /** 187 | * Membership service struct. 188 | * Returned by WSREP_MEMBERSHIP_SERVICE_INIT_FUNC_V2 189 | */ 190 | struct wsrep_membership_service_v2 191 | { 192 | wsrep_get_membership_v2_fn get_membership; 193 | }; 194 | 195 | #ifdef __cplusplus 196 | } 197 | #endif /* __cplusplus */ 198 | 199 | typedef 200 | wsrep_status_t 201 | (*wsrep_membership_service_v1_init_fn) (struct wsrep_membership_service_v1*); 202 | typedef 203 | void 204 | (*wsrep_membership_service_v1_deinit_fn)(void); 205 | 206 | typedef 207 | wsrep_status_t 208 | (*wsrep_membership_service_v2_init_fn) (struct wsrep_membership_service_v2*); 209 | typedef 210 | void 211 | (*wsrep_membership_service_v2_deinit_fn)(void); 212 | 213 | /** must be exported by the provider */ 214 | #define WSREP_MEMBERSHIP_SERVICE_V1_INIT_FN "wsrep_init_membership_service_v1" 215 | #define WSREP_MEMBERSHIP_SERVICE_V1_DEINIT_FN "wsrep_deinit_membership_service_v1" 216 | #define WSREP_MEMBERSHIP_SERVICE_V2_INIT_FN "wsrep_init_membership_service_v2" 217 | #define WSREP_MEMBERSHIP_SERVICE_V2_DEINIT_FN "wsrep_deinit_membership_service_v2" 218 | 219 | #endif /* WSREP_MEMBERSHIP_SERVICE_H */ 220 | -------------------------------------------------------------------------------- /wsrep_node_isolation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Codership Oy 3 | * 4 | * This file is part of wsrep-API. 5 | * 6 | * Wsrep-API is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * Wsrep-API is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with wsrep-API. If not, see . 18 | */ 19 | 20 | #ifndef WSREP_NODE_ISOLATION_H 21 | #define WSREP_NODE_ISOLATION_H 22 | 23 | /** @file wsrep_node_isolation.h 24 | * 25 | * This file defines and interface to isolate the node from 26 | * the rest of the cluster. The purpose of isolation is to shut 27 | * down all communication with the rest of the cluster in case 28 | * of node failure where the node cannot continue reliably anymore, 29 | * e.g. in case of handling a signal which will terminate the process. 30 | */ 31 | 32 | /** 33 | * Mode of node isolation. 34 | */ 35 | enum wsrep_node_isolation_mode 36 | { 37 | /** Node is not isolated. */ 38 | WSREP_NODE_ISOLATION_NOT_ISOLATED, 39 | /** Node is isolated from the rest of the cluster on network 40 | * level. All ongoing network connections will be terminated and 41 | * no new connections are accepted. */ 42 | WSREP_NODE_ISOLATION_ISOLATED, 43 | /** As WSREP_NODE_ISOLATION_ON, but also force the provider 44 | * to deliver view with status WSREP_VIEW_DISCONNECTED. */ 45 | WSREP_NODE_ISOLATION_FORCE_DISCONNECT, 46 | }; 47 | 48 | enum wsrep_node_isolation_result 49 | { 50 | /** Setting the isolation mode was successful. */ 51 | WSREP_NODE_ISOLATION_SUCCESS, 52 | /** Invalid isolation mode was passed. */ 53 | WSREP_NODE_ISOLATION_INVALID_VALUE 54 | }; 55 | 56 | /** Set mode isolation mode according to give wsrep_node_isolation_mode 57 | * enum. 58 | * 59 | * The implementation must be async signal safe to allow calling 60 | * it from program signal handler. 61 | * 62 | * @param mode Mode to set. 63 | * @return wsrep_node_isolation_result enum. 64 | */ 65 | typedef enum wsrep_node_isolation_result (*wsrep_node_isolation_mode_set_fn_v1)( 66 | enum wsrep_node_isolation_mode mode); 67 | 68 | #define WSREP_NODE_ISOLATION_MODE_SET_V1 "wsrep_node_isolation_mode_set_v1" 69 | 70 | #endif /* WSREP_NODE_ISOLATION_H */ 71 | -------------------------------------------------------------------------------- /wsrep_thread_service.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 Codership Oy 3 | * 4 | * This file is part of wsrep-API. 5 | * 6 | * Wsrep-API is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * Wsrep-API is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with wsrep-API. If not, see . 18 | */ 19 | 20 | /** @file wsrep_thread_service.h 21 | * 22 | * Service interface for threads, mutexes and condition variables. 23 | * The application which may provide callbacks to routines which will 24 | * be used to manage lifetime and use threads and sycnronization primitives. 25 | * 26 | * The type tags and interface methods are loosely modeled after POSIX 27 | * threading interface. 28 | * 29 | * The application must either none or all of the callbacks defined in 30 | * wsrep_thread_service structure which is defined below. 31 | * 32 | * The error codes returned by the callbacks are generally assumed to 33 | * the system error numbers defined in errno.h unless stated otherwise. 34 | * 35 | * The provider must implement and export the following functions 36 | * to provide initialization point for the service implementation: 37 | * 38 | * Version 1: 39 | * int wsrep_init_thread_service_v1(wsrep_thread_service_v1_t*) 40 | * void wsrep_deinit_thread_service_v1(). 41 | * 42 | * The application defined implementation must be initialized before 43 | * calling the provider initialization function via wsrep->init(). The 44 | * deinitialization must be done via deinit function after the 45 | * provider side resources have been released via wsrep->free(). 46 | */ 47 | 48 | #ifndef WSREP_THREAD_SERVICE_H 49 | #define WSREP_THREAD_SERVICE_H 50 | 51 | #include /* size_t */ 52 | 53 | #ifdef __cplusplus 54 | extern "C" 55 | { 56 | #endif /* __cplusplus */ 57 | 58 | /* Forward declarations */ 59 | struct timespec; 60 | struct sched_param; 61 | 62 | /** Thread type tags */ 63 | typedef struct wsrep_thread_key_st wsrep_thread_key_t; 64 | typedef struct wsrep_thread_st wsrep_thread_t; 65 | /** Mutex type tags */ 66 | typedef struct wsrep_mutex_key_st wsrep_mutex_key_t; 67 | typedef struct wsrep_mutex_st wsrep_mutex_t; 68 | /** Condition variable tags */ 69 | typedef struct wsrep_cond_key_st wsrep_cond_key_t; 70 | typedef struct wsrep_cond_st wsrep_cond_t; 71 | 72 | /** 73 | * Create key for a thread with a name. This key object will be passed 74 | * to thread creation and destrunction notification callbacks. 75 | * 76 | * @param name Name of the thread. 77 | */ 78 | typedef const wsrep_thread_key_t* (*wsrep_thread_key_create_cb_t)( 79 | const char* name); 80 | 81 | /** 82 | * Create a new thread. 83 | * 84 | * @param[out] thread Newly allocated thread. 85 | * @param key Key created by wsrep_thread_key_create_cb_t 86 | * @param start_fn Pointer to start routine 87 | * @param arg Argument for start_fn 88 | * 89 | * @return Zero in case of success, non-zero error code in case of failure. 90 | */ 91 | typedef int (*wsrep_thread_create_cb_t)(const wsrep_thread_key_t* key, 92 | wsrep_thread_t** thread, 93 | void* (*start_fn)(void*), 94 | void* arg); 95 | 96 | /** 97 | * Detach a thread. 98 | * 99 | * @param thread Thread to be detached. 100 | * 101 | * @return Zero in case of error, non-zero error code in case of failure. 102 | */ 103 | typedef int (*wsrep_thread_detach_cb_t)(wsrep_thread_t* thread); 104 | 105 | /** 106 | * Compare two threads for equality. 107 | * 108 | * @params t1, t2 Threads to be compared. 109 | * 110 | * @return Non-zero value if threads are equal, zero otherwise. 111 | */ 112 | typedef int (*wsrep_thread_equal_cb_t)(wsrep_thread_t* t1, 113 | wsrep_thread_t* t2); 114 | 115 | /** 116 | * Terminate the calling thread. 117 | * 118 | * @param thread Pointer to thread. 119 | * @param retval Pointer to return value. 120 | * 121 | * This function does not return. 122 | */ 123 | typedef void __attribute__((noreturn)) (*wsrep_thread_exit_cb_t)( 124 | wsrep_thread_t* thread, void* retval); 125 | 126 | /** 127 | * Join a thread. Trying to join detached thread may cause undefined 128 | * behavior. 129 | * 130 | * @param thread Thread to be joined. 131 | * @param[out] retval Return value from the thread wthat was joined. 132 | * 133 | * @return Zero in case of success, non-zero error code in case of error. 134 | */ 135 | typedef int (*wsrep_thread_join_cb_t)(wsrep_thread_t* thread, 136 | void** retval); 137 | 138 | /** 139 | * Return a pointer to the wsrep_thread_t of the calling thread. 140 | * 141 | * @return Pointer to wsrep_thread_t associated with current thread. 142 | */ 143 | typedef wsrep_thread_t* (*wsrep_thread_self_cb_t)(void); 144 | 145 | /** 146 | * Set the scheduling policy for the thread. 147 | * 148 | * @param thread Thread for which sceduing policy should be changed. 149 | * @param policy New scheduling policy for the thread. 150 | * @param param New scheduling parameters for the thread. 151 | */ 152 | typedef int (*wsrep_thread_setschedparam_cb_t)( 153 | wsrep_thread_t* thread, int policy, const struct sched_param* param); 154 | 155 | /** 156 | * Get the current scheduling policy for the thread. 157 | * 158 | * @param thread Thread. 159 | * @param policy Pointer to location where the scheduling policy will 160 | * will be stored in. 161 | * @param Param Pointer to location where the current scheduling 162 | * parameters will be stored. 163 | */ 164 | typedef int (*wsrep_thread_getschedparam_cb_t)(wsrep_thread_t* thread, 165 | int* policy, 166 | struct sched_param* param); 167 | /** 168 | * Create key for a mutex with a name. This key object must be passed 169 | * to mutex creation callback. 170 | * 171 | * @param name Name of the mutex. 172 | * 173 | * @return Const pointer to mutex key. 174 | */ 175 | typedef const wsrep_mutex_key_t* (*wsrep_mutex_key_create_cb_t)( 176 | const char* name); 177 | 178 | /** 179 | * Create a mutex. 180 | * 181 | * @param key Mutex key obtained via wsrep_mutex_key_create_cb call. 182 | * @param memblock Optional memory block allocated by the provider 183 | * which can be used by the implementation to store 184 | * the mutex. 185 | * @param memblock_size Size of the optional memory block. 186 | * 187 | * @return Pointer to wsrep_mutex_t object or NULL in case of failure. 188 | */ 189 | typedef wsrep_mutex_t* (*wsrep_mutex_init_cb_t)( 190 | const wsrep_mutex_key_t* key, void* memblock, size_t memblock_size); 191 | 192 | /** 193 | * Destroy a mutex. This call must consume the mutex object. 194 | * 195 | * @param mutex Mutex to be destroyed. 196 | */ 197 | typedef int (*wsrep_mutex_destroy_cb_t)(wsrep_mutex_t* mutex); 198 | 199 | /** 200 | * Lock a mutex. 201 | * 202 | * @param mutex Mutex to be locked. 203 | * 204 | * @return Zero on success, non-zero error code on error. 205 | */ 206 | typedef int (*wsrep_mutex_lock_cb_t)(wsrep_mutex_t* mutex); 207 | 208 | /** 209 | * Try to lock a mutex. 210 | * 211 | * @param Mutex to be locked. 212 | * 213 | * @return Zero if mutex was successfully locked. 214 | * @return EBUSY if the mutex could not be acquired because it was already 215 | * locked. 216 | * @return Non-zero error code on any other error. 217 | */ 218 | typedef int (*wsrep_mutex_trylock_cb_t)(wsrep_mutex_t* mutex); 219 | 220 | /** 221 | * Unlock a mutex. 222 | * 223 | * @param mutex Mutex to be unlocked. 224 | * 225 | * @return Zero on success, non-zero on error. 226 | */ 227 | typedef int (*wsrep_mutex_unlock_cb_t)(wsrep_mutex_t* mutex); 228 | 229 | /** 230 | * Create key for a condition variable with a name. This key 231 | * must be passed to wsrep_cond_create_cb when creating a new 232 | * condition variable. 233 | * 234 | * @param name Name of the condition variable. 235 | * 236 | * @return Allocated key object. 237 | */ 238 | typedef const wsrep_cond_key_t* (*wsrep_cond_key_create_cb_t)( 239 | const char* name); 240 | 241 | /** 242 | * Create a new condition variable. 243 | * 244 | * @param key Const pointer to key object created by 245 | * wsrep_cond_key_create_cb. 246 | * @param memblock Optional memory block allocated by the provider 247 | * which can be used by the implementation to store 248 | * the mutex. 249 | * @param memblock_size Size of the optional memory block. 250 | * 251 | * @return Pointer to new condition variable. 252 | */ 253 | typedef wsrep_cond_t* (*wsrep_cond_init_cb_t)(const wsrep_cond_key_t* key, 254 | void* memblock, 255 | size_t memblock_size); 256 | 257 | /** 258 | * Destroy a condition variable. This call must consume the condition 259 | * variable object. 260 | * 261 | * @param cond Condition variable to be destroyed. 262 | * 263 | * @return Zero on success, non-zero on error. 264 | */ 265 | typedef int (*wsrep_cond_destroy_cb_t)(wsrep_cond_t* cond); 266 | 267 | /** 268 | * Wait for condition. 269 | * 270 | * @param cond Condition variable to wait for. 271 | * @param mutex Mutex associated to the condition variable. The mutex 272 | * may be unlocked for the duration of the wait. 273 | * 274 | * @return Zero on success, non-zero on error. 275 | */ 276 | typedef int (*wsrep_cond_wait_cb_t)(wsrep_cond_t* cond, 277 | wsrep_mutex_t* mutex); 278 | 279 | /** 280 | * Perform timed wait on condition. 281 | * 282 | * @param cond Condition to wait for. 283 | * @param mutex Mutex associated to the condition variable. The mutex 284 | * may be unlocked for the duration of the wait. 285 | * @param wait_until System time to wait until before returning from the 286 | * the timed wait. 287 | * 288 | * @return Zero on success. 289 | * @return ETIMEDOUT if the time specified by wait_until has passed. 290 | * @return Non-zero error code on other error. 291 | */ 292 | typedef int (*wsrep_cond_timedwait_cb_t)(wsrep_cond_t* cond, 293 | wsrep_mutex_t* mutex, 294 | const struct timespec* wait_until); 295 | 296 | /** 297 | * Signal a condition variable. This will wake up at least one of 298 | * the threads which is waiting for the condition. 299 | * 300 | * @param cond Condition variable to signal. 301 | * 302 | * @return Zero on success, non-zero on failure. 303 | */ 304 | typedef int (*wsrep_cond_signal_cb_t)(wsrep_cond_t* cond); 305 | 306 | /** 307 | * Broadcast a signal to condition variable. This will wake up 308 | * all the threads which are currently waiting on condition variable. 309 | * 310 | * @param cond Condition variable to broadcast the signal to. 311 | * 312 | * @return Zero on success, non-zero on failure. 313 | */ 314 | typedef int (*wsrep_cond_broadcast_cb_t)(wsrep_cond_t* cond); 315 | 316 | typedef struct wsrep_thread_service_v1_st 317 | { 318 | /* Threads */ 319 | wsrep_thread_key_create_cb_t thread_key_create_cb; 320 | wsrep_thread_create_cb_t thread_create_cb; 321 | wsrep_thread_detach_cb_t thread_detach_cb; 322 | wsrep_thread_equal_cb_t thread_equal_cb; 323 | wsrep_thread_exit_cb_t thread_exit_cb; 324 | wsrep_thread_join_cb_t thread_join_cb; 325 | wsrep_thread_self_cb_t thread_self_cb; 326 | wsrep_thread_setschedparam_cb_t thread_setschedparam_cb; 327 | wsrep_thread_getschedparam_cb_t thread_getschedparam_cb; 328 | /* Mutexes */ 329 | wsrep_mutex_key_create_cb_t mutex_key_create_cb; 330 | wsrep_mutex_init_cb_t mutex_init_cb; 331 | wsrep_mutex_destroy_cb_t mutex_destroy_cb; 332 | wsrep_mutex_lock_cb_t mutex_lock_cb; 333 | wsrep_mutex_trylock_cb_t mutex_trylock_cb; 334 | wsrep_mutex_unlock_cb_t mutex_unlock_cb; 335 | /* Condition variables */ 336 | wsrep_cond_key_create_cb_t cond_key_create_cb; 337 | wsrep_cond_init_cb_t cond_init_cb; 338 | wsrep_cond_destroy_cb_t cond_destroy_cb; 339 | wsrep_cond_wait_cb_t cond_wait_cb; 340 | wsrep_cond_timedwait_cb_t cond_timedwait_cb; 341 | wsrep_cond_signal_cb_t cond_signal_cb; 342 | wsrep_cond_broadcast_cb_t cond_broadcast_cb; 343 | } wsrep_thread_service_v1_t; 344 | 345 | #ifdef __cplusplus 346 | } 347 | 348 | #define WSREP_THREAD_SERVICE_INIT_FUNC_V1 "wsrep_init_thread_service_v1" 349 | #define WSREP_THREAD_SERVICE_DEINIT_FUNC_V1 "wsrep_deinit_thread_service_v1" 350 | 351 | /* For backwards compatibility. */ 352 | #define WSREP_THREAD_SERVICE_INIT_FUNC WSREP_THREAD_SERVICE_INIT_FUNC_V1 353 | 354 | #endif /* __cplusplus */ 355 | #endif /* WSREP_THREAD_SERVICE_H */ 356 | -------------------------------------------------------------------------------- /wsrep_tls_service.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Codership Oy 3 | * 4 | * This file is part of wsrep-API. 5 | * 6 | * Wsrep-API is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * Wsrep-API is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with wsrep-API. If not, see . 18 | */ 19 | 20 | /** @file wsrep_tls_service.h 21 | * 22 | * This file defines interface for TLS services provided by the application, 23 | * used by the provider. 24 | * 25 | * In order to support both synchronous and asynchronous IO operations, 26 | * the interface is designed to work with sockets in both blocking 27 | * and non-blockig mode. 28 | * 29 | * The provider is in charge of opening and closing file 30 | * descriptors and connecting transport. After the connection has 31 | * been established, all further IO operations will be delegated 32 | * to the TLS service implementation which is provided by the application. 33 | * 34 | * The provider which is capable of using the service interface v1 must 35 | * export the following functions. 36 | * 37 | * int wsrep_init_tls_service_v1(wsrep_tls_service_v1_t*) 38 | * void wsrep_deinit_tls_service_v1() 39 | * 40 | * which can be probed by the application. 41 | * 42 | * The application must initialize the service via above init function 43 | * before the provider is initialized via wsrep->init(). The deinit 44 | * function must be called after the provider side resources have been 45 | * released via wsrep->free(). 46 | */ 47 | 48 | #ifndef WSREP_TLS_SERVICE_H 49 | #define WSREP_TLS_SERVICE_H 50 | 51 | #include /* posix size_t */ 52 | 53 | #ifdef __cplusplus 54 | extern "C" 55 | { 56 | #endif /* __cplusplus */ 57 | 58 | /** 59 | * Type tag for application defined TLS context. 60 | * 61 | * Application may pass pointer to the context when initializing 62 | * TLS service. This pointer is passed a first parameter for 63 | * each service call. 64 | */ 65 | typedef struct wsrep_tls_context wsrep_tls_context_t; 66 | 67 | /** 68 | * TLS stream structure. 69 | */ 70 | typedef struct wsrep_tls_stream_st 71 | { 72 | /** 73 | * File descriptor corresponding to the stream. The provider is 74 | * responsible in opening and closing the socket. 75 | */ 76 | int fd; 77 | /** 78 | * Opaque pointer reserved for application use. 79 | */ 80 | void* opaque; 81 | } wsrep_tls_stream_t; 82 | 83 | /** 84 | * Enumeration for return codes. 85 | */ 86 | enum wsrep_tls_result 87 | { 88 | /** 89 | * The operation completed successfully, no further actions 90 | * are necessary. 91 | */ 92 | wsrep_tls_result_success = 0, 93 | /** 94 | * The operation completed successfully, but the application side wants 95 | * to make further reads. The provider must wait until the stream 96 | * becomes readable and then try the same operation again. 97 | */ 98 | wsrep_tls_result_want_read, 99 | /** 100 | * The operation completed successfully, but the application side wants 101 | * to make further writes. The provider must wait until the stream 102 | * becomes writable and then try the same operation again. 103 | */ 104 | wsrep_tls_result_want_write, 105 | /** 106 | * End of file was read from the stream. This result is needed to 107 | * make difference between graceful stream shutdown and zero length 108 | * reads which result from errors. 109 | */ 110 | wsrep_tls_result_eof, 111 | /** 112 | * An error occurred. The specific error reason must be 113 | * queried with wsrep_tls_stream_get_error_number and 114 | * wsrep_tls_stream_get_error_category. 115 | */ 116 | wsrep_tls_result_error 117 | }; 118 | 119 | /** 120 | * Initialize a new TLS stream. 121 | * 122 | * Initialize the stream for IO operations. During this call the 123 | * application must set up all of the data structures needed for 124 | * IO, but must not do any reads or writes into the stream yet. 125 | * 126 | * @param stream TLS stream to be initialized. 127 | * 128 | * @return Zero on success, system error number on error. 129 | */ 130 | typedef int (*wsrep_tls_stream_init_t)(wsrep_tls_context_t*, 131 | wsrep_tls_stream_t* stream); 132 | 133 | /** 134 | * Deinitialize the TLS stream. 135 | * 136 | * Deinitialize the TLS stream and free all allocated resources. 137 | * Note that this function must not close the socket file descriptor 138 | * associated the the stream. 139 | * 140 | * @param stream Stream to be deinitialized. 141 | */ 142 | typedef void (*wsrep_tls_stream_deinit_t)(wsrep_tls_context_t*, 143 | wsrep_tls_stream_t* stream); 144 | 145 | /** 146 | * Get error number of the last stream error. The error numbers are 147 | * defined by the application and must be integral type. By the convention 148 | * zero value must denote success. 149 | * 150 | * For managing errors other than system errors, the application may 151 | * provide several error categories via wsrep_tls_stream_get_error_category_t. 152 | * 153 | * @param stream TLS stream to get the last error from. 154 | * 155 | * @return Error number. 156 | */ 157 | typedef int (*wsrep_tls_stream_get_error_number_t)( 158 | wsrep_tls_context_t*, 159 | const wsrep_tls_stream_t* stream); 160 | 161 | /** 162 | * Get the error category of the last stream error. 163 | * 164 | * The category is represented via a const void pointer to the provider. 165 | * If the category is NULL pointer, the error number is assumed to be 166 | * system error. 167 | * 168 | * @param stream Stream to get last error category from. 169 | * 170 | * @return Pointer to error category. 171 | */ 172 | typedef const void* (*wsrep_tls_stream_get_error_category_t)( 173 | wsrep_tls_context_t*, 174 | const wsrep_tls_stream_t* stream); 175 | 176 | /** 177 | * Return human readable error message by error number and error 178 | * category. 179 | * 180 | * The message string returned by the application must contain only 181 | * printable characters and must be null terminated. 182 | * 183 | * @param error_number Error number returned by 184 | * wsrep_tls_stream_get_error_number_t. 185 | * @param category Error category returned by 186 | * wsrep_tls_stream_get_error_category_t. 187 | * 188 | * @return Human readable message string. 189 | */ 190 | typedef const char* (*wsrep_tls_error_message_get_t)( 191 | wsrep_tls_context_t*, 192 | const wsrep_tls_stream_t* stream, 193 | int error_number, const void* category); 194 | 195 | /** 196 | * Initiate TLS client side handshake. This function is called for the 197 | * stream sockets which have been connected by the provider. 198 | * 199 | * If the stream socket is in non-blocking mode, the call should return 200 | * immediately with appropriate result indicating if more actions are needed 201 | * in the case the operation would block. The provider will call this function 202 | * again until either a success or an error is returned. 203 | * 204 | * @param stream TLS stream. 205 | * 206 | * @return Enum wsrep_tls_result. 207 | */ 208 | typedef enum wsrep_tls_result (*wsrep_tls_stream_client_handshake_t)( 209 | wsrep_tls_context_t*, 210 | wsrep_tls_stream_t* stream); 211 | 212 | /** 213 | * Initiate TLS server side handshake. This function is called for stream 214 | * sockets which have been accepted by the provider. 215 | * 216 | * If the stream socket is in non-blocking mode, the call should return 217 | * immediately with appropriate result indicating if more actions are needed 218 | * in the case the operation would block. The provider will call this function 219 | * again until either a success or an error is returned. 220 | * 221 | * @param stream TLS stream. 222 | * 223 | * @return Enum wsrep_tls_result. 224 | */ 225 | typedef enum wsrep_tls_result (*wsrep_tls_stream_server_handshake_t)( 226 | wsrep_tls_context_t*, 227 | wsrep_tls_stream_t* stream); 228 | 229 | /** 230 | * Perform a read from the stream. If the file descriptor associated 231 | * to the stream is in non-blocking mode, the call must return immediately 232 | * with appropriate result if the stream processing would block. 233 | * 234 | * @param[in] stream TLS stream. 235 | * @param[in] buf Buffer to read the data into. 236 | * @param[in] max_count Maximum number of bytes to read. 237 | * @param[out] bytes_transferred Number of bytes read into the buffer during 238 | * the operation. 239 | * 240 | * @return Enum wsrep_tls_result. 241 | */ 242 | typedef enum wsrep_tls_result (*wsrep_tls_stream_read_t)( 243 | wsrep_tls_context_t*, 244 | wsrep_tls_stream_t* stream, 245 | void* buf, 246 | size_t max_count, 247 | size_t* bytes_transferred); 248 | 249 | /** 250 | * Perform a write to the stream. If the file descriptor asociated to 251 | * te stream is in non-blocking mode, the call must return immediately 252 | * with appropriate result if the stream processing would block. 253 | * 254 | * @param[in] stream TLS stream. 255 | * @param[in] buf Buffer which contains the data to write. 256 | * @param[in] count Number of bytes to be written. 257 | * @param[out] bytes_transferred Number of bytes written into the stream 258 | * during the opration. 259 | * 260 | * @return Enum wsrep_tls_result. 261 | */ 262 | typedef enum wsrep_tls_result (*wsrep_tls_stream_write_t)( 263 | wsrep_tls_context_t*, 264 | wsrep_tls_stream_t* stream, 265 | const void* buf, 266 | size_t count, 267 | size_t* bytes_transferred); 268 | 269 | /** 270 | * Shutdown the TLS stream. 271 | * 272 | * Note that the implementation must not close the associated stream 273 | * socket, just shut down the protocol. 274 | * 275 | * If the shutdown call returns either wsrep_result_want_read or 276 | * wsrep_result_want_write, the provider must wait until the socket 277 | * becomes readable or writable and then call the function again 278 | * until the return status is either success or an error occurs. 279 | * 280 | * @param stream TLS stream to be shut down. 281 | * 282 | * @return Enum wsrep_tls_result code. 283 | * 284 | */ 285 | typedef enum wsrep_tls_result (*wsrep_tls_stream_shutdown_t)( 286 | wsrep_tls_context_t*, 287 | wsrep_tls_stream_t* stream); 288 | 289 | /** 290 | * TLS service struct. 291 | * 292 | * A pointer to this struct must be passed to the call to 293 | * wsrep_init_tls_service_v1. 294 | * 295 | * The application must provide implementation to all functions defined 296 | * in this struct. 297 | */ 298 | typedef struct wsrep_tls_service_v1_st 299 | { 300 | /* Stream */ 301 | wsrep_tls_stream_init_t stream_init; 302 | wsrep_tls_stream_deinit_t stream_deinit; 303 | wsrep_tls_stream_get_error_number_t stream_get_error_number; 304 | wsrep_tls_stream_get_error_category_t stream_get_error_category; 305 | wsrep_tls_stream_client_handshake_t stream_client_handshake; 306 | wsrep_tls_stream_server_handshake_t stream_server_handshake; 307 | wsrep_tls_stream_read_t stream_read; 308 | wsrep_tls_stream_write_t stream_write; 309 | wsrep_tls_stream_shutdown_t stream_shutdown; 310 | /* Error */ 311 | wsrep_tls_error_message_get_t error_message_get; 312 | /* Pointer to application defined TLS context. */ 313 | wsrep_tls_context_t* context; 314 | } wsrep_tls_service_v1_t; 315 | 316 | 317 | #ifdef __cplusplus 318 | } 319 | #endif /* __cplusplus */ 320 | 321 | 322 | #define WSREP_TLS_SERVICE_INIT_FUNC_V1 "wsrep_init_tls_service_v1" 323 | #define WSREP_TLS_SERVICE_DEINIT_FUNC_V1 "wsrep_deinit_tls_service_v1" 324 | 325 | #endif /* WSREP_TLS_SERVICE_H */ 326 | 327 | -------------------------------------------------------------------------------- /wsrep_uuid.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2009 Codership Oy 2 | 3 | This program is free software; you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation; version 2 of the License. 6 | 7 | This program is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | 12 | You should have received a copy of the GNU General Public License 13 | along with this program; if not, write to the Free Software 14 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | /*! @file Helper functions to deal with history UUID string representations */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "wsrep_api.h" 25 | 26 | /*! 27 | * Read UUID from string 28 | * @return length of UUID string representation or -EINVAL in case of error 29 | */ 30 | int 31 | wsrep_uuid_scan (const char* str, size_t str_len, wsrep_uuid_t* uuid) 32 | { 33 | unsigned int uuid_len = 0; 34 | unsigned int uuid_offt = 0; 35 | 36 | while (uuid_len + 1 < str_len) { 37 | /* We are skipping potential '-' after uuid_offt == 4, 6, 8, 10 38 | * which means 39 | * (uuid_offt >> 1) == 2, 3, 4, 5, 40 | * which in turn means 41 | * (uuid_offt >> 1) - 2 <= 3 42 | * since it is always >= 0, because uuid_offt is unsigned */ 43 | if (((uuid_offt >> 1) - 2) <= 3 && str[uuid_len] == '-') { 44 | // skip dashes after 4th, 6th, 8th and 10th positions 45 | uuid_len += 1; 46 | continue; 47 | } 48 | 49 | if (isxdigit(str[uuid_len]) && isxdigit(str[uuid_len + 1])) { 50 | // got hex digit, scan another byte to uuid, increment uuid_offt 51 | sscanf (str + uuid_len, "%2hhx", uuid->data + uuid_offt); 52 | uuid_len += 2; 53 | uuid_offt += 1; 54 | if (sizeof (uuid->data) == uuid_offt) 55 | return (int)uuid_len; 56 | } 57 | else { 58 | break; 59 | } 60 | } 61 | 62 | *uuid = WSREP_UUID_UNDEFINED; 63 | return -EINVAL; 64 | } 65 | 66 | /*! 67 | * Write UUID to string 68 | * @return length of UUID string representation or -EMSGSIZE if string is too 69 | * short 70 | */ 71 | int 72 | wsrep_uuid_print (const wsrep_uuid_t* uuid, char* str, size_t str_len) 73 | { 74 | if (str_len > 36) { 75 | const unsigned char* u = uuid->data; 76 | return snprintf(str, str_len, "%02x%02x%02x%02x-%02x%02x-%02x%02x-" 77 | "%02x%02x-%02x%02x%02x%02x%02x%02x", 78 | u[ 0], u[ 1], u[ 2], u[ 3], u[ 4], u[ 5], u[ 6], u[ 7], 79 | u[ 8], u[ 9], u[10], u[11], u[12], u[13], u[14], u[15]); 80 | } 81 | else { 82 | return -EMSGSIZE; 83 | } 84 | } 85 | 86 | /*! 87 | * Compare two UUIDs 88 | * @return -1, 0, 1 if lhs is respectively smaller, equal, or greater than rhs 89 | */ 90 | int 91 | wsrep_uuid_compare (const wsrep_uuid_t* lhs, const wsrep_uuid_t* rhs) 92 | { 93 | return memcmp(lhs, rhs, sizeof(wsrep_uuid_t)); 94 | } 95 | --------------------------------------------------------------------------------