├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── bin └── lkp-ctl ├── build.sh ├── etc ├── dockerfile │ └── Dockerfile └── protobuf-cpp-3.0.0.tar.gz ├── images └── lkp.png ├── lib ├── container.sh ├── docker.sh ├── env.sh ├── init.sh ├── lkp.sh └── log.sh ├── lkp-extent.config ├── sbin ├── init ├── list ├── push ├── result ├── run ├── start ├── stop └── update ├── src ├── lib │ ├── lkpCodec.cc │ ├── lkpCodec.h │ ├── lkpDispatcher.h │ ├── lkpProto.pb.cc │ └── lkpProto.pb.h ├── lkpClient.cc ├── lkpClient.h ├── lkpCommand.cc ├── lkpHelper.cc ├── lkpHelper.h ├── lkpProto.proto ├── lkpServer.cc ├── lkpServer.h ├── lkp_extent.cc └── makefile └── testcases └── test.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | lkp-tests 2 | lkp-mirror 3 | workspace 4 | .vscode 5 | build 6 | src/build 7 | log/* 8 | results/remote/ 9 | results/local/ 10 | etc/dockerimages -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/muduo"] 2 | path = src/muduo 3 | url = https://github.com/BIGWJZ/muduo.git 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2022 THL A29 Limited 2 | 3 | nettrace is licensed under Mulan PSL v2. You can use this software according to the terms and conditions of the 4 | Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at: http://license.coscl.org.cn/MulanPSL2 5 | THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, 6 | INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 7 | See the Mulan PSL v2 for more details. 8 | 9 | January 2020 http://license.coscl.org.cn/MulanPSL2 10 | 11 | Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions: 12 | 13 | 0. Definition 14 | 15 | Software means the program and related documents which are licensed under this License and comprise all Contribution(s). 16 | 17 | Contribution means the copyrightable work licensed by a particular Contributor under this License. 18 | 19 | Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License. 20 | 21 | Legal Entity means the entity making a Contribution and all its Affiliates. 22 | 23 | Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, ‘control’ means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity. 24 | 25 | 1. Grant of Copyright License 26 | 27 | Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not. 28 | 29 | 2. Grant of Patent License 30 | 31 | Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken. 32 | 33 | 3. No Trademark License 34 | 35 | No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in Section 4. 36 | 37 | 4. Distribution Restriction 38 | 39 | You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software. 40 | 41 | 5. Disclaimer of Warranty and Limitation of Liability 42 | 43 | THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 44 | 45 | 6. Language 46 | 47 | THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL. 48 | 49 | END OF THE TERMS AND CONDITIONS 50 | 51 | 52 | 53 | Other dependencies and licenses: 54 | 55 | 1. bcc 56 | Copyright (c) bcc authors and contributors 57 | 58 | Apache License 59 | Version 2.0, January 2004 60 | http://www.apache.org/licenses/ 61 | 62 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 63 | 64 | 1. Definitions. 65 | 66 | "License" shall mean the terms and conditions for use, reproduction, 67 | and distribution as defined by Sections 1 through 9 of this document. 68 | 69 | "Licensor" shall mean the copyright owner or entity authorized by 70 | the copyright owner that is granting the License. 71 | 72 | "Legal Entity" shall mean the union of the acting entity and all 73 | other entities that control, are controlled by, or are under common 74 | control with that entity. For the purposes of this definition, 75 | "control" means (i) the power, direct or indirect, to cause the 76 | direction or management of such entity, whether by contract or 77 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 78 | outstanding shares, or (iii) beneficial ownership of such entity. 79 | 80 | "You" (or "Your") shall mean an individual or Legal Entity 81 | exercising permissions granted by this License. 82 | 83 | "Source" form shall mean the preferred form for making modifications, 84 | including but not limited to software source code, documentation 85 | source, and configuration files. 86 | 87 | "Object" form shall mean any form resulting from mechanical 88 | transformation or translation of a Source form, including but 89 | not limited to compiled object code, generated documentation, 90 | and conversions to other media types. 91 | 92 | "Work" shall mean the work of authorship, whether in Source or 93 | Object form, made available under the License, as indicated by a 94 | copyright notice that is included in or attached to the work 95 | (an example is provided in the Appendix below). 96 | 97 | "Derivative Works" shall mean any work, whether in Source or Object 98 | form, that is based on (or derived from) the Work and for which the 99 | editorial revisions, annotations, elaborations, or other modifications 100 | represent, as a whole, an original work of authorship. For the purposes 101 | of this License, Derivative Works shall not include works that remain 102 | separable from, or merely link (or bind by name) to the interfaces of, 103 | the Work and Derivative Works thereof. 104 | 105 | "Contribution" shall mean any work of authorship, including 106 | the original version of the Work and any modifications or additions 107 | to that Work or Derivative Works thereof, that is intentionally 108 | submitted to Licensor for inclusion in the Work by the copyright owner 109 | or by an individual or Legal Entity authorized to submit on behalf of 110 | the copyright owner. For the purposes of this definition, "submitted" 111 | means any form of electronic, verbal, or written communication sent 112 | to the Licensor or its representatives, including but not limited to 113 | communication on electronic mailing lists, source code control systems, 114 | and issue tracking systems that are managed by, or on behalf of, the 115 | Licensor for the purpose of discussing and improving the Work, but 116 | excluding communication that is conspicuously marked or otherwise 117 | designated in writing by the copyright owner as "Not a Contribution." 118 | 119 | "Contributor" shall mean Licensor and any individual or Legal Entity 120 | on behalf of whom a Contribution has been received by Licensor and 121 | subsequently incorporated within the Work. 122 | 123 | 2. Grant of Copyright License. Subject to the terms and conditions of 124 | this License, each Contributor hereby grants to You a perpetual, 125 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 126 | copyright license to reproduce, prepare Derivative Works of, 127 | publicly display, publicly perform, sublicense, and distribute the 128 | Work and such Derivative Works in Source or Object form. 129 | 130 | 3. Grant of Patent License. Subject to the terms and conditions of 131 | this License, each Contributor hereby grants to You a perpetual, 132 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 133 | (except as stated in this section) patent license to make, have made, 134 | use, offer to sell, sell, import, and otherwise transfer the Work, 135 | where such license applies only to those patent claims licensable 136 | by such Contributor that are necessarily infringed by their 137 | Contribution(s) alone or by combination of their Contribution(s) 138 | with the Work to which such Contribution(s) was submitted. If You 139 | institute patent litigation against any entity (including a 140 | cross-claim or counterclaim in a lawsuit) alleging that the Work 141 | or a Contribution incorporated within the Work constitutes direct 142 | or contributory patent infringement, then any patent licenses 143 | granted to You under this License for that Work shall terminate 144 | as of the date such litigation is filed. 145 | 146 | 4. Redistribution. You may reproduce and distribute copies of the 147 | Work or Derivative Works thereof in any medium, with or without 148 | modifications, and in Source or Object form, provided that You 149 | meet the following conditions: 150 | 151 | (a) You must give any other recipients of the Work or 152 | Derivative Works a copy of this License; and 153 | 154 | (b) You must cause any modified files to carry prominent notices 155 | stating that You changed the files; and 156 | 157 | (c) You must retain, in the Source form of any Derivative Works 158 | that You distribute, all copyright, patent, trademark, and 159 | attribution notices from the Source form of the Work, 160 | excluding those notices that do not pertain to any part of 161 | the Derivative Works; and 162 | 163 | (d) If the Work includes a "NOTICE" text file as part of its 164 | distribution, then any Derivative Works that You distribute must 165 | include a readable copy of the attribution notices contained 166 | within such NOTICE file, excluding those notices that do not 167 | pertain to any part of the Derivative Works, in at least one 168 | of the following places: within a NOTICE text file distributed 169 | as part of the Derivative Works; within the Source form or 170 | documentation, if provided along with the Derivative Works; or, 171 | within a display generated by the Derivative Works, if and 172 | wherever such third-party notices normally appear. The contents 173 | of the NOTICE file are for informational purposes only and 174 | do not modify the License. You may add Your own attribution 175 | notices within Derivative Works that You distribute, alongside 176 | or as an addendum to the NOTICE text from the Work, provided 177 | that such additional attribution notices cannot be construed 178 | as modifying the License. 179 | 180 | You may add Your own copyright statement to Your modifications and 181 | may provide additional or different license terms and conditions 182 | for use, reproduction, or distribution of Your modifications, or 183 | for any such Derivative Works as a whole, provided Your use, 184 | reproduction, and distribution of the Work otherwise complies with 185 | the conditions stated in this License. 186 | 187 | 5. Submission of Contributions. Unless You explicitly state otherwise, 188 | any Contribution intentionally submitted for inclusion in the Work 189 | by You to the Licensor shall be under the terms and conditions of 190 | this License, without any additional terms or conditions. 191 | Notwithstanding the above, nothing herein shall supersede or modify 192 | the terms of any separate license agreement you may have executed 193 | with Licensor regarding such Contributions. 194 | 195 | 6. Trademarks. This License does not grant permission to use the trade 196 | names, trademarks, service marks, or product names of the Licensor, 197 | except as required for reasonable and customary use in describing the 198 | origin of the Work and reproducing the content of the NOTICE file. 199 | 200 | 7. Disclaimer of Warranty. Unless required by applicable law or 201 | agreed to in writing, Licensor provides the Work (and each 202 | Contributor provides its Contributions) on an "AS IS" BASIS, 203 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 204 | implied, including, without limitation, any warranties or conditions 205 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 206 | PARTICULAR PURPOSE. You are solely responsible for determining the 207 | appropriateness of using or redistributing the Work and assume any 208 | risks associated with Your exercise of permissions under this License. 209 | 210 | 8. Limitation of Liability. In no event and under no legal theory, 211 | whether in tort (including negligence), contract, or otherwise, 212 | unless required by applicable law (such as deliberate and grossly 213 | negligent acts) or agreed to in writing, shall any Contributor be 214 | liable to You for damages, including any direct, indirect, special, 215 | incidental, or consequential damages of any character arising as a 216 | result of this License or out of the use or inability to use the 217 | Work (including but not limited to damages for loss of goodwill, 218 | work stoppage, computer failure or malfunction, or any and all 219 | other commercial damages or losses), even if such Contributor 220 | has been advised of the possibility of such damages. 221 | 222 | 9. Accepting Warranty or Additional Liability. While redistributing 223 | the Work or Derivative Works thereof, You may choose to offer, 224 | and charge a fee for, acceptance of support, warranty, indemnity, 225 | or other liability obligations and/or rights consistent with this 226 | License. However, in accepting such obligations, You may act only 227 | on Your own behalf and on Your sole responsibility, not on behalf 228 | of any other Contributor, and only if You agree to indemnify, 229 | defend, and hold each Contributor harmless for any liability 230 | incurred by, or claims asserted against, such Contributor by reason 231 | of your accepting any such warranty or additional liability. 232 | 233 | END OF TERMS AND CONDITIONS 234 | 235 | APPENDIX: How to apply the Apache License to your work. 236 | 237 | To apply the Apache License to your work, attach the following 238 | boilerplate notice, with the fields enclosed by brackets "{}" 239 | replaced with your own identifying information. (Don't include 240 | the brackets!) The text should be enclosed in the appropriate 241 | comment syntax for the file format. We also recommend that a 242 | file or class name and description of purpose be included on the 243 | same "printed page" as the copyright notice for easier 244 | identification within third-party archives. 245 | 246 | Copyright {yyyy} {name of copyright owner} 247 | 248 | Licensed under the Apache License, Version 2.0 (the "License"); 249 | you may not use this file except in compliance with the License. 250 | You may obtain a copy of the License at 251 | 252 | http://www.apache.org/licenses/LICENSE-2.0 253 | 254 | Unless required by applicable law or agreed to in writing, software 255 | distributed under the License is distributed on an "AS IS" BASIS, 256 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 257 | See the License for the specific language governing permissions and 258 | limitations under the License. 259 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![img](images/lkp.png) 2 | 3 | # lkp-extent 4 | 5 | lkp-extent项目致力于增加[LKP](https://github.com/intel/lkp-tests "LKP")项目在容器环境下的压力相关测试,从而增加Linux系统的ras特性。目前主要分为如下几个方向: 6 | ``` 7 | 1) 增加LKP远程管理分发机制 (已完成) 8 | 2) 增加LKP对容器环境的测试 (大部分完成) 9 | 3) 增加ebpf测试内核的用例 (待完成) 10 | ``` 11 | 12 | ## 1. 项目介绍 13 | 14 | >lkp-extent是[LKP](https://github.com/intel/lkp-tests "LKP")的一个扩展功能,但是该repo并不会对[LKP](https://github.com/intel/lkp-tests "LKP")工程本身进行修改,他可以在最大的程度上使用最新的[LKP](https://github.com/intel/lkp-tests "LKP"),而lkp-extent上面新增的测试case也只会以overlay的方式叠加到原生态的LKP工程上。 15 | 16 | 1.1 远程管理与分发 17 | >我们知道在测试系统稳定性的时候,对不同类型的服务器进行大批量暴力测试,才能更容易说明问题。但是原生态的[LKP](https://github.com/intel/lkp-tests "LKP")套件主要是用于在单台Linux服务器上测试系统的稳定性,如果需要部署多台不同类型的服务器进行同时测试,则需要手动登录每一台服务器进行设置。因此lkp-extent主要用于扩展[LKP](https://github.com/intel/lkp-tests "LKP")功能,解决其在这方面的不足,设计出一个 一对多点的运作模式。 18 | 19 | lkp-server 20 | | 21 | +-----------------+----------------+----------------+-------------------+ 22 | | | | | | 23 | | | | | | 24 | lkp-node lkp-node ..... lkp-node lkp-node 25 | 26 | >如图,首先我们将一台服务器称为node,而lkp-extent则需要存在一个server node和若干个client node。server node会进入监听模式,client node会根据自身的服务器配置相继接入对应的server node。这样server node上面,就可以对client node进行全方位的操作. 27 | 28 | 1.2 容器环境支持 29 | 30 | >目前[LKP](https://github.com/intel/lkp-tests "LKP")的测试case更多的是偏向于对Linux内核本身的测试,然而对于容器环境相关的测试则是几乎没有,因此lkp-extent工程会重点研发容器环境相关的测试case,用于打造一个更稳定的容器OS。 31 | 32 | 1.3 实现 33 | >lkp-extent使用以下第三方库: 34 | ``` 35 | (1) 基于muduo :满足C10K并发要求,适合内网工具使用的非阻塞异步网络库 36 | (2) 基于overlayfs:与原lkp项目解耦,容器挂载于overlayfs的merged目录 37 | (3) 基于protobuf :高性能消息序列化工具。 38 | ``` 39 | 40 | >lkp-extent目前提供以下能力: 41 | ``` 42 | (1)对客户端的动态管理,命令下发,testcase分发,result回收。减轻测试运维压力。 43 | (2)对lkp的容器扩展,在容器中执行测试,将result打包至宿主机目录内。 44 | ``` 45 | 46 | >lkp-extent目前存在以下不足: 47 | ``` 48 | (1)缺少对运行lkp的docker的后台管理,后续可以考虑加入。 49 | (2)缺少对docker特性的lkp测试用例,后续可以考虑加入。 50 | (3)目前的docker镜像使用ubuntu制作。可以制作OpenCloudOS版本镜像用于测试,后续可以考虑加入其他docker镜像。 51 | ``` 52 | ## 2. 安装方法 53 | 2.1 安装TencentOS或者OpenCloudOS镜像 54 | 55 | 2.2 安装编译需要的相关依赖 56 | ``` 57 | $ yum install boost-devel cmake -y 58 | ``` 59 | 2.3 下载lkp-extent源码 60 | ``` 61 | $ git clone https://github.com/OpenCloudOS/lkp-extent.git 62 | $ cd lkp-extent 63 | ``` 64 | 65 | 2.4 protobuf安装(使用protobuf 3.0.0离线压缩包,在etc目录下有安装包) 66 | ``` 67 | $ cd etc 68 | $ tar xvf protobuf-cpp-3.0.0.tar.gz 69 | $ cd protobuf-3.0.0 70 | $ ./configure --prefix=/usr/ 71 | $ make 72 | $ make install 73 | ``` 74 | 75 | 2.5 lkp-extent安装 76 | 77 | ``` 78 | $ cd ../.. 79 | $ ./build.sh # 编译lkp-extent代码 80 | 81 | 显示lkp-extent is ready!即可。 82 | ``` 83 | 84 | 输入lkp-ctl可以看到lkp-extent的介绍则说明安装成功。 85 | 86 | ## 3. 使用方法 87 | 88 | >**用之前需要在lkp-extent.config配置文件中修改IP、port等配置。** 89 | 90 | 3.1 初始化,下载安装lkp项目,配置overlayfs并mount。 91 | ``` 92 | lkp-ctl init 93 | ``` 94 | 95 | 3.2 开启服务,可选择为当前主机开启lkp-extent的client或者server服务 96 | ``` 97 | lkp-ctl start server 98 | lkp-ctl start client 99 | ``` 100 | 101 | 3.3 显示当前已经连接的节点数量与信息,只对server有效 102 | ``` 103 | lkp-ctl list 104 | ``` 105 | 106 | 3.4 控制节点执行lkp测试 107 | ``` 108 | lkp-ctl run ebizzy #执行本机lkp测试 109 | lkp-ctl -a run ebizzy #所有远程client节点执行ebizzy测试 110 | lkp-ctl -i 2 -c 5 dockertest #2号节点开启5个容器执行dockertest测试(当前没有dockertest.yaml,使用ebizzy进行过容器测试) 111 | ``` 112 | 113 | 3.5 向远端节点推送自定义testcase 114 | ``` 115 | lkp-ctl -a push dockertest.yaml #向所有远端节点广播推送 116 | lkp-ctl -i 0 push dockertest.yaml #向0号节点推送dockertest.yaml,会添加到/lkp-tests/jobs中 117 | ``` 118 | 119 | 3.6 从远端节点回收测试结果 120 | ``` 121 | lkp-ctl -a result #向所有节点回收结果 122 | lkp-ctl -i 0 result #向0号节点回收结果 123 | ``` 124 | 125 | 3.7 命令远端节点更新 126 | ``` 127 | lkp-ctl -a update #所有节点更新 128 | lkp-ctl -i 11 update #11号节点更新 129 | ``` 130 | 131 | 3.8 关闭lkp-extent服务 132 | ``` 133 | lkp-ctl stop 134 | ``` 135 | 136 | ## 4. 结语 137 | 138 | >lkp-extent是一个依赖于LKP测试套件的工程,因此lkp-extent工程里面关于容器测试case的写法和[LKP](https://github.com/intel/lkp-tests "LKP")的job写法相同([readme](https://github.com/intel/lkp-tests/blob/master/doc/add-testcase.md "how to"))。在使用过程中,lkp-extent会将自身的测试项overlay到[LKP](https://github.com/intel/lkp-tests "LKP")工程的jobs目录上,这样方便LKP工程进行统一管理。同样在之前提到的,拥有远程管理的基础上,lkp-ctl可以拥有通过配置文件,让多个host在指定时间,指定条件进行自动部署,自动测试和自动返回测试结果的功能。 139 | 140 | -------------------------------------------------------------------------------- /bin/lkp-ctl: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | usage() { 4 | subcommand_show(){ 5 | for cmd in $(ls $ROOT_DIR/sbin);do 6 | eval $(sed -n '/^help_doc=\"/p' $ROOT_DIR/sbin/$cmd) 7 | lkp_print "\t$cmd\t$help_doc\n" 8 | done 9 | } 10 | 11 | lkp_show "Usage: $1 [OPTION] COMMAND [arg0 ...]" 12 | lkp_print "\nA enhance lkp for containers\n" 13 | lkp_print "\nOptions:\n" 14 | lkp_print "\t-a specify all node to run case\n" 15 | lkp_print "\t-c set the number of containers per node, default: 0\n" 16 | lkp_print "\t-i specify the node to run case (nodeid), default: current node\n" 17 | lkp_print "\t-d enable debug mode\n" 18 | lkp_print "\t-h list help\n" 19 | lkp_print "\nCOMMAND:\n" 20 | subcommand_show 21 | lkp_print "\nTo get more help, Please see the README.md\n" 22 | } 23 | 24 | export VM_CNT=0 25 | export NODE_ID=-1 26 | export NODE_ALL=1 27 | export LOCAL_FLAG=1 28 | export ROOT_DIR=$(dirname $(dirname $(readlink -e -v $0))) 29 | 30 | source $ROOT_DIR/lib/env.sh 31 | source $ROOT_DIR/lib/log.sh 32 | 33 | # parse parameters 34 | while getopts ":i:c:dha" opt; do 35 | case $opt in 36 | d) set -x;; 37 | c) export VM_CNT=$OPTARG;; 38 | i) export NODE_ID=$OPTARG;export NODE_ALL=0;LOCAL_FLAG=0;; 39 | a) export NODE_ALL=1;LOCAL_FLAG=0;; 40 | h) usage $PROGRAM && exit 1;; 41 | ?) usage $PROGRAM && exit 1;; 42 | esac 43 | done 44 | 45 | shift $((OPTIND - 1)) 46 | command="${1}" 47 | shift 1 48 | 49 | lkp_loginit 50 | for func in $(ls $ROOT_DIR/sbin);do 51 | [ "$func" == "$command" ] && { 52 | sh $ROOT_DIR/sbin/$command $@ 53 | exit 0 54 | } 55 | done 56 | 57 | # generally, it will not run here 58 | usage $PROGRAM 59 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ex 3 | 4 | ROOT_DIR=$(pwd) 5 | echo $ROOT_DIR 6 | 7 | git submodule init 8 | git submodule update 9 | 10 | #make and install muduo 11 | cd $ROOT_DIR/src/muduo 12 | ./build.sh 13 | ./build.sh install 14 | 15 | cp -r $ROOT_DIR/src/build/release-install-cpp11/include/muduo /usr/include 16 | cp $ROOT_DIR/src/build/release-install-cpp11/lib/* /usr/lib 17 | 18 | mkdir -p /usr/include/muduo/net/protorpc/ 19 | cp $ROOT_DIR/src/muduo/muduo/net/protorpc/google-inl.h /usr/include/muduo/net/protorpc/ 20 | #make lkp-extent 21 | cd $ROOT_DIR/src 22 | make 23 | 24 | #install lkp-extent 25 | mkdir -p /usr/local/bin 26 | ln -sf $ROOT_DIR/bin/lkp-ctl /usr/local/bin/lkp-ctl 27 | 28 | mkdir -p $ROOT_DIR/log 29 | mkdir -p $ROOT_DIR/results/local 30 | mkdir -p $ROOT_DIR/results/remote 31 | mkdir -p $ROOT_DIR/testcases 32 | 33 | set +ex 34 | 35 | echo "lkp-extent is ready!" 36 | echo "Use 'lkp-ctl init' and 'lkp-ctl start server/client' to start lkp-extent" 37 | 38 | 39 | -------------------------------------------------------------------------------- /etc/dockerfile/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | MAINTAINER wjz 3 | RUN apt-get update \ 4 | && apt-get -y install bc debianutils gawk gzip kmod numactl rsync time automake bison build-essential bzip2 ca-certificates cpio fakeroot flex gcc git libarchive-tools libc6-dev libc6-dev-x32 libipc-run-perl libklibc-dev libssl-dev libtool linux-libc-dev linux-tools-common make openssl patch rsync ruby ruby-dev wget \ 5 | && apt-get -y install linux-tools-generic linux-cloud-tools-generic 6 | -------------------------------------------------------------------------------- /etc/protobuf-cpp-3.0.0.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCloudOS/lkp-extent/61436532af2df1e0b11d0cf55ccb925456ec8028/etc/protobuf-cpp-3.0.0.tar.gz -------------------------------------------------------------------------------- /images/lkp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCloudOS/lkp-extent/61436532af2df1e0b11d0cf55ccb925456ec8028/images/lkp.png -------------------------------------------------------------------------------- /lib/container.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source $ROOT_DIR/lib/docker.sh 4 | 5 | do_container_test(){ 6 | local container_type=$1 7 | 8 | shift 1 9 | 10 | mkdir -p $ROOT_DIR/lkp_tests/dockerResults 11 | #${container_type}_create_image $DOCKER_INAME 12 | ${container_type}_create_container $DOCKER_INAME $VM_CNT 13 | #${container_type}_test_container $1 14 | tar -cvf $ROOT_DIR/results/local/result.tar $ROOT_DIR/lkp-tests/dockerResults/* 15 | } 16 | -------------------------------------------------------------------------------- /lib/docker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source $ROOT_DIR/lib/env.sh 4 | source $ROOT_DIR/lib/log.sh 5 | 6 | vol_map="$LKP_DIR:$LKP_IN_CONTAINER" 7 | 8 | # - $1: image name 9 | docker_create_image() { 10 | local found=0 11 | local docker_images="$1" 12 | 13 | docker images | grep $docker_images >/dev/null 2>/dev/null 14 | for image in $(docker images | sed '1d' | awk '{print $1}');do 15 | if [ "$image" == "$docker_images" ];then 16 | found=1 17 | fi 18 | done 19 | 20 | [ $found -eq 0 ] && { 21 | docker build -t $docker_images:latest $DOCKER_PATH 22 | lkp_log2f LOG_INF "docker create image: $docker_images\n" 23 | } || { 24 | lkp_log2f LOG_INF "docker image:$docker_images is already created\n" 25 | } 26 | } 27 | 28 | # - $1: docker_images 29 | # - $2: container count 30 | # 直接使用创建好的image运行lkp测试,目前的image只安装了ebizzy的依赖项,但是docker里的脚本也可以自动安装所需依赖 31 | docker_create_container (){ 32 | local container_flag 33 | local docker_images=$1 34 | local vm_count=${2:-1} 35 | local found=0 36 | for image in $(docker images | sed '1d' | awk '{print $1}');do 37 | if [ "$image" == "$docker_images" ];then 38 | found=1 39 | fi 40 | done 41 | 42 | [ $found -eq 0 ] && { 43 | lkp_show "lkp-ctl run docker error: Cannot find docker iamge!" 44 | } || { 45 | container_flag="--privileged=$DOCKER_HAS_ROOT -dit" 46 | for i in $(seq 1 $vm_count); do 47 | lkp_log2f LOG_INF "docker $i run $docker_images /bin/bash\n"; 48 | docker run $container_flag --name "lkptest$i" -v $vol_map --rm $docker_images:1.1 /bin/bash; 49 | done 50 | } 51 | } 52 | 53 | # - $1: testcase path 54 | # 启动docker内的lkp-test进行测试 55 | docker_test_container (){ 56 | local testcase="$1" 57 | local container_flag 58 | 59 | container_flag="--privileged=$DOCKER_HAS_ROOT -dit" 60 | for id in `docker ps | sed '1 d' | awk '{print $1 }'`; do 61 | lkp_log2f LOG_INF "docker $i exec $id $testcase\n" 62 | docker exec $container_flag $id /bin/bash -c "/lkp-tests/lkp-extent.sh $testcase" 63 | done 64 | } 65 | -------------------------------------------------------------------------------- /lib/env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export LOG_LEVEL=LOG_INF 4 | export PATH="$PATH:$ROOT_DIR/sbin:$ROOT_DIR/bin" 5 | 6 | PROGRAM=$(basename $0) 7 | 8 | # get parent task name 9 | PNAME=$(cat /proc/$PPID/comm) 10 | 11 | # log path 12 | LOG_FILE="/tmp/lkp/log.txt" 13 | 14 | # workspace directory 15 | WORKSPACE=$ROOT_DIR/workspace 16 | 17 | # LKP tests project 18 | LKP_PRJ=$WORKSPACE/lkp-tests 19 | LKP_URL="https://github.com/intel/lkp-tests.git" 20 | 21 | # overlayfs configration 22 | LOWER_DIR=$LKP_PRJ 23 | FSWORKDIR=$WORKSPACE/tmp 24 | LKP_DIR=$ROOT_DIR/lkp-tests 25 | UPPER_DIR=$ROOT_DIR/lkp-mirror 26 | LKP_IN_CONTAINER="/lkp-tests" 27 | 28 | # dockerfile path 29 | DOCKER_PATH=$ROOT_DIR/etc/dockerfile 30 | 31 | # docker privilege 32 | DOCKER_HAS_ROOT=true 33 | DOCKER_INAME="lkp-extent-ubuntu-18-wjz" 34 | 35 | # job path 36 | JOB_WORKDIR=$WORKSPACE/jobs 37 | 38 | #src path 39 | SRC_PATH=$ROOT_DIR/src 40 | -------------------------------------------------------------------------------- /lib/init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source $ROOT_DIR/lib/log.sh 4 | 5 | code_init() { 6 | local dir 7 | # 在workspace/lkp-tests安装lkp,作为overlay的lower dir(only read, 不影响lkp项目) 8 | dir=$(dirname $LKP_PRJ) 9 | [ ! -d $LKP_PRJ ] && { 10 | mkdir -p $dir 11 | cd $dir && git clone $LKP_URL $(basename $LKP_PRJ) 12 | } 13 | 14 | 15 | } 16 | 17 | overlay_init(){ 18 | mkdir -p $FSWORKDIR 19 | mkdir -p $LKP_DIR 20 | 21 | [ ! -e "$UPPER_DIR" ] && { 22 | mkdir -p $UPPER_DIR 23 | } 24 | #将Upperdir(lkp-mirror)与lowerdir(workspace/lkp-tests)合并挂载到lkp-tests 25 | mount -t overlay overlay -olowerdir=$LOWER_DIR,upperdir=$UPPER_DIR,workdir=$FSWORKDIR $LKP_DIR -o index=off -o metacopy=off 26 | [ $? -ne 0 ] && { 27 | lkp_show "overlayfs init failed" 28 | } || { 29 | lkp_show "overlayfs is mounted" 30 | } 31 | return 0 32 | } 33 | 34 | fs_init(){ 35 | local found=0 36 | 37 | mkdir -p $WORKSPACE 38 | [ ! -d $LKP_PRJ ] && { 39 | code_init 40 | } 41 | 42 | 43 | 44 | for mountpoint in $(cat /proc/mounts | awk '{print $2}');do 45 | fstype=$(cat /proc/mounts | grep $mountpoint | awk '{print $1}') 46 | 47 | if [ "$fstype" == "overlay" -a "$mountpoint" == "$LKP_DIR" ];then 48 | found=1 49 | break 50 | fi 51 | done 52 | 53 | # if not found 54 | [ $found -eq 0 ] && { 55 | overlay_init 56 | } || { 57 | lkp_show "overlayfs is already mounted" 58 | } 59 | } 60 | 61 | fs_deinit(){ 62 | umount $LKP_DIR 63 | rm -rf $LKP_DIR 64 | rm -rf $WORKSPACE 65 | } 66 | -------------------------------------------------------------------------------- /lib/lkp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | LKP_ELF="lkp" 4 | source $ROOT_DIR/lib/env.sh 5 | source $ROOT_DIR/lib/log.sh 6 | 7 | lkp_install () { 8 | do_make(){ 9 | cd $LKP_DIR 10 | make && make install 11 | } 12 | 13 | which $LKP_ELF >/dev/null 2>&1 14 | [ $? -ne 0 ] && do_make 15 | $LKP_ELF install $@ 16 | } 17 | 18 | lkp_run_testcase (){ 19 | local job 20 | local jobs="$1" 21 | local basename="$(basename $1)" 22 | 23 | # split jobs 24 | $LKP_ELF split-job "${jobs}.yaml" 25 | [ $? -ne 0 ] && { 26 | lkp_show "No such job: $jobs" 27 | lkp_log2f LOG_ERR "No such job: $jobs\n" 28 | return 29 | } 30 | 31 | # install job 32 | for job in $(ls ${basename}*);do 33 | lkp_install $job 34 | done 35 | 36 | # run job 37 | for job in $(ls ${basename}*);do 38 | $LKP_ELF run $job 39 | done 40 | 41 | # add to results path for use 42 | 43 | } 44 | 45 | # - $1: lkp jobs directory 46 | # - $2: jobs work directory 47 | lkp_run_testcases (){ 48 | local job 49 | local jobsdir="$1" 50 | local workdir="$2" 51 | 52 | [ ! -d "$workdir" ] && { 53 | mkdir -p $workdir 54 | } 55 | 56 | shift 2 57 | cd $workdir # enter work directory 58 | while [ -n "$1" ]; do 59 | job="$jobsdir/$1" 60 | lkp_run_testcase "$job" 61 | shift 1 62 | done 63 | lkp_log2f LOG_INF "lkp run-jobs [$@]" 64 | } 65 | -------------------------------------------------------------------------------- /lib/log.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | LOG_ERR=0 4 | LOG_WAR=1 5 | LOG_DBG=2 6 | LOG_INF=3 7 | 8 | lkp_show(){ 9 | echo "$@" 10 | } 11 | 12 | lkp_print(){ 13 | printf "$@" 14 | } 15 | 16 | lkp_log(){ 17 | local level 18 | local log_level 19 | local max_level 20 | 21 | level="$1" 22 | log_level=$(eval echo \$$level) 23 | max_level=$(eval echo \$$LOG_LEVEL) 24 | 25 | shift 1 26 | [ $log_level -le $max_level ] && { 27 | printf "$(date +"%Y-%m-%d %H:%M.%S"): (${level/LOG_/}) $@" 28 | } 29 | } 30 | 31 | lkp_log2f(){ 32 | [ -f $LOG_FILE ] && { 33 | lkp_log "$@" >> $LOG_FILE 34 | } 35 | } 36 | 37 | lkp_loginit(){ 38 | mkdir -p $(dirname $LOG_FILE) 39 | [ ! -f $LOG_FILE ] && { 40 | touch $LOG_FILE 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lkp-extent.config: -------------------------------------------------------------------------------- 1 | # This is a comment 2 | # Configure the parameters of lkp-extent here. 3 | 4 | # for Server Use 5 | ServerListenPort = 7777 6 | ServerThreadsNum = 4 7 | # When timeout, the client will be unconnected 8 | ServerTimeControl = 10 9 | ServerflushInterval = 3 10 | # In fact, $ROOT_DIR/testcases 11 | ServerPushPath = testcases 12 | # In fact, $ROOT_DIR/results 13 | ServerResultPath = results 14 | 15 | # for Client Use 16 | ServerAddress = 172.28.158.128 17 | ServerPort = 7777 18 | HeartBeatTime = 5 19 | # In fact, $ROOT_DIR/testcases 20 | ClientPushPath = testcases 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /sbin/init: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | help_doc="initialize working directory" 4 | 5 | usage() { 6 | lkp_show "Usage: $PNAME $1 [OPTION]" 7 | lkp_print "\ninitialize working directory\n" 8 | lkp_print "\nOptions:\n" 9 | lkp_print "\t-d enable debug mode\n" 10 | lkp_print "\t-h list help\n" 11 | lkp_print "\nTo get more help, Please see the README.md\n" 12 | } 13 | 14 | source $ROOT_DIR/lib/env.sh 15 | source $ROOT_DIR/lib/log.sh 16 | source $ROOT_DIR/lib/init.sh 17 | source $ROOT_DIR/lib/lkp.sh 18 | 19 | # parse parameters 20 | while getopts ":hd" opt; do 21 | case $opt in 22 | d) set -x;; 23 | h) usage $PROGRAM && exit 1;; 24 | ?) usage $PROGRAM && exit 1;; 25 | esac 26 | done 27 | 28 | fs_init 29 | lkp_install 30 | -------------------------------------------------------------------------------- /sbin/list: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | help_doc="list the associated nodes" 4 | 5 | usage() { 6 | lkp_show "Usage: $PNAME $1 [OPTION]" 7 | lkp_print "\nlist the nodes associated with lkp-extent\n" 8 | lkp_print "\nOptions:\n" 9 | lkp_print "\t-d enable debug mode\n" 10 | lkp_print "\t-h list help\n" 11 | lkp_print "\nTo get more help, Please see the README.md\n" 12 | } 13 | 14 | source $ROOT_DIR/lib/env.sh 15 | source $ROOT_DIR/lib/log.sh 16 | 17 | # parse parameters 18 | while getopts ":hd" opt; do 19 | case $opt in 20 | d) set -x;; 21 | h) usage $PROGRAM && exit 1;; 22 | ?) usage $PROGRAM && exit 1;; 23 | esac 24 | done 25 | 26 | main () { 27 | $SRC_PATH/build/lkp_extent_CLI LIST null -1 0 $ROOT_DIR 28 | } 29 | 30 | main $@ 31 | -------------------------------------------------------------------------------- /sbin/push: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | help_doc="push the testcase to the nodes" 4 | 5 | usage() { 6 | lkp_show "Usage: $PNAME $1 [OPTION]" 7 | lkp_print "\npush the testcase to the nodes\n" 8 | lkp_print "\nOptions:\n" 9 | lkp_print "\t-d enable debug mode\n" 10 | lkp_print "\t-h list help\n" 11 | lkp_print "\nTo get more help, Please see the README.md\n" 12 | } 13 | 14 | source $ROOT_DIR/lib/env.sh 15 | source $ROOT_DIR/lib/log.sh 16 | 17 | # parse parameters 18 | while getopts ":hd" opt; do 19 | case $opt in 20 | d) set -x;; 21 | h) usage $PROGRAM && exit 1;; 22 | ?) usage $PROGRAM && exit 1;; 23 | esac 24 | done 25 | 26 | 27 | testcase="$@" # testcase group 28 | 29 | if [ ! -f $ROOT_DIR/testcases/$testcase ]; then 30 | lkp_show "Error: push testcase does not exist!" 31 | exit 0 32 | fi 33 | 34 | $SRC_PATH/build/lkp_extent_CLI PUSH $testcase $NODE_ID 0 $ROOT_DIR 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /sbin/result: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | help_doc="get the test result from nodes" 4 | 5 | usage() { 6 | lkp_show "Usage: $PNAME $1 [OPTION]" 7 | lkp_print "\nget the test result from nodes\n" 8 | lkp_print "\nOptions:\n" 9 | lkp_print "\t-d enable debug mode\n" 10 | lkp_print "\t-h list help\n" 11 | lkp_print "\nTo get more help, Please see the README.md\n" 12 | } 13 | 14 | source $ROOT_DIR/lib/env.sh 15 | source $ROOT_DIR/lib/log.sh 16 | 17 | # parse parameters 18 | while getopts ":hd" opt; do 19 | case $opt in 20 | d) set -x;; 21 | h) usage $PROGRAM && exit 1;; 22 | ?) usage $PROGRAM && exit 1;; 23 | esac 24 | done 25 | 26 | $SRC_PATH/build/lkp_extent_CLI RESULT null $NODE_ID 0 $ROOT_DIR 27 | 28 | -------------------------------------------------------------------------------- /sbin/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | help_doc="run the specified testcase" 4 | 5 | usage() { 6 | lkp_show "Usage: $PNAME $1 [OPTION] testcase" 7 | lkp_print "\nrun the specified testcase\n" 8 | lkp_print "\nOptions:\n" 9 | lkp_print "\t-d enable debug mode\n" 10 | lkp_print "\t-h list help\n" 11 | lkp_print "\nTo get more help, Please see the README.md\n" 12 | } 13 | 14 | source $ROOT_DIR/lib/env.sh 15 | source $ROOT_DIR/lib/log.sh 16 | source $ROOT_DIR/lib/lkp.sh 17 | source $ROOT_DIR/lib/container.sh 18 | 19 | [ $# -eq 0 ] && { 20 | usage $PROGRAM 21 | exit 1 22 | } 23 | 24 | # parse parameters 25 | while getopts ":hd" opt; do 26 | case $opt in 27 | d) set -x;; 28 | h) usage $PROGRAM && exit 1;; 29 | ?) usage $PROGRAM && exit 1;; 30 | esac 31 | done 32 | 33 | shift $((OPTIND - 1)) 34 | testcases="$@" # testcase group 35 | 36 | do_local_test(){ 37 | lkp_run_testcases "$LKP_DIR/jobs" "$JOB_WORKDIR" "$@" 38 | tar -cvf $JOB_WORKDIR/result.tar $JOB_WORKDIR/result/* 39 | cp $JOB_WORKDIR//result.tar $ROOT_DIR/results/local/ 40 | } 41 | 42 | current_run(){ 43 | # if VM_CNT > 0, start container test 44 | if [ $VM_CNT -gt 0 ]; then 45 | do_container_test "docker" $@ 46 | else 47 | do_local_test $@ 48 | fi 49 | } 50 | 51 | if [ -f $ROOT_DIR/results/local/result.tar ];then 52 | rm $ROOT_DIR/results/local/result.tar 53 | fi 54 | 55 | if [ $LOCAL_FLAG -eq 1 ] ; then 56 | current_run $@ 57 | else 58 | $SRC_PATH/build/lkp_extent_CLI RUN $testcases $NODE_ID $VM_CNT $ROOT_DIR 59 | fi 60 | 61 | -------------------------------------------------------------------------------- /sbin/start: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | help_doc="start lkp service" 4 | 5 | usage() { 6 | lkp_show "Usage: $PNAME $1 [OPTION]" 7 | lkp_print "\nstart lkp server\n" 8 | lkp_print "\nOptions:\n" 9 | lkp_print "\t-d enable debug mode\n" 10 | lkp_print "\t-h list help\n" 11 | lkp_print "\nTo get more help, Please see the README.md\n" 12 | } 13 | 14 | source $ROOT_DIR/lib/env.sh 15 | source $ROOT_DIR/lib/log.sh 16 | 17 | # parse parameters 18 | while getopts ":hd" opt; do 19 | case $opt in 20 | d) set -x;; 21 | h) usage $PROGRAM && exit 1;; 22 | ?) usage $PROGRAM && exit 1;; 23 | esac 24 | done 25 | 26 | $SRC_PATH/build/lkp_extent $ROOT_DIR $@ 27 | -------------------------------------------------------------------------------- /sbin/stop: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | help_doc="start lkp service" 4 | 5 | usage() { 6 | lkp_show "Usage: $PNAME $1 [OPTION]" 7 | lkp_print "\nstart lkp server\n" 8 | lkp_print "\nOptions:\n" 9 | lkp_print "\t-d enable debug mode\n" 10 | lkp_print "\t-h list help\n" 11 | lkp_print "\nTo get more help, Please see the README.md\n" 12 | } 13 | 14 | source $ROOT_DIR/lib/env.sh 15 | source $ROOT_DIR/lib/log.sh 16 | 17 | # parse parameters 18 | while getopts ":hd" opt; do 19 | case $opt in 20 | d) set -x;; 21 | h) usage $PROGRAM && exit 1;; 22 | ?) usage $PROGRAM && exit 1;; 23 | esac 24 | done 25 | 26 | set -e 27 | for pid in $(ps -ef | grep -E "lkp-extent/src/build|lkp-tests" | awk '$8 !~ /grep/,/stop/ {print $2}');do 28 | kill $pid 29 | done 30 | 31 | lkp_show "lkp-exent service stop!" 32 | -------------------------------------------------------------------------------- /sbin/update: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | help_doc="update testcase" 4 | 5 | usage() { 6 | lkp_show "Usage: $PNAME $1 [OPTION]" 7 | lkp_print "\nupdate testcase for lkp-extent \n" 8 | lkp_print "\nOptions:\n" 9 | lkp_print "\t-d enable debug mode\n" 10 | lkp_print "\t-h list help\n" 11 | lkp_print "\nTo get more help, Please see the README.md\n" 12 | } 13 | 14 | source $ROOT_DIR/lib/env.sh 15 | source $ROOT_DIR/lib/log.sh 16 | 17 | # parse parameters 18 | while getopts ":hd" opt; do 19 | case $opt in 20 | d) set -x;; 21 | h) usage $PROGRAM && exit 1;; 22 | ?) usage $PROGRAM && exit 1;; 23 | esac 24 | done 25 | 26 | do_update_current(){ 27 | lkp_show "git update $LKP_PRJ" 28 | cd $LKP_PRJ;git pull 29 | } 30 | 31 | if [ $LOCAL_FLAG -eq 1 ] ; then 32 | do_update_current 33 | else 34 | $SRC_PATH/build/lkp_extent_CLI UPDATE null $NODE_ID 0 $ROOT_DIR 35 | fi 36 | 37 | -------------------------------------------------------------------------------- /src/lib/lkpCodec.cc: -------------------------------------------------------------------------------- 1 | #include "lkpCodec.h" 2 | 3 | #include "muduo/base/Logging.h" 4 | #include "muduo/net/Endian.h" 5 | #include "muduo/net/protorpc/google-inl.h" 6 | 7 | #include 8 | 9 | #include // adler32 10 | 11 | using namespace muduo; 12 | using namespace muduo::net; 13 | 14 | void lkpCodec::fillEmptyBuffer(Buffer* buf, const google::protobuf::Message& message) 15 | { 16 | // buf->retrieveAll(); 17 | assert(buf->readableBytes() == 0); 18 | 19 | const std::string& typeName = message.GetTypeName(); 20 | int32_t nameLen = static_cast(typeName.size()+1); 21 | buf->appendInt32(nameLen); 22 | buf->append(typeName.c_str(), nameLen); 23 | 24 | // code copied from MessageLite::SerializeToArray() and MessageLite::SerializePartialToArray(). 25 | GOOGLE_DCHECK(message.IsInitialized()) << InitializationErrorMessage("serialize", message); 26 | 27 | /** 28 | * 'ByteSize()' of message is deprecated in Protocol Buffers v3.4.0 firstly. 29 | * But, till to v3.11.0, it just getting start to be marked by '__attribute__((deprecated()))'. 30 | * So, here, v3.9.2 is selected as maximum version using 'ByteSize()' to avoid 31 | * potential effect for previous muduo code/projects as far as possible. 32 | * Note: All information above just INFER from 33 | * 1) https://github.com/protocolbuffers/protobuf/releases/tag/v3.4.0 34 | * 2) MACRO in file 'include/google/protobuf/port_def.inc'. 35 | * eg. '#define PROTOBUF_DEPRECATED_MSG(msg) __attribute__((deprecated(msg)))'. 36 | * In addition, usage of 'ToIntSize()' comes from Impl of ByteSize() in new version's Protocol Buffers. 37 | */ 38 | 39 | #if GOOGLE_PROTOBUF_VERSION > 3009002 40 | int byte_size = google::protobuf::internal::ToIntSize(message.ByteSizeLong()); 41 | #else 42 | int byte_size = message.ByteSize(); 43 | #endif 44 | buf->ensureWritableBytes(byte_size); 45 | 46 | uint8_t* start = reinterpret_cast(buf->beginWrite()); 47 | uint8_t* end = message.SerializeWithCachedSizesToArray(start); 48 | if (end - start != byte_size) 49 | { 50 | #if GOOGLE_PROTOBUF_VERSION > 3009002 51 | ByteSizeConsistencyError(byte_size, google::protobuf::internal::ToIntSize(message.ByteSizeLong()), static_cast(end - start)); 52 | #else 53 | ByteSizeConsistencyError(byte_size, message.ByteSize(), static_cast(end - start)); 54 | #endif 55 | } 56 | buf->hasWritten(byte_size); 57 | 58 | int32_t checkSum = static_cast( 59 | ::adler32(1, 60 | reinterpret_cast(buf->peek()), 61 | static_cast(buf->readableBytes()))); 62 | buf->appendInt32(checkSum); 63 | assert(buf->readableBytes() == sizeof nameLen + nameLen + byte_size + sizeof checkSum); 64 | int32_t len = sockets::hostToNetwork32(static_cast(buf->readableBytes())); 65 | buf->prepend(&len, sizeof len); 66 | } 67 | 68 | // 69 | // no more google code after this 70 | // 71 | 72 | // 73 | // FIXME: merge with RpcCodec 74 | // 75 | 76 | namespace 77 | { 78 | const string kNoErrorStr = "NoError"; 79 | const string kInvalidLengthStr = "InvalidLength"; 80 | const string kCheckSumErrorStr = "CheckSumError"; 81 | const string kInvalidNameLenStr = "InvalidNameLen"; 82 | const string kUnknownMessageTypeStr = "UnknownMessageType"; 83 | const string kParseErrorStr = "ParseError"; 84 | const string kUnknownErrorStr = "UnknownError"; 85 | } 86 | 87 | const string& lkpCodec::errorCodeToString(ErrorCode errorCode) 88 | { 89 | switch (errorCode) 90 | { 91 | case kNoError: 92 | return kNoErrorStr; 93 | case kInvalidLength: 94 | return kInvalidLengthStr; 95 | case kCheckSumError: 96 | return kCheckSumErrorStr; 97 | case kInvalidNameLen: 98 | return kInvalidNameLenStr; 99 | case kUnknownMessageType: 100 | return kUnknownMessageTypeStr; 101 | case kParseError: 102 | return kParseErrorStr; 103 | default: 104 | return kUnknownErrorStr; 105 | } 106 | } 107 | 108 | void lkpCodec::defaultErrorCallback(const muduo::net::TcpConnectionPtr& conn, 109 | muduo::net::Buffer* buf, 110 | muduo::Timestamp, 111 | ErrorCode errorCode) 112 | { 113 | LOG_ERROR << "lkpCodec::defaultErrorCallback - " << errorCodeToString(errorCode); 114 | if (conn && conn->connected()) 115 | { 116 | conn->shutdown(); 117 | } 118 | } 119 | 120 | int32_t asInt32(const char* buf) 121 | { 122 | int32_t be32 = 0; 123 | ::memcpy(&be32, buf, sizeof(be32)); 124 | return sockets::networkToHost32(be32); 125 | } 126 | 127 | void lkpCodec::onMessage(const TcpConnectionPtr& conn, 128 | Buffer* buf, 129 | Timestamp receiveTime) 130 | { 131 | while (buf->readableBytes() >= kMinMessageLen + kHeaderLen) 132 | { 133 | const int32_t len = buf->peekInt32(); 134 | if (len > kMaxMessageLen || len < kMinMessageLen) 135 | { 136 | errorCallback_(conn, buf, receiveTime, kInvalidLength); 137 | break; 138 | } 139 | else if (buf->readableBytes() >= implicit_cast(len + kHeaderLen)) 140 | { 141 | ErrorCode errorCode = kNoError; 142 | MessagePtr message = parse(buf->peek()+kHeaderLen, len, &errorCode); 143 | if (errorCode == kNoError && message) 144 | { 145 | messageCallback_(conn, message, receiveTime); 146 | buf->retrieve(kHeaderLen+len); 147 | } 148 | else 149 | { 150 | errorCallback_(conn, buf, receiveTime, errorCode); 151 | break; 152 | } 153 | } 154 | else 155 | { 156 | break; 157 | } 158 | } 159 | } 160 | 161 | //根据typeName,利用protobuf功能生成descriptor,再根据descriptor生成prototype,最后message = prototype->New()形成定义的消息。 162 | google::protobuf::Message* lkpCodec::createMessage(const std::string& typeName) 163 | { 164 | google::protobuf::Message* message = NULL; 165 | const google::protobuf::Descriptor* descriptor = 166 | google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(typeName); 167 | if (descriptor) 168 | { 169 | const google::protobuf::Message* prototype = 170 | google::protobuf::MessageFactory::generated_factory()->GetPrototype(descriptor); 171 | if (prototype) 172 | { 173 | message = prototype->New(); 174 | } 175 | } 176 | return message; 177 | } 178 | 179 | //根据typeName,利用protobuf功能生成descriptor,再根据descriptor生成prototype,最后message = prototype->New()形成定义的消息。 180 | MessagePtr lkpCodec::parse(const char* buf, int len, ErrorCode* error) 181 | { 182 | MessagePtr message; 183 | 184 | // check sum 185 | int32_t expectedCheckSum = asInt32(buf + len - kHeaderLen); 186 | int32_t checkSum = static_cast( 187 | ::adler32(1, 188 | reinterpret_cast(buf), 189 | static_cast(len - kHeaderLen))); 190 | if (checkSum == expectedCheckSum) 191 | { 192 | // get message type name 193 | int32_t nameLen = asInt32(buf); 194 | if (nameLen >= 2 && nameLen <= len - 2*kHeaderLen) 195 | { 196 | std::string typeName(buf + kHeaderLen, buf + kHeaderLen + nameLen - 1); 197 | // create message object 198 | message.reset(createMessage(typeName)); 199 | if (message) 200 | { 201 | // parse from buffer 202 | const char* data = buf + kHeaderLen + nameLen; 203 | int32_t dataLen = len - nameLen - 2*kHeaderLen; 204 | if (message->ParseFromArray(data, dataLen)) 205 | { 206 | *error = kNoError; 207 | } 208 | else 209 | { 210 | *error = kParseError; 211 | } 212 | } 213 | else 214 | { 215 | *error = kUnknownMessageType; 216 | } 217 | } 218 | else 219 | { 220 | *error = kInvalidNameLen; 221 | } 222 | } 223 | else 224 | { 225 | *error = kCheckSumError; 226 | } 227 | 228 | return message; 229 | } 230 | -------------------------------------------------------------------------------- /src/lib/lkpCodec.h: -------------------------------------------------------------------------------- 1 | #ifndef LKP_CODEC_H 2 | #define LKP_CODEC_H 3 | 4 | #include "muduo/net/Buffer.h" 5 | #include "muduo/net/TcpConnection.h" 6 | 7 | #include 8 | 9 | // struct Format __attribute__ ((__packed__)) 10 | // { 11 | // int32_t len; 12 | // int32_t nameLen; 13 | // char typeName[nameLen]; 14 | // char protobufData[len-nameLen-8]; 15 | // int32_t checkSum; // adler32 of nameLen, typeName and protobufData 16 | // } 17 | 18 | typedef std::shared_ptr MessagePtr; 19 | 20 | // 21 | // FIXME: merge with RpcCodec 22 | // 23 | class lkpCodec : muduo::noncopyable 24 | { 25 | public: 26 | 27 | enum ErrorCode 28 | { 29 | kNoError = 0, 30 | kInvalidLength, 31 | kCheckSumError, 32 | kInvalidNameLen, 33 | kUnknownMessageType, 34 | kParseError, 35 | }; 36 | 37 | typedef std::function ProtobufMessageCallback; 40 | 41 | typedef std::function ErrorCallback; 45 | 46 | explicit lkpCodec(const ProtobufMessageCallback& messageCb) 47 | : messageCallback_(messageCb), 48 | errorCallback_(defaultErrorCallback) 49 | { 50 | } 51 | 52 | lkpCodec(const ProtobufMessageCallback& messageCb, const ErrorCallback& errorCb) 53 | : messageCallback_(messageCb), 54 | errorCallback_(errorCb) 55 | { 56 | } 57 | 58 | void onMessage(const muduo::net::TcpConnectionPtr& conn, 59 | muduo::net::Buffer* buf, 60 | muduo::Timestamp receiveTime); 61 | 62 | void send(const muduo::net::TcpConnectionPtr& conn, 63 | const google::protobuf::Message& message) 64 | { 65 | // FIXME: serialize to TcpConnection::outputBuffer() 66 | muduo::net::Buffer buf; 67 | fillEmptyBuffer(&buf, message); 68 | conn->send(&buf); 69 | } 70 | 71 | static const muduo::string& errorCodeToString(ErrorCode errorCode); 72 | static void fillEmptyBuffer(muduo::net::Buffer* buf, const google::protobuf::Message& message); 73 | static google::protobuf::Message* createMessage(const std::string& type_name); 74 | static MessagePtr parse(const char* buf, int len, ErrorCode* errorCode); 75 | 76 | private: 77 | static void defaultErrorCallback(const muduo::net::TcpConnectionPtr&, 78 | muduo::net::Buffer*, 79 | muduo::Timestamp, 80 | ErrorCode); 81 | 82 | ProtobufMessageCallback messageCallback_; 83 | ErrorCallback errorCallback_; 84 | 85 | const static int kHeaderLen = sizeof(int32_t); 86 | const static int kMinMessageLen = 2*kHeaderLen + 2; // nameLen + typeName + checkSum 87 | const static int kMaxMessageLen = 64*1024*1024; // same as codec_stream.h kDefaultTotalBytesLimit 88 | }; 89 | 90 | #endif // LKP_CODEC_H 91 | -------------------------------------------------------------------------------- /src/lib/lkpDispatcher.h: -------------------------------------------------------------------------------- 1 | #ifndef LKP_DISPATCHER_H 2 | #define LKP_DISPATCHER_H 3 | 4 | #include "muduo/base/noncopyable.h" 5 | #include "muduo/net/Callbacks.h" 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | 13 | typedef std::shared_ptr MessagePtr; 14 | 15 | class Callback : muduo::noncopyable 16 | { 17 | public: 18 | virtual ~Callback() = default; 19 | virtual void onMessage(const muduo::net::TcpConnectionPtr&, 20 | const MessagePtr& message, 21 | muduo::Timestamp) const = 0; 22 | }; 23 | 24 | //每种message对应一个CallbackT,内部包含一个callback_ 25 | template 26 | class CallbackT : public Callback 27 | { 28 | static_assert(std::is_base_of::value, 29 | "T must be derived from gpb::Message."); 30 | public: 31 | typedef std::function& message, 33 | muduo::Timestamp)> ProtobufMessageTCallback; 34 | 35 | CallbackT(const ProtobufMessageTCallback& callback) 36 | : callback_(callback) 37 | { 38 | } 39 | 40 | void onMessage(const muduo::net::TcpConnectionPtr& conn, 41 | const MessagePtr& message, 42 | muduo::Timestamp receiveTime) const override 43 | { 44 | std::shared_ptr concrete = muduo::down_pointer_cast(message); 45 | assert(concrete != NULL); 46 | callback_(conn, concrete, receiveTime); 47 | } 48 | 49 | private: 50 | ProtobufMessageTCallback callback_; 51 | }; 52 | 53 | class lkpDispatcher 54 | { 55 | public: 56 | typedef std::function ProtobufMessageCallback; 59 | 60 | explicit lkpDispatcher(const ProtobufMessageCallback& defaultCb) 61 | : defaultCallback_(defaultCb) 62 | { 63 | } 64 | 65 | //得到根据类型生成的message后调用 66 | void onProtobufMessage(const muduo::net::TcpConnectionPtr& conn, 67 | const MessagePtr& message, 68 | muduo::Timestamp receiveTime) const 69 | { 70 | CallbackMap::const_iterator it = callbacks_.find(message->GetDescriptor());//利用message内的descriptor从哈系表取出正确CallbackT 71 | if (it != callbacks_.end()) 72 | { 73 | it->second->onMessage(conn, message, receiveTime);//CallbackT内的onMessage是该类型消息的回调函数 74 | } 75 | else 76 | { 77 | defaultCallback_(conn, message, receiveTime); 78 | } 79 | } 80 | 81 | //T例如lkpMessage::Command 82 | template 83 | void registerMessageCallback(const typename CallbackT::ProtobufMessageTCallback& callback) 84 | { 85 | std::shared_ptr > pd(new CallbackT(callback)); 86 | callbacks_[T::descriptor()] = pd;//从lkpMessage::Command中取出descriptor 87 | } 88 | 89 | private: 90 | typedef std::map > CallbackMap; 91 | 92 | CallbackMap callbacks_; 93 | ProtobufMessageCallback defaultCallback_; 94 | }; 95 | #endif // LKP_DISPATCHER_H 96 | 97 | -------------------------------------------------------------------------------- /src/lib/lkpProto.pb.h: -------------------------------------------------------------------------------- 1 | // Generated by the protocol buffer compiler. DO NOT EDIT! 2 | // source: lkpProto.proto 3 | 4 | #ifndef PROTOBUF_lkpProto_2eproto__INCLUDED 5 | #define PROTOBUF_lkpProto_2eproto__INCLUDED 6 | 7 | #include 8 | 9 | #include 10 | 11 | #if GOOGLE_PROTOBUF_VERSION < 3000000 12 | #error This file was generated by a newer version of protoc which is 13 | #error incompatible with your Protocol Buffer headers. Please update 14 | #error your headers. 15 | #endif 16 | #if 3000000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION 17 | #error This file was generated by an older version of protoc which is 18 | #error incompatible with your Protocol Buffer headers. Please 19 | #error regenerate this file with a newer version of protoc. 20 | #endif 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | // @@protoc_insertion_point(includes) 32 | 33 | namespace lkpMessage { 34 | 35 | // Internal implementation detail -- do not call these. 36 | void protobuf_AddDesc_lkpProto_2eproto(); 37 | void protobuf_AssignDesc_lkpProto_2eproto(); 38 | void protobuf_ShutdownFile_lkpProto_2eproto(); 39 | 40 | class Command; 41 | class CommandACK; 42 | class File; 43 | class HeartBeat; 44 | class PushACK; 45 | class Return; 46 | class Return_NodeInfo; 47 | 48 | enum File_filetype { 49 | File_filetype_TESTCASE = 0, 50 | File_filetype_RESULT = 1, 51 | File_filetype_END = 2, 52 | File_filetype_File_filetype_INT_MIN_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32min, 53 | File_filetype_File_filetype_INT_MAX_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32max 54 | }; 55 | bool File_filetype_IsValid(int value); 56 | const File_filetype File_filetype_filetype_MIN = File_filetype_TESTCASE; 57 | const File_filetype File_filetype_filetype_MAX = File_filetype_END; 58 | const int File_filetype_filetype_ARRAYSIZE = File_filetype_filetype_MAX + 1; 59 | 60 | const ::google::protobuf::EnumDescriptor* File_filetype_descriptor(); 61 | inline const ::std::string& File_filetype_Name(File_filetype value) { 62 | return ::google::protobuf::internal::NameOfEnum( 63 | File_filetype_descriptor(), value); 64 | } 65 | inline bool File_filetype_Parse( 66 | const ::std::string& name, File_filetype* value) { 67 | return ::google::protobuf::internal::ParseNamedEnum( 68 | File_filetype_descriptor(), name, value); 69 | } 70 | enum commandID { 71 | UPDATE = 0, 72 | RUN = 1, 73 | RESULT = 2, 74 | PUSH = 3, 75 | LIST = 4, 76 | commandID_INT_MIN_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32min, 77 | commandID_INT_MAX_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32max 78 | }; 79 | bool commandID_IsValid(int value); 80 | const commandID commandID_MIN = UPDATE; 81 | const commandID commandID_MAX = LIST; 82 | const int commandID_ARRAYSIZE = commandID_MAX + 1; 83 | 84 | const ::google::protobuf::EnumDescriptor* commandID_descriptor(); 85 | inline const ::std::string& commandID_Name(commandID value) { 86 | return ::google::protobuf::internal::NameOfEnum( 87 | commandID_descriptor(), value); 88 | } 89 | inline bool commandID_Parse( 90 | const ::std::string& name, commandID* value) { 91 | return ::google::protobuf::internal::ParseNamedEnum( 92 | commandID_descriptor(), name, value); 93 | } 94 | // =================================================================== 95 | 96 | class Command : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:lkpMessage.Command) */ { 97 | public: 98 | Command(); 99 | virtual ~Command(); 100 | 101 | Command(const Command& from); 102 | 103 | inline Command& operator=(const Command& from) { 104 | CopyFrom(from); 105 | return *this; 106 | } 107 | 108 | static const ::google::protobuf::Descriptor* descriptor(); 109 | static const Command& default_instance(); 110 | 111 | void Swap(Command* other); 112 | 113 | // implements Message ---------------------------------------------- 114 | 115 | inline Command* New() const { return New(NULL); } 116 | 117 | Command* New(::google::protobuf::Arena* arena) const; 118 | void CopyFrom(const ::google::protobuf::Message& from); 119 | void MergeFrom(const ::google::protobuf::Message& from); 120 | void CopyFrom(const Command& from); 121 | void MergeFrom(const Command& from); 122 | void Clear(); 123 | bool IsInitialized() const; 124 | 125 | int ByteSize() const; 126 | bool MergePartialFromCodedStream( 127 | ::google::protobuf::io::CodedInputStream* input); 128 | void SerializeWithCachedSizes( 129 | ::google::protobuf::io::CodedOutputStream* output) const; 130 | ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( 131 | bool deterministic, ::google::protobuf::uint8* output) const; 132 | ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { 133 | return InternalSerializeWithCachedSizesToArray(false, output); 134 | } 135 | int GetCachedSize() const { return _cached_size_; } 136 | private: 137 | void SharedCtor(); 138 | void SharedDtor(); 139 | void SetCachedSize(int size) const; 140 | void InternalSwap(Command* other); 141 | private: 142 | inline ::google::protobuf::Arena* GetArenaNoVirtual() const { 143 | return _internal_metadata_.arena(); 144 | } 145 | inline void* MaybeArenaPtr() const { 146 | return _internal_metadata_.raw_arena_ptr(); 147 | } 148 | public: 149 | 150 | ::google::protobuf::Metadata GetMetadata() const; 151 | 152 | // nested types ---------------------------------------------------- 153 | 154 | // accessors ------------------------------------------------------- 155 | 156 | // optional .lkpMessage.commandID command = 1; 157 | void clear_command(); 158 | static const int kCommandFieldNumber = 1; 159 | ::lkpMessage::commandID command() const; 160 | void set_command(::lkpMessage::commandID value); 161 | 162 | // optional bool send_to_all = 2; 163 | void clear_send_to_all(); 164 | static const int kSendToAllFieldNumber = 2; 165 | bool send_to_all() const; 166 | void set_send_to_all(bool value); 167 | 168 | // optional string testcase = 3; 169 | void clear_testcase(); 170 | static const int kTestcaseFieldNumber = 3; 171 | const ::std::string& testcase() const; 172 | void set_testcase(const ::std::string& value); 173 | void set_testcase(const char* value); 174 | void set_testcase(const char* value, size_t size); 175 | ::std::string* mutable_testcase(); 176 | ::std::string* release_testcase(); 177 | void set_allocated_testcase(::std::string* testcase); 178 | 179 | // optional uint32 docker_num = 4; 180 | void clear_docker_num(); 181 | static const int kDockerNumFieldNumber = 4; 182 | ::google::protobuf::uint32 docker_num() const; 183 | void set_docker_num(::google::protobuf::uint32 value); 184 | 185 | // optional uint32 tesetcase_len = 5; 186 | void clear_tesetcase_len(); 187 | static const int kTesetcaseLenFieldNumber = 5; 188 | ::google::protobuf::uint32 tesetcase_len() const; 189 | void set_tesetcase_len(::google::protobuf::uint32 value); 190 | 191 | // optional uint32 node_id = 6; 192 | void clear_node_id(); 193 | static const int kNodeIdFieldNumber = 6; 194 | ::google::protobuf::uint32 node_id() const; 195 | void set_node_id(::google::protobuf::uint32 value); 196 | 197 | // @@protoc_insertion_point(class_scope:lkpMessage.Command) 198 | private: 199 | 200 | ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; 201 | bool _is_default_instance_; 202 | int command_; 203 | bool send_to_all_; 204 | ::google::protobuf::internal::ArenaStringPtr testcase_; 205 | ::google::protobuf::uint32 docker_num_; 206 | ::google::protobuf::uint32 tesetcase_len_; 207 | ::google::protobuf::uint32 node_id_; 208 | mutable int _cached_size_; 209 | friend void protobuf_AddDesc_lkpProto_2eproto(); 210 | friend void protobuf_AssignDesc_lkpProto_2eproto(); 211 | friend void protobuf_ShutdownFile_lkpProto_2eproto(); 212 | 213 | void InitAsDefaultInstance(); 214 | static Command* default_instance_; 215 | }; 216 | // ------------------------------------------------------------------- 217 | 218 | class File : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:lkpMessage.File) */ { 219 | public: 220 | File(); 221 | virtual ~File(); 222 | 223 | File(const File& from); 224 | 225 | inline File& operator=(const File& from) { 226 | CopyFrom(from); 227 | return *this; 228 | } 229 | 230 | static const ::google::protobuf::Descriptor* descriptor(); 231 | static const File& default_instance(); 232 | 233 | void Swap(File* other); 234 | 235 | // implements Message ---------------------------------------------- 236 | 237 | inline File* New() const { return New(NULL); } 238 | 239 | File* New(::google::protobuf::Arena* arena) const; 240 | void CopyFrom(const ::google::protobuf::Message& from); 241 | void MergeFrom(const ::google::protobuf::Message& from); 242 | void CopyFrom(const File& from); 243 | void MergeFrom(const File& from); 244 | void Clear(); 245 | bool IsInitialized() const; 246 | 247 | int ByteSize() const; 248 | bool MergePartialFromCodedStream( 249 | ::google::protobuf::io::CodedInputStream* input); 250 | void SerializeWithCachedSizes( 251 | ::google::protobuf::io::CodedOutputStream* output) const; 252 | ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( 253 | bool deterministic, ::google::protobuf::uint8* output) const; 254 | ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { 255 | return InternalSerializeWithCachedSizesToArray(false, output); 256 | } 257 | int GetCachedSize() const { return _cached_size_; } 258 | private: 259 | void SharedCtor(); 260 | void SharedDtor(); 261 | void SetCachedSize(int size) const; 262 | void InternalSwap(File* other); 263 | private: 264 | inline ::google::protobuf::Arena* GetArenaNoVirtual() const { 265 | return _internal_metadata_.arena(); 266 | } 267 | inline void* MaybeArenaPtr() const { 268 | return _internal_metadata_.raw_arena_ptr(); 269 | } 270 | public: 271 | 272 | ::google::protobuf::Metadata GetMetadata() const; 273 | 274 | // nested types ---------------------------------------------------- 275 | 276 | typedef File_filetype filetype; 277 | static const filetype TESTCASE = 278 | File_filetype_TESTCASE; 279 | static const filetype RESULT = 280 | File_filetype_RESULT; 281 | static const filetype END = 282 | File_filetype_END; 283 | static inline bool filetype_IsValid(int value) { 284 | return File_filetype_IsValid(value); 285 | } 286 | static const filetype filetype_MIN = 287 | File_filetype_filetype_MIN; 288 | static const filetype filetype_MAX = 289 | File_filetype_filetype_MAX; 290 | static const int filetype_ARRAYSIZE = 291 | File_filetype_filetype_ARRAYSIZE; 292 | static inline const ::google::protobuf::EnumDescriptor* 293 | filetype_descriptor() { 294 | return File_filetype_descriptor(); 295 | } 296 | static inline const ::std::string& filetype_Name(filetype value) { 297 | return File_filetype_Name(value); 298 | } 299 | static inline bool filetype_Parse(const ::std::string& name, 300 | filetype* value) { 301 | return File_filetype_Parse(name, value); 302 | } 303 | 304 | // accessors ------------------------------------------------------- 305 | 306 | // optional .lkpMessage.File.filetype file_type = 1; 307 | void clear_file_type(); 308 | static const int kFileTypeFieldNumber = 1; 309 | ::lkpMessage::File_filetype file_type() const; 310 | void set_file_type(::lkpMessage::File_filetype value); 311 | 312 | // optional string file_name = 2; 313 | void clear_file_name(); 314 | static const int kFileNameFieldNumber = 2; 315 | const ::std::string& file_name() const; 316 | void set_file_name(const ::std::string& value); 317 | void set_file_name(const char* value); 318 | void set_file_name(const char* value, size_t size); 319 | ::std::string* mutable_file_name(); 320 | ::std::string* release_file_name(); 321 | void set_allocated_file_name(::std::string* file_name); 322 | 323 | // optional uint32 patch_len = 3; 324 | void clear_patch_len(); 325 | static const int kPatchLenFieldNumber = 3; 326 | ::google::protobuf::uint32 patch_len() const; 327 | void set_patch_len(::google::protobuf::uint32 value); 328 | 329 | // optional uint32 file_size = 4; 330 | void clear_file_size(); 331 | static const int kFileSizeFieldNumber = 4; 332 | ::google::protobuf::uint32 file_size() const; 333 | void set_file_size(::google::protobuf::uint32 value); 334 | 335 | // optional bool first_patch = 5; 336 | void clear_first_patch(); 337 | static const int kFirstPatchFieldNumber = 5; 338 | bool first_patch() const; 339 | void set_first_patch(bool value); 340 | 341 | // optional bytes content = 6; 342 | void clear_content(); 343 | static const int kContentFieldNumber = 6; 344 | const ::std::string& content() const; 345 | void set_content(const ::std::string& value); 346 | void set_content(const char* value); 347 | void set_content(const void* value, size_t size); 348 | ::std::string* mutable_content(); 349 | ::std::string* release_content(); 350 | void set_allocated_content(::std::string* content); 351 | 352 | // optional uint32 node_id = 7; 353 | void clear_node_id(); 354 | static const int kNodeIdFieldNumber = 7; 355 | ::google::protobuf::uint32 node_id() const; 356 | void set_node_id(::google::protobuf::uint32 value); 357 | 358 | // @@protoc_insertion_point(class_scope:lkpMessage.File) 359 | private: 360 | 361 | ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; 362 | bool _is_default_instance_; 363 | ::google::protobuf::internal::ArenaStringPtr file_name_; 364 | int file_type_; 365 | ::google::protobuf::uint32 patch_len_; 366 | ::google::protobuf::uint32 file_size_; 367 | bool first_patch_; 368 | ::google::protobuf::internal::ArenaStringPtr content_; 369 | ::google::protobuf::uint32 node_id_; 370 | mutable int _cached_size_; 371 | friend void protobuf_AddDesc_lkpProto_2eproto(); 372 | friend void protobuf_AssignDesc_lkpProto_2eproto(); 373 | friend void protobuf_ShutdownFile_lkpProto_2eproto(); 374 | 375 | void InitAsDefaultInstance(); 376 | static File* default_instance_; 377 | }; 378 | // ------------------------------------------------------------------- 379 | 380 | class CommandACK : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:lkpMessage.CommandACK) */ { 381 | public: 382 | CommandACK(); 383 | virtual ~CommandACK(); 384 | 385 | CommandACK(const CommandACK& from); 386 | 387 | inline CommandACK& operator=(const CommandACK& from) { 388 | CopyFrom(from); 389 | return *this; 390 | } 391 | 392 | static const ::google::protobuf::Descriptor* descriptor(); 393 | static const CommandACK& default_instance(); 394 | 395 | void Swap(CommandACK* other); 396 | 397 | // implements Message ---------------------------------------------- 398 | 399 | inline CommandACK* New() const { return New(NULL); } 400 | 401 | CommandACK* New(::google::protobuf::Arena* arena) const; 402 | void CopyFrom(const ::google::protobuf::Message& from); 403 | void MergeFrom(const ::google::protobuf::Message& from); 404 | void CopyFrom(const CommandACK& from); 405 | void MergeFrom(const CommandACK& from); 406 | void Clear(); 407 | bool IsInitialized() const; 408 | 409 | int ByteSize() const; 410 | bool MergePartialFromCodedStream( 411 | ::google::protobuf::io::CodedInputStream* input); 412 | void SerializeWithCachedSizes( 413 | ::google::protobuf::io::CodedOutputStream* output) const; 414 | ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( 415 | bool deterministic, ::google::protobuf::uint8* output) const; 416 | ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { 417 | return InternalSerializeWithCachedSizesToArray(false, output); 418 | } 419 | int GetCachedSize() const { return _cached_size_; } 420 | private: 421 | void SharedCtor(); 422 | void SharedDtor(); 423 | void SetCachedSize(int size) const; 424 | void InternalSwap(CommandACK* other); 425 | private: 426 | inline ::google::protobuf::Arena* GetArenaNoVirtual() const { 427 | return _internal_metadata_.arena(); 428 | } 429 | inline void* MaybeArenaPtr() const { 430 | return _internal_metadata_.raw_arena_ptr(); 431 | } 432 | public: 433 | 434 | ::google::protobuf::Metadata GetMetadata() const; 435 | 436 | // nested types ---------------------------------------------------- 437 | 438 | // accessors ------------------------------------------------------- 439 | 440 | // optional bool status = 1; 441 | void clear_status(); 442 | static const int kStatusFieldNumber = 1; 443 | bool status() const; 444 | void set_status(bool value); 445 | 446 | // optional .lkpMessage.commandID command = 2; 447 | void clear_command(); 448 | static const int kCommandFieldNumber = 2; 449 | ::lkpMessage::commandID command() const; 450 | void set_command(::lkpMessage::commandID value); 451 | 452 | // optional string ack_message = 3; 453 | void clear_ack_message(); 454 | static const int kAckMessageFieldNumber = 3; 455 | const ::std::string& ack_message() const; 456 | void set_ack_message(const ::std::string& value); 457 | void set_ack_message(const char* value); 458 | void set_ack_message(const char* value, size_t size); 459 | ::std::string* mutable_ack_message(); 460 | ::std::string* release_ack_message(); 461 | void set_allocated_ack_message(::std::string* ack_message); 462 | 463 | // optional uint32 node_id = 4; 464 | void clear_node_id(); 465 | static const int kNodeIdFieldNumber = 4; 466 | ::google::protobuf::uint32 node_id() const; 467 | void set_node_id(::google::protobuf::uint32 value); 468 | 469 | // @@protoc_insertion_point(class_scope:lkpMessage.CommandACK) 470 | private: 471 | 472 | ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; 473 | bool _is_default_instance_; 474 | bool status_; 475 | int command_; 476 | ::google::protobuf::internal::ArenaStringPtr ack_message_; 477 | ::google::protobuf::uint32 node_id_; 478 | mutable int _cached_size_; 479 | friend void protobuf_AddDesc_lkpProto_2eproto(); 480 | friend void protobuf_AssignDesc_lkpProto_2eproto(); 481 | friend void protobuf_ShutdownFile_lkpProto_2eproto(); 482 | 483 | void InitAsDefaultInstance(); 484 | static CommandACK* default_instance_; 485 | }; 486 | // ------------------------------------------------------------------- 487 | 488 | class HeartBeat : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:lkpMessage.HeartBeat) */ { 489 | public: 490 | HeartBeat(); 491 | virtual ~HeartBeat(); 492 | 493 | HeartBeat(const HeartBeat& from); 494 | 495 | inline HeartBeat& operator=(const HeartBeat& from) { 496 | CopyFrom(from); 497 | return *this; 498 | } 499 | 500 | static const ::google::protobuf::Descriptor* descriptor(); 501 | static const HeartBeat& default_instance(); 502 | 503 | void Swap(HeartBeat* other); 504 | 505 | // implements Message ---------------------------------------------- 506 | 507 | inline HeartBeat* New() const { return New(NULL); } 508 | 509 | HeartBeat* New(::google::protobuf::Arena* arena) const; 510 | void CopyFrom(const ::google::protobuf::Message& from); 511 | void MergeFrom(const ::google::protobuf::Message& from); 512 | void CopyFrom(const HeartBeat& from); 513 | void MergeFrom(const HeartBeat& from); 514 | void Clear(); 515 | bool IsInitialized() const; 516 | 517 | int ByteSize() const; 518 | bool MergePartialFromCodedStream( 519 | ::google::protobuf::io::CodedInputStream* input); 520 | void SerializeWithCachedSizes( 521 | ::google::protobuf::io::CodedOutputStream* output) const; 522 | ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( 523 | bool deterministic, ::google::protobuf::uint8* output) const; 524 | ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { 525 | return InternalSerializeWithCachedSizesToArray(false, output); 526 | } 527 | int GetCachedSize() const { return _cached_size_; } 528 | private: 529 | void SharedCtor(); 530 | void SharedDtor(); 531 | void SetCachedSize(int size) const; 532 | void InternalSwap(HeartBeat* other); 533 | private: 534 | inline ::google::protobuf::Arena* GetArenaNoVirtual() const { 535 | return _internal_metadata_.arena(); 536 | } 537 | inline void* MaybeArenaPtr() const { 538 | return _internal_metadata_.raw_arena_ptr(); 539 | } 540 | public: 541 | 542 | ::google::protobuf::Metadata GetMetadata() const; 543 | 544 | // nested types ---------------------------------------------------- 545 | 546 | // accessors ------------------------------------------------------- 547 | 548 | // optional bool status = 1; 549 | void clear_status(); 550 | static const int kStatusFieldNumber = 1; 551 | bool status() const; 552 | void set_status(bool value); 553 | 554 | // @@protoc_insertion_point(class_scope:lkpMessage.HeartBeat) 555 | private: 556 | 557 | ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; 558 | bool _is_default_instance_; 559 | bool status_; 560 | mutable int _cached_size_; 561 | friend void protobuf_AddDesc_lkpProto_2eproto(); 562 | friend void protobuf_AssignDesc_lkpProto_2eproto(); 563 | friend void protobuf_ShutdownFile_lkpProto_2eproto(); 564 | 565 | void InitAsDefaultInstance(); 566 | static HeartBeat* default_instance_; 567 | }; 568 | // ------------------------------------------------------------------- 569 | 570 | class PushACK : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:lkpMessage.PushACK) */ { 571 | public: 572 | PushACK(); 573 | virtual ~PushACK(); 574 | 575 | PushACK(const PushACK& from); 576 | 577 | inline PushACK& operator=(const PushACK& from) { 578 | CopyFrom(from); 579 | return *this; 580 | } 581 | 582 | static const ::google::protobuf::Descriptor* descriptor(); 583 | static const PushACK& default_instance(); 584 | 585 | void Swap(PushACK* other); 586 | 587 | // implements Message ---------------------------------------------- 588 | 589 | inline PushACK* New() const { return New(NULL); } 590 | 591 | PushACK* New(::google::protobuf::Arena* arena) const; 592 | void CopyFrom(const ::google::protobuf::Message& from); 593 | void MergeFrom(const ::google::protobuf::Message& from); 594 | void CopyFrom(const PushACK& from); 595 | void MergeFrom(const PushACK& from); 596 | void Clear(); 597 | bool IsInitialized() const; 598 | 599 | int ByteSize() const; 600 | bool MergePartialFromCodedStream( 601 | ::google::protobuf::io::CodedInputStream* input); 602 | void SerializeWithCachedSizes( 603 | ::google::protobuf::io::CodedOutputStream* output) const; 604 | ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( 605 | bool deterministic, ::google::protobuf::uint8* output) const; 606 | ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { 607 | return InternalSerializeWithCachedSizesToArray(false, output); 608 | } 609 | int GetCachedSize() const { return _cached_size_; } 610 | private: 611 | void SharedCtor(); 612 | void SharedDtor(); 613 | void SetCachedSize(int size) const; 614 | void InternalSwap(PushACK* other); 615 | private: 616 | inline ::google::protobuf::Arena* GetArenaNoVirtual() const { 617 | return _internal_metadata_.arena(); 618 | } 619 | inline void* MaybeArenaPtr() const { 620 | return _internal_metadata_.raw_arena_ptr(); 621 | } 622 | public: 623 | 624 | ::google::protobuf::Metadata GetMetadata() const; 625 | 626 | // nested types ---------------------------------------------------- 627 | 628 | // accessors ------------------------------------------------------- 629 | 630 | // optional bool status = 1; 631 | void clear_status(); 632 | static const int kStatusFieldNumber = 1; 633 | bool status() const; 634 | void set_status(bool value); 635 | 636 | // optional string ack_message = 2; 637 | void clear_ack_message(); 638 | static const int kAckMessageFieldNumber = 2; 639 | const ::std::string& ack_message() const; 640 | void set_ack_message(const ::std::string& value); 641 | void set_ack_message(const char* value); 642 | void set_ack_message(const char* value, size_t size); 643 | ::std::string* mutable_ack_message(); 644 | ::std::string* release_ack_message(); 645 | void set_allocated_ack_message(::std::string* ack_message); 646 | 647 | // optional uint32 node_id = 3; 648 | void clear_node_id(); 649 | static const int kNodeIdFieldNumber = 3; 650 | ::google::protobuf::uint32 node_id() const; 651 | void set_node_id(::google::protobuf::uint32 value); 652 | 653 | // @@protoc_insertion_point(class_scope:lkpMessage.PushACK) 654 | private: 655 | 656 | ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; 657 | bool _is_default_instance_; 658 | ::google::protobuf::internal::ArenaStringPtr ack_message_; 659 | bool status_; 660 | ::google::protobuf::uint32 node_id_; 661 | mutable int _cached_size_; 662 | friend void protobuf_AddDesc_lkpProto_2eproto(); 663 | friend void protobuf_AssignDesc_lkpProto_2eproto(); 664 | friend void protobuf_ShutdownFile_lkpProto_2eproto(); 665 | 666 | void InitAsDefaultInstance(); 667 | static PushACK* default_instance_; 668 | }; 669 | // ------------------------------------------------------------------- 670 | 671 | class Return_NodeInfo : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:lkpMessage.Return.NodeInfo) */ { 672 | public: 673 | Return_NodeInfo(); 674 | virtual ~Return_NodeInfo(); 675 | 676 | Return_NodeInfo(const Return_NodeInfo& from); 677 | 678 | inline Return_NodeInfo& operator=(const Return_NodeInfo& from) { 679 | CopyFrom(from); 680 | return *this; 681 | } 682 | 683 | static const ::google::protobuf::Descriptor* descriptor(); 684 | static const Return_NodeInfo& default_instance(); 685 | 686 | void Swap(Return_NodeInfo* other); 687 | 688 | // implements Message ---------------------------------------------- 689 | 690 | inline Return_NodeInfo* New() const { return New(NULL); } 691 | 692 | Return_NodeInfo* New(::google::protobuf::Arena* arena) const; 693 | void CopyFrom(const ::google::protobuf::Message& from); 694 | void MergeFrom(const ::google::protobuf::Message& from); 695 | void CopyFrom(const Return_NodeInfo& from); 696 | void MergeFrom(const Return_NodeInfo& from); 697 | void Clear(); 698 | bool IsInitialized() const; 699 | 700 | int ByteSize() const; 701 | bool MergePartialFromCodedStream( 702 | ::google::protobuf::io::CodedInputStream* input); 703 | void SerializeWithCachedSizes( 704 | ::google::protobuf::io::CodedOutputStream* output) const; 705 | ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( 706 | bool deterministic, ::google::protobuf::uint8* output) const; 707 | ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { 708 | return InternalSerializeWithCachedSizesToArray(false, output); 709 | } 710 | int GetCachedSize() const { return _cached_size_; } 711 | private: 712 | void SharedCtor(); 713 | void SharedDtor(); 714 | void SetCachedSize(int size) const; 715 | void InternalSwap(Return_NodeInfo* other); 716 | private: 717 | inline ::google::protobuf::Arena* GetArenaNoVirtual() const { 718 | return _internal_metadata_.arena(); 719 | } 720 | inline void* MaybeArenaPtr() const { 721 | return _internal_metadata_.raw_arena_ptr(); 722 | } 723 | public: 724 | 725 | ::google::protobuf::Metadata GetMetadata() const; 726 | 727 | // nested types ---------------------------------------------------- 728 | 729 | // accessors ------------------------------------------------------- 730 | 731 | // optional uint32 node_id = 1; 732 | void clear_node_id(); 733 | static const int kNodeIdFieldNumber = 1; 734 | ::google::protobuf::uint32 node_id() const; 735 | void set_node_id(::google::protobuf::uint32 value); 736 | 737 | // optional string node_msg = 2; 738 | void clear_node_msg(); 739 | static const int kNodeMsgFieldNumber = 2; 740 | const ::std::string& node_msg() const; 741 | void set_node_msg(const ::std::string& value); 742 | void set_node_msg(const char* value); 743 | void set_node_msg(const char* value, size_t size); 744 | ::std::string* mutable_node_msg(); 745 | ::std::string* release_node_msg(); 746 | void set_allocated_node_msg(::std::string* node_msg); 747 | 748 | // @@protoc_insertion_point(class_scope:lkpMessage.Return.NodeInfo) 749 | private: 750 | 751 | ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; 752 | bool _is_default_instance_; 753 | ::google::protobuf::internal::ArenaStringPtr node_msg_; 754 | ::google::protobuf::uint32 node_id_; 755 | mutable int _cached_size_; 756 | friend void protobuf_AddDesc_lkpProto_2eproto(); 757 | friend void protobuf_AssignDesc_lkpProto_2eproto(); 758 | friend void protobuf_ShutdownFile_lkpProto_2eproto(); 759 | 760 | void InitAsDefaultInstance(); 761 | static Return_NodeInfo* default_instance_; 762 | }; 763 | // ------------------------------------------------------------------- 764 | 765 | class Return : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:lkpMessage.Return) */ { 766 | public: 767 | Return(); 768 | virtual ~Return(); 769 | 770 | Return(const Return& from); 771 | 772 | inline Return& operator=(const Return& from) { 773 | CopyFrom(from); 774 | return *this; 775 | } 776 | 777 | static const ::google::protobuf::Descriptor* descriptor(); 778 | static const Return& default_instance(); 779 | 780 | void Swap(Return* other); 781 | 782 | // implements Message ---------------------------------------------- 783 | 784 | inline Return* New() const { return New(NULL); } 785 | 786 | Return* New(::google::protobuf::Arena* arena) const; 787 | void CopyFrom(const ::google::protobuf::Message& from); 788 | void MergeFrom(const ::google::protobuf::Message& from); 789 | void CopyFrom(const Return& from); 790 | void MergeFrom(const Return& from); 791 | void Clear(); 792 | bool IsInitialized() const; 793 | 794 | int ByteSize() const; 795 | bool MergePartialFromCodedStream( 796 | ::google::protobuf::io::CodedInputStream* input); 797 | void SerializeWithCachedSizes( 798 | ::google::protobuf::io::CodedOutputStream* output) const; 799 | ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( 800 | bool deterministic, ::google::protobuf::uint8* output) const; 801 | ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { 802 | return InternalSerializeWithCachedSizesToArray(false, output); 803 | } 804 | int GetCachedSize() const { return _cached_size_; } 805 | private: 806 | void SharedCtor(); 807 | void SharedDtor(); 808 | void SetCachedSize(int size) const; 809 | void InternalSwap(Return* other); 810 | private: 811 | inline ::google::protobuf::Arena* GetArenaNoVirtual() const { 812 | return _internal_metadata_.arena(); 813 | } 814 | inline void* MaybeArenaPtr() const { 815 | return _internal_metadata_.raw_arena_ptr(); 816 | } 817 | public: 818 | 819 | ::google::protobuf::Metadata GetMetadata() const; 820 | 821 | // nested types ---------------------------------------------------- 822 | 823 | typedef Return_NodeInfo NodeInfo; 824 | 825 | // accessors ------------------------------------------------------- 826 | 827 | // optional uint32 client_num = 1; 828 | void clear_client_num(); 829 | static const int kClientNumFieldNumber = 1; 830 | ::google::protobuf::uint32 client_num() const; 831 | void set_client_num(::google::protobuf::uint32 value); 832 | 833 | // optional uint32 client_ok_num = 2; 834 | void clear_client_ok_num(); 835 | static const int kClientOkNumFieldNumber = 2; 836 | ::google::protobuf::uint32 client_ok_num() const; 837 | void set_client_ok_num(::google::protobuf::uint32 value); 838 | 839 | // optional .lkpMessage.commandID command = 3; 840 | void clear_command(); 841 | static const int kCommandFieldNumber = 3; 842 | ::lkpMessage::commandID command() const; 843 | void set_command(::lkpMessage::commandID value); 844 | 845 | // repeated .lkpMessage.Return.NodeInfo node_info = 4; 846 | int node_info_size() const; 847 | void clear_node_info(); 848 | static const int kNodeInfoFieldNumber = 4; 849 | const ::lkpMessage::Return_NodeInfo& node_info(int index) const; 850 | ::lkpMessage::Return_NodeInfo* mutable_node_info(int index); 851 | ::lkpMessage::Return_NodeInfo* add_node_info(); 852 | ::google::protobuf::RepeatedPtrField< ::lkpMessage::Return_NodeInfo >* 853 | mutable_node_info(); 854 | const ::google::protobuf::RepeatedPtrField< ::lkpMessage::Return_NodeInfo >& 855 | node_info() const; 856 | 857 | // @@protoc_insertion_point(class_scope:lkpMessage.Return) 858 | private: 859 | 860 | ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; 861 | bool _is_default_instance_; 862 | ::google::protobuf::uint32 client_num_; 863 | ::google::protobuf::uint32 client_ok_num_; 864 | ::google::protobuf::RepeatedPtrField< ::lkpMessage::Return_NodeInfo > node_info_; 865 | int command_; 866 | mutable int _cached_size_; 867 | friend void protobuf_AddDesc_lkpProto_2eproto(); 868 | friend void protobuf_AssignDesc_lkpProto_2eproto(); 869 | friend void protobuf_ShutdownFile_lkpProto_2eproto(); 870 | 871 | void InitAsDefaultInstance(); 872 | static Return* default_instance_; 873 | }; 874 | // =================================================================== 875 | 876 | 877 | // =================================================================== 878 | 879 | #if !PROTOBUF_INLINE_NOT_IN_HEADERS 880 | // Command 881 | 882 | // optional .lkpMessage.commandID command = 1; 883 | inline void Command::clear_command() { 884 | command_ = 0; 885 | } 886 | inline ::lkpMessage::commandID Command::command() const { 887 | // @@protoc_insertion_point(field_get:lkpMessage.Command.command) 888 | return static_cast< ::lkpMessage::commandID >(command_); 889 | } 890 | inline void Command::set_command(::lkpMessage::commandID value) { 891 | 892 | command_ = value; 893 | // @@protoc_insertion_point(field_set:lkpMessage.Command.command) 894 | } 895 | 896 | // optional bool send_to_all = 2; 897 | inline void Command::clear_send_to_all() { 898 | send_to_all_ = false; 899 | } 900 | inline bool Command::send_to_all() const { 901 | // @@protoc_insertion_point(field_get:lkpMessage.Command.send_to_all) 902 | return send_to_all_; 903 | } 904 | inline void Command::set_send_to_all(bool value) { 905 | 906 | send_to_all_ = value; 907 | // @@protoc_insertion_point(field_set:lkpMessage.Command.send_to_all) 908 | } 909 | 910 | // optional string testcase = 3; 911 | inline void Command::clear_testcase() { 912 | testcase_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 913 | } 914 | inline const ::std::string& Command::testcase() const { 915 | // @@protoc_insertion_point(field_get:lkpMessage.Command.testcase) 916 | return testcase_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 917 | } 918 | inline void Command::set_testcase(const ::std::string& value) { 919 | 920 | testcase_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); 921 | // @@protoc_insertion_point(field_set:lkpMessage.Command.testcase) 922 | } 923 | inline void Command::set_testcase(const char* value) { 924 | 925 | testcase_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); 926 | // @@protoc_insertion_point(field_set_char:lkpMessage.Command.testcase) 927 | } 928 | inline void Command::set_testcase(const char* value, size_t size) { 929 | 930 | testcase_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), 931 | ::std::string(reinterpret_cast(value), size)); 932 | // @@protoc_insertion_point(field_set_pointer:lkpMessage.Command.testcase) 933 | } 934 | inline ::std::string* Command::mutable_testcase() { 935 | 936 | // @@protoc_insertion_point(field_mutable:lkpMessage.Command.testcase) 937 | return testcase_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 938 | } 939 | inline ::std::string* Command::release_testcase() { 940 | // @@protoc_insertion_point(field_release:lkpMessage.Command.testcase) 941 | 942 | return testcase_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 943 | } 944 | inline void Command::set_allocated_testcase(::std::string* testcase) { 945 | if (testcase != NULL) { 946 | 947 | } else { 948 | 949 | } 950 | testcase_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), testcase); 951 | // @@protoc_insertion_point(field_set_allocated:lkpMessage.Command.testcase) 952 | } 953 | 954 | // optional uint32 docker_num = 4; 955 | inline void Command::clear_docker_num() { 956 | docker_num_ = 0u; 957 | } 958 | inline ::google::protobuf::uint32 Command::docker_num() const { 959 | // @@protoc_insertion_point(field_get:lkpMessage.Command.docker_num) 960 | return docker_num_; 961 | } 962 | inline void Command::set_docker_num(::google::protobuf::uint32 value) { 963 | 964 | docker_num_ = value; 965 | // @@protoc_insertion_point(field_set:lkpMessage.Command.docker_num) 966 | } 967 | 968 | // optional uint32 tesetcase_len = 5; 969 | inline void Command::clear_tesetcase_len() { 970 | tesetcase_len_ = 0u; 971 | } 972 | inline ::google::protobuf::uint32 Command::tesetcase_len() const { 973 | // @@protoc_insertion_point(field_get:lkpMessage.Command.tesetcase_len) 974 | return tesetcase_len_; 975 | } 976 | inline void Command::set_tesetcase_len(::google::protobuf::uint32 value) { 977 | 978 | tesetcase_len_ = value; 979 | // @@protoc_insertion_point(field_set:lkpMessage.Command.tesetcase_len) 980 | } 981 | 982 | // optional uint32 node_id = 6; 983 | inline void Command::clear_node_id() { 984 | node_id_ = 0u; 985 | } 986 | inline ::google::protobuf::uint32 Command::node_id() const { 987 | // @@protoc_insertion_point(field_get:lkpMessage.Command.node_id) 988 | return node_id_; 989 | } 990 | inline void Command::set_node_id(::google::protobuf::uint32 value) { 991 | 992 | node_id_ = value; 993 | // @@protoc_insertion_point(field_set:lkpMessage.Command.node_id) 994 | } 995 | 996 | // ------------------------------------------------------------------- 997 | 998 | // File 999 | 1000 | // optional .lkpMessage.File.filetype file_type = 1; 1001 | inline void File::clear_file_type() { 1002 | file_type_ = 0; 1003 | } 1004 | inline ::lkpMessage::File_filetype File::file_type() const { 1005 | // @@protoc_insertion_point(field_get:lkpMessage.File.file_type) 1006 | return static_cast< ::lkpMessage::File_filetype >(file_type_); 1007 | } 1008 | inline void File::set_file_type(::lkpMessage::File_filetype value) { 1009 | 1010 | file_type_ = value; 1011 | // @@protoc_insertion_point(field_set:lkpMessage.File.file_type) 1012 | } 1013 | 1014 | // optional string file_name = 2; 1015 | inline void File::clear_file_name() { 1016 | file_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 1017 | } 1018 | inline const ::std::string& File::file_name() const { 1019 | // @@protoc_insertion_point(field_get:lkpMessage.File.file_name) 1020 | return file_name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 1021 | } 1022 | inline void File::set_file_name(const ::std::string& value) { 1023 | 1024 | file_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); 1025 | // @@protoc_insertion_point(field_set:lkpMessage.File.file_name) 1026 | } 1027 | inline void File::set_file_name(const char* value) { 1028 | 1029 | file_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); 1030 | // @@protoc_insertion_point(field_set_char:lkpMessage.File.file_name) 1031 | } 1032 | inline void File::set_file_name(const char* value, size_t size) { 1033 | 1034 | file_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), 1035 | ::std::string(reinterpret_cast(value), size)); 1036 | // @@protoc_insertion_point(field_set_pointer:lkpMessage.File.file_name) 1037 | } 1038 | inline ::std::string* File::mutable_file_name() { 1039 | 1040 | // @@protoc_insertion_point(field_mutable:lkpMessage.File.file_name) 1041 | return file_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 1042 | } 1043 | inline ::std::string* File::release_file_name() { 1044 | // @@protoc_insertion_point(field_release:lkpMessage.File.file_name) 1045 | 1046 | return file_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 1047 | } 1048 | inline void File::set_allocated_file_name(::std::string* file_name) { 1049 | if (file_name != NULL) { 1050 | 1051 | } else { 1052 | 1053 | } 1054 | file_name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), file_name); 1055 | // @@protoc_insertion_point(field_set_allocated:lkpMessage.File.file_name) 1056 | } 1057 | 1058 | // optional uint32 patch_len = 3; 1059 | inline void File::clear_patch_len() { 1060 | patch_len_ = 0u; 1061 | } 1062 | inline ::google::protobuf::uint32 File::patch_len() const { 1063 | // @@protoc_insertion_point(field_get:lkpMessage.File.patch_len) 1064 | return patch_len_; 1065 | } 1066 | inline void File::set_patch_len(::google::protobuf::uint32 value) { 1067 | 1068 | patch_len_ = value; 1069 | // @@protoc_insertion_point(field_set:lkpMessage.File.patch_len) 1070 | } 1071 | 1072 | // optional uint32 file_size = 4; 1073 | inline void File::clear_file_size() { 1074 | file_size_ = 0u; 1075 | } 1076 | inline ::google::protobuf::uint32 File::file_size() const { 1077 | // @@protoc_insertion_point(field_get:lkpMessage.File.file_size) 1078 | return file_size_; 1079 | } 1080 | inline void File::set_file_size(::google::protobuf::uint32 value) { 1081 | 1082 | file_size_ = value; 1083 | // @@protoc_insertion_point(field_set:lkpMessage.File.file_size) 1084 | } 1085 | 1086 | // optional bool first_patch = 5; 1087 | inline void File::clear_first_patch() { 1088 | first_patch_ = false; 1089 | } 1090 | inline bool File::first_patch() const { 1091 | // @@protoc_insertion_point(field_get:lkpMessage.File.first_patch) 1092 | return first_patch_; 1093 | } 1094 | inline void File::set_first_patch(bool value) { 1095 | 1096 | first_patch_ = value; 1097 | // @@protoc_insertion_point(field_set:lkpMessage.File.first_patch) 1098 | } 1099 | 1100 | // optional bytes content = 6; 1101 | inline void File::clear_content() { 1102 | content_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 1103 | } 1104 | inline const ::std::string& File::content() const { 1105 | // @@protoc_insertion_point(field_get:lkpMessage.File.content) 1106 | return content_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 1107 | } 1108 | inline void File::set_content(const ::std::string& value) { 1109 | 1110 | content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); 1111 | // @@protoc_insertion_point(field_set:lkpMessage.File.content) 1112 | } 1113 | inline void File::set_content(const char* value) { 1114 | 1115 | content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); 1116 | // @@protoc_insertion_point(field_set_char:lkpMessage.File.content) 1117 | } 1118 | inline void File::set_content(const void* value, size_t size) { 1119 | 1120 | content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), 1121 | ::std::string(reinterpret_cast(value), size)); 1122 | // @@protoc_insertion_point(field_set_pointer:lkpMessage.File.content) 1123 | } 1124 | inline ::std::string* File::mutable_content() { 1125 | 1126 | // @@protoc_insertion_point(field_mutable:lkpMessage.File.content) 1127 | return content_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 1128 | } 1129 | inline ::std::string* File::release_content() { 1130 | // @@protoc_insertion_point(field_release:lkpMessage.File.content) 1131 | 1132 | return content_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 1133 | } 1134 | inline void File::set_allocated_content(::std::string* content) { 1135 | if (content != NULL) { 1136 | 1137 | } else { 1138 | 1139 | } 1140 | content_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), content); 1141 | // @@protoc_insertion_point(field_set_allocated:lkpMessage.File.content) 1142 | } 1143 | 1144 | // optional uint32 node_id = 7; 1145 | inline void File::clear_node_id() { 1146 | node_id_ = 0u; 1147 | } 1148 | inline ::google::protobuf::uint32 File::node_id() const { 1149 | // @@protoc_insertion_point(field_get:lkpMessage.File.node_id) 1150 | return node_id_; 1151 | } 1152 | inline void File::set_node_id(::google::protobuf::uint32 value) { 1153 | 1154 | node_id_ = value; 1155 | // @@protoc_insertion_point(field_set:lkpMessage.File.node_id) 1156 | } 1157 | 1158 | // ------------------------------------------------------------------- 1159 | 1160 | // CommandACK 1161 | 1162 | // optional bool status = 1; 1163 | inline void CommandACK::clear_status() { 1164 | status_ = false; 1165 | } 1166 | inline bool CommandACK::status() const { 1167 | // @@protoc_insertion_point(field_get:lkpMessage.CommandACK.status) 1168 | return status_; 1169 | } 1170 | inline void CommandACK::set_status(bool value) { 1171 | 1172 | status_ = value; 1173 | // @@protoc_insertion_point(field_set:lkpMessage.CommandACK.status) 1174 | } 1175 | 1176 | // optional .lkpMessage.commandID command = 2; 1177 | inline void CommandACK::clear_command() { 1178 | command_ = 0; 1179 | } 1180 | inline ::lkpMessage::commandID CommandACK::command() const { 1181 | // @@protoc_insertion_point(field_get:lkpMessage.CommandACK.command) 1182 | return static_cast< ::lkpMessage::commandID >(command_); 1183 | } 1184 | inline void CommandACK::set_command(::lkpMessage::commandID value) { 1185 | 1186 | command_ = value; 1187 | // @@protoc_insertion_point(field_set:lkpMessage.CommandACK.command) 1188 | } 1189 | 1190 | // optional string ack_message = 3; 1191 | inline void CommandACK::clear_ack_message() { 1192 | ack_message_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 1193 | } 1194 | inline const ::std::string& CommandACK::ack_message() const { 1195 | // @@protoc_insertion_point(field_get:lkpMessage.CommandACK.ack_message) 1196 | return ack_message_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 1197 | } 1198 | inline void CommandACK::set_ack_message(const ::std::string& value) { 1199 | 1200 | ack_message_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); 1201 | // @@protoc_insertion_point(field_set:lkpMessage.CommandACK.ack_message) 1202 | } 1203 | inline void CommandACK::set_ack_message(const char* value) { 1204 | 1205 | ack_message_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); 1206 | // @@protoc_insertion_point(field_set_char:lkpMessage.CommandACK.ack_message) 1207 | } 1208 | inline void CommandACK::set_ack_message(const char* value, size_t size) { 1209 | 1210 | ack_message_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), 1211 | ::std::string(reinterpret_cast(value), size)); 1212 | // @@protoc_insertion_point(field_set_pointer:lkpMessage.CommandACK.ack_message) 1213 | } 1214 | inline ::std::string* CommandACK::mutable_ack_message() { 1215 | 1216 | // @@protoc_insertion_point(field_mutable:lkpMessage.CommandACK.ack_message) 1217 | return ack_message_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 1218 | } 1219 | inline ::std::string* CommandACK::release_ack_message() { 1220 | // @@protoc_insertion_point(field_release:lkpMessage.CommandACK.ack_message) 1221 | 1222 | return ack_message_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 1223 | } 1224 | inline void CommandACK::set_allocated_ack_message(::std::string* ack_message) { 1225 | if (ack_message != NULL) { 1226 | 1227 | } else { 1228 | 1229 | } 1230 | ack_message_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ack_message); 1231 | // @@protoc_insertion_point(field_set_allocated:lkpMessage.CommandACK.ack_message) 1232 | } 1233 | 1234 | // optional uint32 node_id = 4; 1235 | inline void CommandACK::clear_node_id() { 1236 | node_id_ = 0u; 1237 | } 1238 | inline ::google::protobuf::uint32 CommandACK::node_id() const { 1239 | // @@protoc_insertion_point(field_get:lkpMessage.CommandACK.node_id) 1240 | return node_id_; 1241 | } 1242 | inline void CommandACK::set_node_id(::google::protobuf::uint32 value) { 1243 | 1244 | node_id_ = value; 1245 | // @@protoc_insertion_point(field_set:lkpMessage.CommandACK.node_id) 1246 | } 1247 | 1248 | // ------------------------------------------------------------------- 1249 | 1250 | // HeartBeat 1251 | 1252 | // optional bool status = 1; 1253 | inline void HeartBeat::clear_status() { 1254 | status_ = false; 1255 | } 1256 | inline bool HeartBeat::status() const { 1257 | // @@protoc_insertion_point(field_get:lkpMessage.HeartBeat.status) 1258 | return status_; 1259 | } 1260 | inline void HeartBeat::set_status(bool value) { 1261 | 1262 | status_ = value; 1263 | // @@protoc_insertion_point(field_set:lkpMessage.HeartBeat.status) 1264 | } 1265 | 1266 | // ------------------------------------------------------------------- 1267 | 1268 | // PushACK 1269 | 1270 | // optional bool status = 1; 1271 | inline void PushACK::clear_status() { 1272 | status_ = false; 1273 | } 1274 | inline bool PushACK::status() const { 1275 | // @@protoc_insertion_point(field_get:lkpMessage.PushACK.status) 1276 | return status_; 1277 | } 1278 | inline void PushACK::set_status(bool value) { 1279 | 1280 | status_ = value; 1281 | // @@protoc_insertion_point(field_set:lkpMessage.PushACK.status) 1282 | } 1283 | 1284 | // optional string ack_message = 2; 1285 | inline void PushACK::clear_ack_message() { 1286 | ack_message_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 1287 | } 1288 | inline const ::std::string& PushACK::ack_message() const { 1289 | // @@protoc_insertion_point(field_get:lkpMessage.PushACK.ack_message) 1290 | return ack_message_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 1291 | } 1292 | inline void PushACK::set_ack_message(const ::std::string& value) { 1293 | 1294 | ack_message_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); 1295 | // @@protoc_insertion_point(field_set:lkpMessage.PushACK.ack_message) 1296 | } 1297 | inline void PushACK::set_ack_message(const char* value) { 1298 | 1299 | ack_message_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); 1300 | // @@protoc_insertion_point(field_set_char:lkpMessage.PushACK.ack_message) 1301 | } 1302 | inline void PushACK::set_ack_message(const char* value, size_t size) { 1303 | 1304 | ack_message_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), 1305 | ::std::string(reinterpret_cast(value), size)); 1306 | // @@protoc_insertion_point(field_set_pointer:lkpMessage.PushACK.ack_message) 1307 | } 1308 | inline ::std::string* PushACK::mutable_ack_message() { 1309 | 1310 | // @@protoc_insertion_point(field_mutable:lkpMessage.PushACK.ack_message) 1311 | return ack_message_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 1312 | } 1313 | inline ::std::string* PushACK::release_ack_message() { 1314 | // @@protoc_insertion_point(field_release:lkpMessage.PushACK.ack_message) 1315 | 1316 | return ack_message_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 1317 | } 1318 | inline void PushACK::set_allocated_ack_message(::std::string* ack_message) { 1319 | if (ack_message != NULL) { 1320 | 1321 | } else { 1322 | 1323 | } 1324 | ack_message_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ack_message); 1325 | // @@protoc_insertion_point(field_set_allocated:lkpMessage.PushACK.ack_message) 1326 | } 1327 | 1328 | // optional uint32 node_id = 3; 1329 | inline void PushACK::clear_node_id() { 1330 | node_id_ = 0u; 1331 | } 1332 | inline ::google::protobuf::uint32 PushACK::node_id() const { 1333 | // @@protoc_insertion_point(field_get:lkpMessage.PushACK.node_id) 1334 | return node_id_; 1335 | } 1336 | inline void PushACK::set_node_id(::google::protobuf::uint32 value) { 1337 | 1338 | node_id_ = value; 1339 | // @@protoc_insertion_point(field_set:lkpMessage.PushACK.node_id) 1340 | } 1341 | 1342 | // ------------------------------------------------------------------- 1343 | 1344 | // Return_NodeInfo 1345 | 1346 | // optional uint32 node_id = 1; 1347 | inline void Return_NodeInfo::clear_node_id() { 1348 | node_id_ = 0u; 1349 | } 1350 | inline ::google::protobuf::uint32 Return_NodeInfo::node_id() const { 1351 | // @@protoc_insertion_point(field_get:lkpMessage.Return.NodeInfo.node_id) 1352 | return node_id_; 1353 | } 1354 | inline void Return_NodeInfo::set_node_id(::google::protobuf::uint32 value) { 1355 | 1356 | node_id_ = value; 1357 | // @@protoc_insertion_point(field_set:lkpMessage.Return.NodeInfo.node_id) 1358 | } 1359 | 1360 | // optional string node_msg = 2; 1361 | inline void Return_NodeInfo::clear_node_msg() { 1362 | node_msg_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 1363 | } 1364 | inline const ::std::string& Return_NodeInfo::node_msg() const { 1365 | // @@protoc_insertion_point(field_get:lkpMessage.Return.NodeInfo.node_msg) 1366 | return node_msg_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 1367 | } 1368 | inline void Return_NodeInfo::set_node_msg(const ::std::string& value) { 1369 | 1370 | node_msg_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); 1371 | // @@protoc_insertion_point(field_set:lkpMessage.Return.NodeInfo.node_msg) 1372 | } 1373 | inline void Return_NodeInfo::set_node_msg(const char* value) { 1374 | 1375 | node_msg_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); 1376 | // @@protoc_insertion_point(field_set_char:lkpMessage.Return.NodeInfo.node_msg) 1377 | } 1378 | inline void Return_NodeInfo::set_node_msg(const char* value, size_t size) { 1379 | 1380 | node_msg_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), 1381 | ::std::string(reinterpret_cast(value), size)); 1382 | // @@protoc_insertion_point(field_set_pointer:lkpMessage.Return.NodeInfo.node_msg) 1383 | } 1384 | inline ::std::string* Return_NodeInfo::mutable_node_msg() { 1385 | 1386 | // @@protoc_insertion_point(field_mutable:lkpMessage.Return.NodeInfo.node_msg) 1387 | return node_msg_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 1388 | } 1389 | inline ::std::string* Return_NodeInfo::release_node_msg() { 1390 | // @@protoc_insertion_point(field_release:lkpMessage.Return.NodeInfo.node_msg) 1391 | 1392 | return node_msg_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 1393 | } 1394 | inline void Return_NodeInfo::set_allocated_node_msg(::std::string* node_msg) { 1395 | if (node_msg != NULL) { 1396 | 1397 | } else { 1398 | 1399 | } 1400 | node_msg_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), node_msg); 1401 | // @@protoc_insertion_point(field_set_allocated:lkpMessage.Return.NodeInfo.node_msg) 1402 | } 1403 | 1404 | // ------------------------------------------------------------------- 1405 | 1406 | // Return 1407 | 1408 | // optional uint32 client_num = 1; 1409 | inline void Return::clear_client_num() { 1410 | client_num_ = 0u; 1411 | } 1412 | inline ::google::protobuf::uint32 Return::client_num() const { 1413 | // @@protoc_insertion_point(field_get:lkpMessage.Return.client_num) 1414 | return client_num_; 1415 | } 1416 | inline void Return::set_client_num(::google::protobuf::uint32 value) { 1417 | 1418 | client_num_ = value; 1419 | // @@protoc_insertion_point(field_set:lkpMessage.Return.client_num) 1420 | } 1421 | 1422 | // optional uint32 client_ok_num = 2; 1423 | inline void Return::clear_client_ok_num() { 1424 | client_ok_num_ = 0u; 1425 | } 1426 | inline ::google::protobuf::uint32 Return::client_ok_num() const { 1427 | // @@protoc_insertion_point(field_get:lkpMessage.Return.client_ok_num) 1428 | return client_ok_num_; 1429 | } 1430 | inline void Return::set_client_ok_num(::google::protobuf::uint32 value) { 1431 | 1432 | client_ok_num_ = value; 1433 | // @@protoc_insertion_point(field_set:lkpMessage.Return.client_ok_num) 1434 | } 1435 | 1436 | // optional .lkpMessage.commandID command = 3; 1437 | inline void Return::clear_command() { 1438 | command_ = 0; 1439 | } 1440 | inline ::lkpMessage::commandID Return::command() const { 1441 | // @@protoc_insertion_point(field_get:lkpMessage.Return.command) 1442 | return static_cast< ::lkpMessage::commandID >(command_); 1443 | } 1444 | inline void Return::set_command(::lkpMessage::commandID value) { 1445 | 1446 | command_ = value; 1447 | // @@protoc_insertion_point(field_set:lkpMessage.Return.command) 1448 | } 1449 | 1450 | // repeated .lkpMessage.Return.NodeInfo node_info = 4; 1451 | inline int Return::node_info_size() const { 1452 | return node_info_.size(); 1453 | } 1454 | inline void Return::clear_node_info() { 1455 | node_info_.Clear(); 1456 | } 1457 | inline const ::lkpMessage::Return_NodeInfo& Return::node_info(int index) const { 1458 | // @@protoc_insertion_point(field_get:lkpMessage.Return.node_info) 1459 | return node_info_.Get(index); 1460 | } 1461 | inline ::lkpMessage::Return_NodeInfo* Return::mutable_node_info(int index) { 1462 | // @@protoc_insertion_point(field_mutable:lkpMessage.Return.node_info) 1463 | return node_info_.Mutable(index); 1464 | } 1465 | inline ::lkpMessage::Return_NodeInfo* Return::add_node_info() { 1466 | // @@protoc_insertion_point(field_add:lkpMessage.Return.node_info) 1467 | return node_info_.Add(); 1468 | } 1469 | inline ::google::protobuf::RepeatedPtrField< ::lkpMessage::Return_NodeInfo >* 1470 | Return::mutable_node_info() { 1471 | // @@protoc_insertion_point(field_mutable_list:lkpMessage.Return.node_info) 1472 | return &node_info_; 1473 | } 1474 | inline const ::google::protobuf::RepeatedPtrField< ::lkpMessage::Return_NodeInfo >& 1475 | Return::node_info() const { 1476 | // @@protoc_insertion_point(field_list:lkpMessage.Return.node_info) 1477 | return node_info_; 1478 | } 1479 | 1480 | #endif // !PROTOBUF_INLINE_NOT_IN_HEADERS 1481 | // ------------------------------------------------------------------- 1482 | 1483 | // ------------------------------------------------------------------- 1484 | 1485 | // ------------------------------------------------------------------- 1486 | 1487 | // ------------------------------------------------------------------- 1488 | 1489 | // ------------------------------------------------------------------- 1490 | 1491 | // ------------------------------------------------------------------- 1492 | 1493 | 1494 | // @@protoc_insertion_point(namespace_scope) 1495 | 1496 | } // namespace lkpMessage 1497 | 1498 | #ifndef SWIG 1499 | namespace google { 1500 | namespace protobuf { 1501 | 1502 | template <> struct is_proto_enum< ::lkpMessage::File_filetype> : ::google::protobuf::internal::true_type {}; 1503 | template <> 1504 | inline const EnumDescriptor* GetEnumDescriptor< ::lkpMessage::File_filetype>() { 1505 | return ::lkpMessage::File_filetype_descriptor(); 1506 | } 1507 | template <> struct is_proto_enum< ::lkpMessage::commandID> : ::google::protobuf::internal::true_type {}; 1508 | template <> 1509 | inline const EnumDescriptor* GetEnumDescriptor< ::lkpMessage::commandID>() { 1510 | return ::lkpMessage::commandID_descriptor(); 1511 | } 1512 | 1513 | } // namespace protobuf 1514 | } // namespace google 1515 | #endif // SWIG 1516 | 1517 | // @@protoc_insertion_point(global_scope) 1518 | 1519 | #endif // PROTOBUF_lkpProto_2eproto__INCLUDED 1520 | -------------------------------------------------------------------------------- /src/lkpClient.cc: -------------------------------------------------------------------------------- 1 | #include "lkpClient.h" 2 | 3 | lkpClient::lkpClient(EventLoop *loop, const InetAddress &serverAddr, int seconds) 4 | : loop_(loop), 5 | client_(loop, serverAddr, "lkpClient"), 6 | seconds_(seconds), 7 | kBufSize_(64 * 1024), 8 | dispatcher_(std::bind(&lkpClient::onUnknownMsg, this, 9 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)), 10 | codec_(std::bind(&lkpDispatcher::onProtobufMessage, &dispatcher_, 11 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)), 12 | 13 | /* 高速缓冲区使用变量,日志文件使用*/ 14 | connection_(nullptr), 15 | flushInterval_(3), 16 | running_(false), 17 | rollSize_(500 * 1000 * 1000), 18 | thread_(std::bind(&lkpClient::threadFunc, this), "Logging_SendtoCMDclient"), 19 | latch_(1), 20 | cond_(mutex_), 21 | currentBuffer_(new Buffer_log), 22 | nextBuffer_(new Buffer_log), 23 | buffers_(), 24 | basename_(ROOT_DIR + "/log/clientfile") //缓冲区的文件名称 25 | { 26 | //缓冲区使用 27 | 28 | currentBuffer_->bzero(); 29 | nextBuffer_->bzero(); 30 | buffers_.reserve(16); 31 | 32 | //logging 33 | running_ = true; //允许后端写日志 34 | thread_.start(); //启动后端线程threadFunc 35 | latch_.wait(); //等待后端线程threadFunc启动,否则服务器不能执行其他动作 36 | 37 | //绑定业务回调函数 38 | dispatcher_.registerMessageCallback(std::bind(&lkpClient::onCommandMsg, 39 | this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 40 | dispatcher_.registerMessageCallback(std::bind(&lkpClient::onFileMsg, 41 | this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 42 | 43 | //绑定新连接请求回调函数 44 | client_.setConnectionCallback( 45 | std::bind(&lkpClient::onConnection, this, std::placeholders::_1)); 46 | //绑定client的信息接收回调函数到lkpCodec 47 | client_.setMessageCallback( 48 | std::bind(&lkpCodec::onMessage, &codec_, 49 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 50 | 51 | //绑定定时器产生心跳包 52 | loop_->runEvery(seconds_, std::bind(&lkpClient::onTimer, this)); 53 | } 54 | 55 | lkpClient::~lkpClient() 56 | { 57 | if (running_) 58 | { 59 | running_ = false; //不允许后端继续写日志 60 | cond_.notify(); //避免后端卡在条件变量处 61 | thread_.join(); //回收后端线程 62 | } 63 | } 64 | 65 | //连接服务器 66 | void lkpClient::connect() 67 | { 68 | client_.connect(); 69 | } 70 | 71 | //断开与服务器的连接 72 | void lkpClient::disconnect() 73 | { 74 | client_.disconnect(); 75 | } 76 | 77 | 78 | // 该函数在IO线程中执行,IO线程与主线程不在同一个线程 79 | void lkpClient::onConnection(const TcpConnectionPtr &conn) 80 | { 81 | // // mutex用来保护connection_这个shared_ptr 82 | // MutexLockGuard lock(mutex_); 83 | if (conn->connected()) 84 | { 85 | connection_ = conn; 86 | std::cout << "lkp-extent client: connect success " << std::endl; 87 | } 88 | else 89 | { 90 | connection_.reset(); 91 | connection_ = nullptr; 92 | LOG_INFO << "lkp-ctl client unconnected !!!"; 93 | } 94 | } 95 | 96 | //收到命令的回调函数,server转发给client, client执行 97 | void lkpClient::onCommandMsg(const TcpConnectionPtr &conn, const RecvCommandPtr &message, Timestamp time) 98 | { 99 | lkpMessage::CommandACK ACK; 100 | ACK.set_command(message->command()); 101 | ACK.set_node_id(message->node_id()); 102 | int status = 0; 103 | 104 | //如果上一个命令还没有运行完,现场尝试回收子进程,如果回收失败,说明上一条命令此时还不可能结束 105 | if (childNum >= 1) 106 | { 107 | lastStatus_ = WIFEXITED(status); 108 | ACK.set_status(false); 109 | ACK.set_ack_message("ERROR 10: Command " + lastCmdString_ + " is still running!"); 110 | SendToServer(ACK); 111 | return; 112 | } 113 | 114 | lkpEnumToCmds(message->command(), lastCmdString_); 115 | lastPid_ = 0; 116 | switch (message->command()) 117 | { 118 | 119 | case lkpMessage::UPDATE: 120 | { 121 | pid_t pid = fork(); 122 | childNum++; 123 | if (pid < 0) 124 | { 125 | ACK.set_status(false); 126 | ACK.set_ack_message("ERROR 11: Fork Error!"); 127 | SendToServer(ACK); 128 | return; 129 | } 130 | //开启新进程执行命令 131 | if (pid == 0) 132 | { 133 | if (execlp("lkp-ctl", "lkp-ctl", "update", NULL) < 0) 134 | { 135 | perror("Error on UPDATE exec:"); 136 | ACK.set_status(false); 137 | ACK.set_ack_message("ERROR 12: Command UPDATE cannot run!"); 138 | SendToServer(ACK); 139 | exit(0); 140 | } 141 | } 142 | else 143 | { 144 | lastPid_ = pid; 145 | 146 | lastStatus_ = WIFEXITED(status); 147 | ACK.set_status(true); 148 | SendToServer(ACK); 149 | } 150 | break; 151 | } 152 | 153 | case lkpMessage::RUN: 154 | { 155 | pid_t pid; 156 | string testname = message->testcase(); 157 | unsigned int dockerNum = message->docker_num(); 158 | string dockerNumString = std::to_string(dockerNum); 159 | pid = fork(); 160 | childNum++; 161 | if (pid == 0) 162 | { 163 | //子进程执行lkp-ctl run (-c vm_cnt) testcase 164 | if (message->docker_num()) 165 | { 166 | if (execlp("lkp-ctl", "lkp-ctl", "-c", dockerNumString.data(), "run", testname.data(), NULL) < 0) 167 | { 168 | perror("Error on RUN exec:"); 169 | exit(0); 170 | } 171 | } 172 | else 173 | { 174 | if (execlp("lkp-ctl", "lkp-ctl", "run", testname.data(), NULL) < 0) 175 | { 176 | perror("Error on RUN exec:"); 177 | exit(0); 178 | } 179 | } 180 | } 181 | else if (pid < 0) 182 | { 183 | ACK.set_status(false); 184 | ACK.set_ack_message("ERROR 11: Fork Error!"); 185 | SendToServer(ACK); 186 | return; 187 | } 188 | //开启新进程执行命令 189 | else 190 | { 191 | lastPid_ = pid; 192 | 193 | lastStatus_ = WIFEXITED(status); 194 | ACK.set_status(true); 195 | SendToServer(ACK); 196 | } 197 | break; 198 | } 199 | 200 | case lkpMessage::RESULT: 201 | { 202 | onResult(conn, message); 203 | break; 204 | } 205 | 206 | case lkpMessage::PUSH: 207 | { 208 | lkpMessage::PushACK PACK; 209 | //To DO: 210 | //bool canRecvFile(uint32 file_len); 211 | //bool createFile(string file_name); 212 | PACK.set_status(true); 213 | SendToServer(PACK); 214 | break; 215 | } 216 | } 217 | } 218 | 219 | //收到result 220 | void lkpClient::onResult(const TcpConnectionPtr &conn, const RecvCommandPtr &message) 221 | { 222 | nodeID_ = message->node_id(); 223 | 224 | string fileName = ROOT_DIR + "/results/local/result.tar"; 225 | 226 | LOG_INFO << "Result fileName:" << fileName; 227 | 228 | //获取文件的大小 229 | struct stat statbuf; 230 | stat(fileName.c_str(), &statbuf); 231 | int fileSize = statbuf.st_size; 232 | 233 | FILE *fp = ::fopen(fileName.c_str(), "rb"); //打开文件 234 | if (!fp) 235 | { 236 | lkpMessage::CommandACK ACK; 237 | ACK.set_command(message->command()); 238 | ACK.set_node_id(nodeID_); 239 | perror("lkp-ctl open local result file error: \n"); 240 | ACK.set_status(false); 241 | ACK.set_ack_message("ERROR 14: No Result File in client"); 242 | SendToServer(ACK); 243 | return; 244 | } 245 | 246 | FilePtr ctx(fp, ::fclose); //多了::fclose参数,表示fp对象的引用计数器变成0时,调用::fclose来销毁fp 247 | conn->setContext(ctx); //把TcpConnectionPtr对象与fp绑定 248 | char buf[kBufSize_]; 249 | size_t nread = ::fread(buf, 1, sizeof buf, fp); //读取kBufSize的内容 250 | 251 | lkpMessage::File fileMessage; 252 | fileMessage.set_file_type(lkpMessage::File::RESULT); 253 | fileMessage.set_file_size(fileSize); 254 | fileMessage.set_patch_len(nread); 255 | fileMessage.set_first_patch(true); 256 | fileMessage.set_content(buf); 257 | fileMessage.set_file_name("result.tar"); 258 | 259 | conn->setWriteCompleteCallback(bind(&lkpClient::onWriteComplete, this, std::placeholders::_1)); //发完一次后继续发 260 | SendToServer(fileMessage); 261 | } 262 | 263 | //每次发送64kb 264 | void lkpClient::onWriteComplete(const TcpConnectionPtr &conn) 265 | { 266 | const FilePtr &fp = boost::any_cast(conn->getContext()); 267 | 268 | char buf[kBufSize_]; 269 | size_t nread = ::fread(buf, 1, sizeof(buf), get_pointer(fp)); 270 | 271 | //续传 272 | if (nread > 0) 273 | { 274 | lkpMessage::File fileMessage; 275 | fileMessage.set_file_type(lkpMessage::File::RESULT); 276 | fileMessage.set_first_patch(false); 277 | fileMessage.set_patch_len(nread); 278 | fileMessage.set_content(buf); 279 | 280 | SendToServer(fileMessage); 281 | } 282 | //结束 283 | else 284 | { 285 | //发送结束信号 286 | lkpMessage::File fileMessage; 287 | fileMessage.set_file_type(lkpMessage::File::END); 288 | 289 | conn->setWriteCompleteCallback(NULL); 290 | 291 | SendToServer(fileMessage); 292 | } 293 | } 294 | 295 | //收到file message的回调函数,server收到的应该是result, client收到的应该是testcase 296 | void lkpClient::onFileMsg(const TcpConnectionPtr &conn, const RecvFilePtr &message, Timestamp time) 297 | { 298 | //文件发送结束 299 | if (message->file_type() == lkpMessage::File::END) 300 | { 301 | fclose(fp_); //必须关闭,不然会错误 302 | 303 | //获取文件的大小 304 | struct stat statbuf; 305 | stat(fileName_.c_str(), &statbuf); 306 | int recvSize = statbuf.st_size; 307 | 308 | //检查文件是否完整 309 | if (recvSize != fileSize_) 310 | { 311 | LOG_INFO << "recvSize:" << recvSize << ",fileSize_:" << fileSize_; 312 | LOG_INFO << "file is not complete!"; 313 | 314 | //失败回复 315 | lkpMessage::PushACK ack; 316 | ack.set_status(false); 317 | ack.set_ack_message("push recv fail"); 318 | ack.set_node_id(nodeID_); 319 | SendToServer(ack); 320 | return; 321 | } 322 | else 323 | { 324 | // printf("recv a complete file\n"); 325 | LOG_INFO << "recv a complete file"; 326 | 327 | //成功 328 | lkpMessage::PushACK ack; 329 | ack.set_status(true); 330 | ack.set_ack_message("push recv success"); 331 | ack.set_node_id(nodeID_); 332 | SendToServer(ack); 333 | const string copyToJobs = "cp " + fileName_ + " " + ROOT_DIR + "/lkp-tests/jobs"; 334 | system(copyToJobs.c_str()); 335 | return; 336 | } 337 | } 338 | //第一次接收 339 | else if (message->first_patch()) 340 | { 341 | nodeID_ = message->node_id(); 342 | fileName_ = ROOT_DIR + "/testcases/" + message->file_name(); 343 | LOG_INFO << "fileName_:" << fileName_; 344 | 345 | fileSize_ = message->file_size(); 346 | fp_ = ::fopen(fileName_.c_str(), "wb"); 347 | assert(fp_); 348 | } 349 | 350 | //每次接收的都输出 351 | fwrite(message->content().c_str(), 1, message->patch_len(), fp_); 352 | } 353 | 354 | //收到未知数据包的回调函数 355 | void lkpClient::onUnknownMsg(const TcpConnectionPtr &conn, const MessagePtr &message, Timestamp time) 356 | { 357 | LOG_INFO << "Error: Unknown Message, shut dowm the connect!"; 358 | conn->shutdown(); 359 | exit(0); 360 | } 361 | 362 | //定期心跳回调函数 363 | void lkpClient::onTimer() 364 | { 365 | if(!connection_){ 366 | printf("lkp-ctl client error: Cannot connect!\n"); 367 | exit(0); 368 | } 369 | lkpMessage::HeartBeat heart; 370 | heart.set_status(true); 371 | SendToServer(heart); 372 | int status; 373 | lastStatus_ = WIFEXITED(status); 374 | } 375 | 376 | //向服务器发送数据 377 | void lkpClient::SendToServer(const google::protobuf::Message &messageToSend) 378 | { 379 | // // mutex用来保护connection_这个shared_ptr 380 | // MutexLockGuard lock(mutex_); 381 | if (connection_->connected()) 382 | { 383 | codec_.send(connection_, messageToSend); 384 | } 385 | } 386 | 387 | //onMessage调用,负责向一级缓冲区写 388 | void lkpClient::append(const char *logline, int len) 389 | { 390 | muduo::MutexLockGuard lock(mutex_); //加锁访问一级缓冲区 391 | 392 | //如果一级当前未满,直接加入 393 | if (currentBuffer_->avail() > len) 394 | { 395 | currentBuffer_->append(logline, len); 396 | } 397 | //一级当前已满,把一级当前加入二级列表,把一级预备转正 398 | else 399 | { 400 | buffers_.push_back(std::move(currentBuffer_)); //一级当前加入二级列表 401 | 402 | if (nextBuffer_) 403 | { 404 | currentBuffer_ = std::move(nextBuffer_); //一级预备转正 405 | } 406 | else 407 | { 408 | currentBuffer_.reset(new Buffer_log); //基本上不会发生,预备空时,重新申请 409 | } 410 | 411 | currentBuffer_->append(logline, len); //向一级当前写 412 | cond_.notify(); //生产者释放条件变量,通知后端条件满足 413 | } 414 | } 415 | 416 | //后端调用,向日志文件写 muduo::Thread thread_ 绑定该函数,实现后端线程负责写 417 | void lkpClient::threadFunc() 418 | { 419 | assert(running_ == true); 420 | 421 | //让start()的latch_.wait()得到0,可以运行前端线程 422 | latch_.countDown(); 423 | 424 | LogFile output(basename_, rollSize_, false); 425 | 426 | //准备2块缓冲区,用于分配给一级 427 | BufferPtr newBuffer1(new Buffer_log); 428 | BufferPtr newBuffer2(new Buffer_log); 429 | newBuffer1->bzero(); 430 | newBuffer2->bzero(); 431 | 432 | //后端操作的二级 433 | BufferVector buffersToWrite; //写日志操作的缓冲区 434 | buffersToWrite.reserve(16); //预分配16个位置 435 | 436 | //真正运行的部分 437 | while (running_) 438 | { 439 | assert(newBuffer1 && newBuffer1->length() == 0); 440 | assert(newBuffer2 && newBuffer2->length() == 0); 441 | assert(buffersToWrite.empty()); 442 | 443 | //加锁,此时前端不能操作一级 444 | { 445 | muduo::MutexLockGuard lock(mutex_); 446 | //条件变量,如果二级列表是空的,就等待超时、前端释放条件变量。 447 | if (buffers_.empty()) 448 | { 449 | cond_.waitForSeconds(flushInterval_); 450 | } 451 | 452 | buffers_.push_back(std::move(currentBuffer_)); //未满的一级加入二级列表 453 | currentBuffer_ = std::move(newBuffer1); //一级当前分配空间 454 | buffersToWrite.swap(buffers_); //交换,快速释放对一级的占用 455 | if (!nextBuffer_) 456 | { 457 | nextBuffer_ = std::move(newBuffer2); 458 | } 459 | } 460 | 461 | assert(!buffersToWrite.empty()); 462 | 463 | //如果消息堆积,只保留前2块缓冲区 464 | if (buffersToWrite.size() > 25) 465 | { 466 | char buf[256]; 467 | snprintf(buf, sizeof buf, "Dropped log messages at %s, %zd larger buffers\n", 468 | Timestamp::now().toFormattedString().c_str(), 469 | buffersToWrite.size() - 2); 470 | fputs(buf, stderr); 471 | output.append(buf, static_cast(strlen(buf))); 472 | buffersToWrite.erase(buffersToWrite.begin() + 2, buffersToWrite.end()); //丢弃多余的日志,只保留前2个 473 | } 474 | 475 | for (const auto &buffer : buffersToWrite) 476 | { 477 | output.append(buffer->data(), buffer->length()); //写日志 478 | } 479 | 480 | if (buffersToWrite.size() > 2) 481 | { 482 | //丢弃无用的缓冲区 483 | buffersToWrite.resize(2); //buffersToWrite的内容已经完成了写入,空闲了。只保留二级缓冲区列表的2个缓冲区,表示newbuffer1,newbuffer2 484 | } 485 | 486 | //为newBuffer1,newBuffer2分配空间 487 | if (!newBuffer1) 488 | { 489 | assert(!buffersToWrite.empty()); 490 | newBuffer1 = std::move(buffersToWrite.back()); 491 | buffersToWrite.pop_back(); 492 | newBuffer1->reset(); 493 | } 494 | //newBuffer2可能分配给了一级缓冲区的预备 495 | if (!newBuffer2) 496 | { 497 | assert(!buffersToWrite.empty()); 498 | newBuffer2 = std::move(buffersToWrite.back()); 499 | buffersToWrite.pop_back(); 500 | newBuffer2->reset(); 501 | } 502 | 503 | buffersToWrite.clear(); 504 | output.flush(); 505 | } 506 | } 507 | 508 | lkpClient *g_asyncLog_client = NULL; 509 | //前端写日志时调用 510 | void asyncOutput_client(const char *msg, int filelen) 511 | { 512 | g_asyncLog_client->append(msg, filelen); 513 | } 514 | -------------------------------------------------------------------------------- /src/lkpClient.h: -------------------------------------------------------------------------------- 1 | #ifndef LKP_CLIENT 2 | #define LKP_CLIENT 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include "muduo/base/Thread.h" 30 | #include "muduo/base/ThreadPool.h" 31 | #include "muduo/base/Logging.h" 32 | #include "muduo/base/Mutex.h" 33 | #include "muduo/base/ThreadLocalSingleton.h" 34 | #include "muduo/net/EventLoop.h" 35 | #include "muduo/net/TcpServer.h" 36 | #include "muduo/base/CurrentThread.h" 37 | #include "muduo/net/EventLoopThread.h" 38 | #include "muduo/net/TcpClient.h" 39 | #include "muduo/base/Timestamp.h" 40 | #include "muduo/net/Callbacks.h" 41 | #include "muduo/net/Channel.h" 42 | #include "muduo/net/TimerId.h" 43 | #include "muduo/base/BlockingQueue.h" 44 | #include "muduo/base/BoundedBlockingQueue.h" 45 | #include "muduo/base/CountDownLatch.h" 46 | #include 47 | #include "muduo/base/LogStream.h" 48 | #include "muduo/base/LogFile.h" 49 | #include 50 | #include 51 | #include "muduo/base/Logging.h" 52 | #include "muduo/base/Mutex.h" 53 | #include "muduo/base/ThreadLocalSingleton.h" 54 | 55 | #include "lib/lkpProto.pb.h" 56 | #include "lib/lkpCodec.h" 57 | #include "lib/lkpDispatcher.h" 58 | #include "lkpHelper.h" 59 | 60 | using namespace muduo; 61 | using namespace muduo::net; 62 | 63 | typedef std::shared_ptr PushACKPtr; 64 | typedef std::shared_ptr CommandACKPtr; 65 | typedef std::shared_ptr RecvFilePtr; 66 | typedef std::shared_ptr RecvCommandPtr; 67 | typedef std::shared_ptr HeartBeatPtr; 68 | typedef boost::shared_ptr FilePtr; 69 | 70 | //前端写日志时调用 71 | void asyncOutput(const char *msg, int len); 72 | 73 | class lkpClient : boost::noncopyable 74 | { 75 | public: 76 | lkpClient(EventLoop *loop, const InetAddress &serverAddr, int seconds); 77 | 78 | ~lkpClient(); 79 | 80 | //连接服务器 81 | void connect(); 82 | //断开与服务器的连接 83 | void disconnect(); 84 | 85 | private: 86 | // 该函数在IO线程中执行,IO线程与主线程不在同一个线程 87 | void onConnection(const TcpConnectionPtr &conn); 88 | 89 | //收到命令的回调函数,server转发给client, client执行 90 | void onCommandMsg(const TcpConnectionPtr &conn, const RecvCommandPtr &message, Timestamp time); 91 | 92 | //收到result 93 | void onResult(const TcpConnectionPtr &conn, const RecvCommandPtr &message); 94 | 95 | //每次发送64kb 96 | void onWriteComplete(const TcpConnectionPtr &conn); 97 | //收到file message的回调函数,server收到的应该是result, client收到的应该是testcase 98 | void onFileMsg(const TcpConnectionPtr &conn, const RecvFilePtr &message, Timestamp time); 99 | 100 | //收到未知数据包的回调函数 101 | void onUnknownMsg(const TcpConnectionPtr &conn, const MessagePtr &message, Timestamp time); 102 | 103 | //定期心跳回调函数 104 | void onTimer(); 105 | 106 | //向服务器发送数据 107 | void SendToServer(const google::protobuf::Message &messageToSend); 108 | 109 | EventLoop *loop_; 110 | TcpClient client_; 111 | 112 | lkpDispatcher dispatcher_; 113 | lkpCodec codec_; 114 | 115 | // MutexLock mutex_; 116 | TcpConnectionPtr connection_; 117 | int seconds_; 118 | 119 | int fileSize_; //文件大小 120 | string fileName_; 121 | int nodeID_; 122 | FILE *fp_; 123 | int kBufSize_; 124 | pid_t lastPid_; 125 | string lastCmdString_; 126 | bool lastStatus_; 127 | 128 | //高速缓冲区使用 129 | // void threadFunc(); //后端线程,把二级缓冲区写入日志文件 130 | typedef muduo::detail::FixedBuffer Buffer_log; //缓冲区 131 | typedef std::vector> BufferVector; //缓冲列表 132 | typedef BufferVector::value_type BufferPtr; 133 | 134 | const int flushInterval_; //超时时间,到达时间后没满的缓冲区也必须把数据写入二级缓冲区 135 | std::atomic running_; //保证服务器停止时,后端线程一定停止 136 | const string basename_; //输出文件的名称 137 | const off_t rollSize_; //日志长度,过长需要roll 138 | muduo::Thread thread_; //后端线程 139 | muduo::CountDownLatch latch_; //确保后端线程启动之后,服务器才开始运行前端线程 140 | muduo::MutexLock mutex_; 141 | muduo::Condition cond_ GUARDED_BY(mutex_); //条件变量,触发后端线程开始写日志 142 | BufferPtr currentBuffer_ GUARDED_BY(mutex_); //一级当前缓冲区 143 | BufferPtr nextBuffer_ GUARDED_BY(mutex_); //一级预备缓冲区 144 | BufferVector buffers_ GUARDED_BY(mutex_); //二级缓冲区列表,后端和buffersToWrite交换后,操作buffersToWrite写日志,避免长时间占用buffers_阻塞前端 145 | 146 | public: 147 | //onMessage调用,负责向一级缓冲区写 148 | void append(const char *logline, int len); 149 | 150 | //后端调用,向日志文件写 muduo::Thread thread_ 绑定该函数,实现后端线程负责写 151 | void threadFunc(); 152 | }; 153 | 154 | //前端写日志时调用 155 | extern lkpClient *g_asyncLog_client; 156 | 157 | void asyncOutput_client(const char *msg, int filelen); 158 | 159 | extern int childNum; 160 | 161 | #endif 162 | 163 | -------------------------------------------------------------------------------- /src/lkpCommand.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "muduo/base/Thread.h" 25 | #include "muduo/base/ThreadPool.h" 26 | #include "muduo/base/Mutex.h" 27 | #include "muduo/base/ThreadLocalSingleton.h" 28 | #include "muduo/net/EventLoop.h" 29 | #include "muduo/net/TcpServer.h" 30 | #include "muduo/base/CurrentThread.h" 31 | #include "muduo/net/EventLoopThread.h" 32 | #include "muduo/net/TcpClient.h" 33 | #include "muduo/base/Timestamp.h" 34 | #include "muduo/net/Callbacks.h" 35 | #include "muduo/net/Channel.h" 36 | #include "muduo/net/TimerId.h" 37 | #include "muduo/base/BlockingQueue.h" 38 | #include "muduo/base/BoundedBlockingQueue.h" 39 | #include "muduo/base/CountDownLatch.h" 40 | #include "muduo/base/Logging.h" 41 | #include "muduo/base/LogStream.h" 42 | #include "muduo/base/LogFile.h" 43 | #include "muduo/base/AsyncLogging.h" 44 | #include 45 | 46 | #include "lib/lkpProto.pb.h" 47 | #include "lib/lkpCodec.h" 48 | #include "lib/lkpDispatcher.h" 49 | #include "lkpHelper.h" 50 | 51 | using namespace muduo; 52 | using namespace muduo::net; 53 | 54 | typedef std::shared_ptr ReturnPtr; 55 | 56 | off_t kRollSize = 500 * 1000 * 1000; 57 | muduo::AsyncLogging *g_asyncLog = NULL; 58 | //前端写日志时调用 59 | void asyncOutput(const char *msg, int filelen) 60 | { 61 | g_asyncLog->append(msg, filelen); 62 | } 63 | 64 | 65 | class lkpCmdClient : boost::noncopyable 66 | { 67 | public: 68 | lkpCmdClient(EventLoop *loop, uint16_t port, lkpMessage::Command commandToSend) 69 | : loop_(loop), 70 | client_(loop, InetAddress("127.0.0.1", port), "lkpCmdClient"), 71 | commandToSend_(commandToSend), 72 | dispatcher_(std::bind(&lkpCmdClient::onUnknownMsg, this, 73 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)), 74 | codec_(std::bind(&lkpDispatcher::onProtobufMessage, &dispatcher_, 75 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)) 76 | { 77 | muduo::Logger::setOutput(asyncOutput);//LOG_INFO调用asyncOutput 78 | //绑定业务回调函数 79 | dispatcher_.registerMessageCallback(std::bind(&lkpCmdClient::onReturnMsg, 80 | this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 81 | 82 | //绑定新连接请求回调函数 83 | client_.setConnectionCallback( 84 | std::bind(&lkpCmdClient::onConnection, this, std::placeholders::_1)); 85 | //绑定client的信息接收回调函数到lkpCodec 86 | client_.setMessageCallback( 87 | std::bind(&lkpCodec::onMessage, &codec_, 88 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 89 | connection_ = nullptr; 90 | loop_->runEvery(1, std::bind(&lkpCmdClient::onTimer, this)); 91 | 92 | } 93 | 94 | //连接服务器 95 | void connect() 96 | { 97 | client_.connect(); 98 | } 99 | 100 | //断开与服务器的连接 101 | void disconnect() 102 | { 103 | client_.disconnect(); 104 | } 105 | 106 | //向服务器发送数据 107 | void SendToServer(const lkpMessage::Command &messageToSend) 108 | { 109 | if (connection_->connected()) 110 | { 111 | codec_.send(connection_, messageToSend); 112 | TimeOutCounter_ = 0; 113 | } 114 | else 115 | { 116 | printf("error to send!\n"); 117 | } 118 | } 119 | 120 | private: 121 | // lkpCmdClient类目前只支持1个连接 122 | void onConnection(const TcpConnectionPtr &conn) 123 | { 124 | if (conn->connected()) 125 | { 126 | 127 | connection_ = conn; 128 | //只要连接上就立刻发命令 129 | SendToServer(commandToSend_); 130 | } 131 | else 132 | { 133 | connection_.reset(); 134 | connection_ = nullptr; 135 | printf("lkp-extent service error: server unconnected!\n"); 136 | } 137 | } 138 | 139 | void onTimer() 140 | { 141 | if(!connection_ || ((connection_)&&!connection_->connected())){ 142 | printf("lkp-extent service error: Cannot find lkp-server!\n"); 143 | exit(0); 144 | } 145 | TimeOutCounter_ ++; 146 | if(TimeOutCounter_ > 5){ 147 | printf("lkp-extent service error: Timeout!\n"); 148 | exit(0); 149 | } 150 | } 151 | 152 | //收到Server的command运行结果return,打印return到terminal 153 | void onReturnMsg(const TcpConnectionPtr &conn, const ReturnPtr &message, Timestamp time) 154 | { 155 | 156 | TimeOutCounter_ = 0; 157 | lkpMessage::commandID myCommandEnum = message->command(); 158 | string myCommandString; 159 | LOG_INFO<<"lkpCommand: Receive a return message, command type:"<client_num(); 165 | printf("LIST: %u clients have connected..\n", clientNum); 166 | 167 | lkpMessage::Return::NodeInfo node; 168 | for (int i = 0; i < clientNum; ++i) 169 | { 170 | node = message->node_info(i); 171 | printf(" Node %2u: %s\n", node.node_id(), node.node_msg().c_str()); 172 | } 173 | } 174 | else{ 175 | uint32_t clientNum = message->client_num(); 176 | uint32_t clientOKNum = message->client_ok_num(); 177 | printf("%s : %u / %u clients succeess!\n", myCommandString.c_str(), clientOKNum, clientNum); 178 | lkpMessage::Return::NodeInfo node; 179 | int sz = message->node_info_size(); 180 | for (int i = 0; i < sz; ++i) 181 | { 182 | node = message->node_info(i); 183 | printf(" Node %2u: %s\n", node.node_id(), node.node_msg().c_str()); 184 | } 185 | } 186 | 187 | exit(0); 188 | } 189 | 190 | //收到未知数据包的回调函数 191 | void onUnknownMsg(const TcpConnectionPtr &conn, const MessagePtr &message, Timestamp time) 192 | { 193 | printf("Error!\n"); 194 | } 195 | 196 | EventLoop *loop_; 197 | TcpClient client_; 198 | 199 | lkpDispatcher dispatcher_; 200 | lkpCodec codec_; 201 | 202 | MutexLock mutex_; 203 | TcpConnectionPtr connection_; 204 | 205 | lkpMessage::Command commandToSend_; 206 | 207 | int TimeOutCounter_ = 0; 208 | }; 209 | 210 | int main(int argc, char *argv[]) 211 | { 212 | EventLoop loop; 213 | lkpMessage::Command commandToSend; 214 | 215 | // argv style, argc = 4 216 | // TODO : 现在这里面无法区分testcase和testcluster,研究一下lkp里面的testcluster是什么东西 217 | // [RUN] [TESTCASE] [NODEID] [VMCNT] 218 | // [UPDATE/RESULT] [NULL] [NODEID] [NULL] 219 | // [PUSH] [TESTCASE] [NODEID] [NULL] 220 | if (argc != 6) 221 | { 222 | printf(" Usage: [Command] [Testcase] [NodeID] [ContainerCnt] [PATH]\n"); 223 | return -1; 224 | } 225 | else 226 | { 227 | lkpMessage::commandID lkpEnum; 228 | 229 | //Command 230 | if (lkpCmdsToEnum(string(argv[1]), lkpEnum)){ 231 | commandToSend.set_command(lkpEnum); 232 | } 233 | 234 | else{ 235 | printf("lkpCmdClient Error: No supprt for command %s\n" 236 | " Usage: [Command] [Testcase] [NodeID] [ContainerCnt] [PATH]\n", 237 | argv[1]); 238 | } 239 | 240 | //Testcase 241 | commandToSend.set_testcase(string(argv[2])); 242 | 243 | 244 | //NodeID,-1表示发送给全体 245 | int nodeID = atoi(argv[3]); 246 | if (nodeID >= 0){ 247 | commandToSend.set_node_id(nodeID); 248 | commandToSend.set_send_to_all(false); 249 | } 250 | else{ 251 | commandToSend.set_node_id(-1); 252 | commandToSend.set_send_to_all(true); 253 | } 254 | 255 | //ContainerCnt 256 | int dockerNum = atoi(argv[4]); 257 | if (dockerNum > 0){ 258 | commandToSend.set_docker_num(dockerNum); 259 | } 260 | 261 | } 262 | 263 | const string myPath = string(argv[5]); 264 | std::map configMap; 265 | lkpConfig CmdConfig; 266 | 267 | //配置初始化 268 | lkpConfigInit(configMap, CmdConfig, myPath); 269 | 270 | const uint16_t port = CmdConfig.ServerListenPort; 271 | //log 272 | muduo::AsyncLogging log( myPath + "/log/CLI_logfile", kRollSize); 273 | log.start(); 274 | g_asyncLog = &log; 275 | 276 | lkpCmdClient client(&loop, port, commandToSend); 277 | client.connect(); 278 | loop.loop(); 279 | } -------------------------------------------------------------------------------- /src/lkpHelper.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "lkpHelper.h" 7 | 8 | 9 | using namespace std; 10 | 11 | 12 | const std::vector ConfigString = { 13 | "ServerListenPort", 14 | "ServerThreadsNum", 15 | "ServerTimeControl", 16 | "ServerflushInterval", 17 | "ServerPushPath", 18 | "ServerResultPath", 19 | "ServerAddress", 20 | "ServerPort", 21 | "HeartBeatTime", 22 | "ClientPushPath" 23 | }; 24 | 25 | bool lkpConfigInit(std::map & m, lkpConfig & myConfig, const string & ROOT_DIR){ 26 | 27 | const string CONFIG_PATH = ROOT_DIR + "/lkp-extent.config"; 28 | if(!ReadConfig(CONFIG_PATH, m)){ 29 | std::cout << "lkp-ctl service start failed: Cannot read config file!" << std::endl; 30 | exit(EXIT_FAILURE); 31 | } 32 | for(string config:ConfigString){ 33 | if(!m.count(config)){ 34 | cout << "lkp-ctl service start failed: miss configure: " << config << endl; 35 | return false; 36 | } 37 | } 38 | myConfig.ServerListenPort = stoi(m.at(ConfigString[0])); 39 | myConfig.ServerThreadsNum = stoi(m.at(ConfigString[1])); 40 | myConfig.ServerTimeControl = stoi(m.at(ConfigString[2])); 41 | myConfig.ServerflushInterval = stoi(m.at(ConfigString[3])); 42 | myConfig.ServerPushPath = m.at(ConfigString[4]); 43 | myConfig.ServerResultPath = m.at(ConfigString[5]); 44 | myConfig.ServerAddress = m.at(ConfigString[6]); 45 | myConfig.ServerPort = stoi(m.at(ConfigString[7])); 46 | myConfig.HeartBeatTime = stoi(m.at(ConfigString[8])); 47 | myConfig.ClientPushPath = m.at(ConfigString[9]); 48 | return true; 49 | } 50 | 51 | //commandID和"UPDATE"等字符串的映射关系 52 | std::vector lkpCommands = { 53 | "UPDATE", "RUN", "RESULT", "PUSH", "LIST"}; 54 | 55 | bool lkpCmdsToEnum(const string &lkpCmdString, lkpMessage::commandID &lkpEnum) 56 | { 57 | size_t sz = lkpCommands.size(); 58 | for (int i = 0; i < sz; ++i) 59 | { 60 | if (lkpCommands[i].compare(lkpCmdString) == 0) 61 | { 62 | lkpEnum = static_cast(i); 63 | return true; 64 | } 65 | } 66 | return false; 67 | } 68 | 69 | bool lkpEnumToCmds(const lkpMessage::commandID lkpEnum, string &lkpCmdString) 70 | { 71 | if (lkpEnum >= lkpCommands.size() || lkpEnum < 0) 72 | return false; 73 | lkpCmdString = lkpCommands[lkpEnum]; 74 | return true; 75 | } 76 | 77 | 78 | lkpClientPool::lkpClientPool() 79 | { 80 | connections_.clear(); 81 | nodeCount_ = 0; 82 | idleNodeID.clear(); 83 | } 84 | 85 | //客户端总量 86 | int lkpClientPool::size() 87 | { 88 | return connections_.size(); 89 | } 90 | 91 | //不是命令行时才可以调用,增加新客户端 92 | int lkpClientPool::add(TcpConnectionPtr conn) 93 | { 94 | int nodeID = -1; 95 | 96 | //分配新的ID 97 | if (idleNodeID.empty()) 98 | { 99 | nodeID = nodeCount_++; 100 | connections_[nodeID] = conn; //新客户端加入 101 | 102 | // printf("新客户端加入,nodeID is:%d\n", nodeID); 103 | // LOG_INFO<<"新客户端加入,nodeID is:"<= 0; --i) { 206 | if (!IsSpace(str[i])) { 207 | break; 208 | } 209 | } 210 | end_pos = i; 211 | str = str.substr(start_pos, end_pos - start_pos + 1); 212 | } 213 | 214 | //分析一行语句 215 | bool AnalyseLine(const string & line, string & key, string & value) 216 | { 217 | if (line.empty()) 218 | return false; 219 | int start_pos = 0, end_pos = line.size() - 1, pos; 220 | if ((pos = line.find(COMMENT_CHAR)) != -1) { 221 | if (0 == pos) { // 行的第一个字符就是注释字符 222 | return false; 223 | } 224 | end_pos = pos - 1; 225 | } 226 | string new_line = line.substr(start_pos, start_pos + 1 - end_pos); // 预处理,删除注释部分 227 | 228 | if ((pos = new_line.find('=')) == -1) 229 | return false; // 没有=号 230 | 231 | key = new_line.substr(0, pos); 232 | value = new_line.substr(pos + 1, end_pos + 1- (pos + 1)); 233 | 234 | Trim(key); 235 | if (key.empty()) { 236 | return false; 237 | } 238 | Trim(value); 239 | return true; 240 | } 241 | 242 | bool ReadConfig(const string & filename, map & m) 243 | { 244 | m.clear(); 245 | ifstream infile(filename.c_str()); 246 | if (!infile) { 247 | cout << "lkp-ctl init failed: Config File open error!" << endl; 248 | return false; 249 | } 250 | string line, key, value; 251 | while (getline(infile, line)) { 252 | if (AnalyseLine(line, key, value)) { 253 | m[key] = value; 254 | } 255 | } 256 | infile.close(); 257 | return true; 258 | } 259 | 260 | // 打印读取出来的数据 261 | void PrintConfig(const map & m) 262 | { 263 | map::const_iterator mite = m.begin(); 264 | for (; mite != m.end(); ++mite) { 265 | cout << mite->first << "=" << mite->second << endl; 266 | } 267 | } 268 | -------------------------------------------------------------------------------- /src/lkpHelper.h: -------------------------------------------------------------------------------- 1 | #ifndef LKP_HELPER 2 | #define LKP_HELPER 3 | 4 | #define COMMENT_CHAR '#' 5 | 6 | #include 7 | #include 8 | #include 9 | #include "muduo/net/Buffer.h" 10 | #include "muduo/net/TcpConnection.h" 11 | #include "lib/lkpProto.pb.h" 12 | 13 | // using namespace std; 14 | using namespace muduo; 15 | using namespace muduo::net; 16 | 17 | extern std::vector lkpCommands; 18 | extern const std::vector ConfigString; 19 | extern string ROOT_DIR; 20 | 21 | typedef struct myLkpConfig{ 22 | uint16_t ServerListenPort; 23 | uint16_t ServerThreadsNum; 24 | uint16_t ServerTimeControl; 25 | uint16_t ServerflushInterval; 26 | uint16_t ServerPort; 27 | uint16_t HeartBeatTime; 28 | string ServerPushPath; 29 | string ServerResultPath; 30 | string ServerAddress; 31 | string ClientPushPath; 32 | } lkpConfig; 33 | 34 | bool lkpConfigInit(std::map & m, lkpConfig & myConfig, const string & ROOT_DIR); 35 | 36 | 37 | 38 | 39 | //将lkpCommand字符串转换为message中使用的enum 40 | bool lkpCmdsToEnum(const string& lkpCmdString, lkpMessage::commandID& lkpEnum); 41 | //将lkpMessage::commandID中的enum转换为字符串 42 | bool lkpEnumToCmds(const lkpMessage::commandID lkpEnum, string& lkpCmdString); 43 | 44 | //读取lkp-extend配置文件 45 | bool ReadConfig(const string & filename, std::map & m); 46 | //打印配置文件到输出流 47 | void PrintConfig(const std::map & m); 48 | 49 | 50 | class lkpClientPool : noncopyable 51 | { 52 | friend class lkpServer; 53 | public: 54 | lkpClientPool(); 55 | 56 | //客户端总量 57 | int size(); 58 | 59 | //不是命令行时才调用,增加新客户端 60 | int add(TcpConnectionPtr conn); 61 | 62 | //删除ID 63 | bool del(int nodeID); 64 | 65 | //获取conn 66 | TcpConnectionPtr getConn(int nodeID); 67 | 68 | //清空信息 69 | void clear_info(); 70 | 71 | //填充信息 72 | void update_info(int nodeID,string info); 73 | 74 | //获取节点的信息 75 | string get_info(int nodeID); 76 | 77 | private: 78 | //client pool nodeID -- cfd 79 | std::map connections_; 80 | 81 | int nodeCount_; 82 | std::set idleNodeID;//存放当前闲置的nodeID 83 | 84 | std::map node_info; 85 | }; 86 | 87 | #endif -------------------------------------------------------------------------------- /src/lkpProto.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package lkpMessage; 4 | 5 | enum commandID{ 6 | UPDATE = 0; //need no parameter 7 | RUN = 1; //optional: docker_num 8 | RESULT = 2; //need no parameter 9 | PUSH = 3; //required: testcase length 10 | LIST = 4; //only when cmdClinet use 11 | } 12 | 13 | // Command inlcudes UPDATE, RUN, RESULT, PUSH, LIST 14 | // CmdClient send Command to Server, Server transfer to Clients 15 | message Command { 16 | commandID command = 1; 17 | bool send_to_all = 2; 18 | string testcase = 3; 19 | uint32 docker_num = 4; 20 | uint32 tesetcase_len = 5; 21 | uint32 node_id = 6; 22 | } 23 | 24 | // File include file informations, for transport testcase and result file 25 | // between Server and Clients 26 | message File { 27 | enum filetype{ 28 | TESTCASE = 0; //Server push testcase to client 29 | RESULT = 1; //Server request result, client send to server 30 | END = 2; 31 | } 32 | filetype file_type = 1; 33 | string file_name = 2; 34 | uint32 patch_len = 3; 35 | uint32 file_size = 4; 36 | bool first_patch = 5; 37 | bytes content = 6; 38 | uint32 node_id = 7; 39 | } 40 | 41 | // Client which received Command should return a CommandACK 42 | // for Server count whether all nodes run the Command 43 | message CommandACK { 44 | bool status = 1; 45 | commandID command = 2; //Return for check 46 | string ack_message = 3; //Error message, etc. 47 | uint32 node_id = 4; 48 | } 49 | 50 | // Clinets should send HearBeat to maintain the connection 51 | message HeartBeat { 52 | bool status = 1; 53 | } 54 | 55 | // Only when a Client receive a Command::PUSH return a PushACK 56 | // and Server should start transport testcase 57 | message PushACK { 58 | bool status = 1; 59 | string ack_message = 2; 60 | uint32 node_id = 3; 61 | } 62 | 63 | // When Server collect all nodes CommandACK or Timeout 64 | // send Return to lkpCommandClient and printf 65 | message Return { 66 | uint32 client_num = 1; 67 | uint32 client_ok_num = 2; 68 | commandID command = 3; 69 | message NodeInfo{ 70 | uint32 node_id = 1; 71 | string node_msg = 2; 72 | } 73 | repeated NodeInfo node_info = 4; 74 | } -------------------------------------------------------------------------------- /src/lkpServer.cc: -------------------------------------------------------------------------------- 1 | #include "lkpServer.h" 2 | 3 | lkpServer *g_asyncLog_server = NULL; 4 | //前端写日志时调用 5 | void asyncOutput_server(const char *msg, int len) 6 | { 7 | g_asyncLog_server->append(msg, len); 8 | } 9 | 10 | lkpServer::lkpServer(EventLoop *loop, 11 | const InetAddress &listenAddr, 12 | const lkpConfig &MyConfig, 13 | off_t rollSize) 14 | : server_(loop, listenAddr, "lkpServer"), 15 | loop_(loop), 16 | numThreads_(MyConfig.ServerThreadsNum), 17 | /*lkpCodec & lkpDispatcher*/ 18 | //绑定dispatcher_收到消息后的默认回调函数,这里设置为收到的message类型未知时的回调函数 19 | dispatcher_(std::bind(&lkpServer::onUnknownMsg, this, 20 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)), 21 | //服务器收到消息后,解析形成对应的message,用message作为参数执行onProtobufMessage,哈系表已经存放了message类型对应的回调函数CallbackT 22 | codec_(std::bind(&lkpDispatcher::onProtobufMessage, &dispatcher_, 23 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)), 24 | //push的文件 25 | kBufSize_(64 * 1024), 26 | 27 | /* 高速缓冲区使用变量,日志文件使用*/ 28 | flushInterval_(MyConfig.ServerflushInterval), 29 | running_(false), 30 | rollSize_(rollSize), 31 | thread_(std::bind(&lkpServer::threadFunc, this), "Logging_SendtoCMDclient"), 32 | latch_(1), 33 | cond_(mutex_), 34 | currentBuffer_(new Buffer_log), 35 | nextBuffer_(new Buffer_log), 36 | buffers_(), 37 | basename_(ROOT_DIR + "/log/logfile")//缓冲区的文件名称 38 | 39 | { 40 | //缓冲区使用 41 | 42 | currentBuffer_->bzero(); 43 | nextBuffer_->bzero(); 44 | buffers_.reserve(16); 45 | 46 | //绑定业务lkpMessage::xxxxx的回调函数,lkpMessage::Command等在.proto文件中 47 | dispatcher_.registerMessageCallback(std::bind(&lkpServer::onCommandMsg, 48 | this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 49 | dispatcher_.registerMessageCallback(std::bind(&lkpServer::onCommandACK, 50 | this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 51 | dispatcher_.registerMessageCallback(std::bind(&lkpServer::onPushACK, 52 | this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 53 | dispatcher_.registerMessageCallback(std::bind(&lkpServer::onFileMsg, 54 | this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 55 | dispatcher_.registerMessageCallback(std::bind(&lkpServer::onHeartBeat, 56 | this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 57 | 58 | //绑定新连接请求回调函数 59 | server_.setConnectionCallback( 60 | std::bind(&lkpServer::onConnection, this, std::placeholders::_1)); 61 | 62 | //绑定lkpCodec接收server新消息的回调函数,解析后形成正确类型的message 63 | server_.setMessageCallback( 64 | std::bind(&lkpCodec::onMessage, &codec_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 65 | 66 | 67 | 68 | //定时断开无响应客户端的连接 69 | connectionBuckets_.resize(MyConfig.ServerTimeControl); 70 | loop->runEvery(1.0, std::bind(&lkpServer::onTimer, this)); 71 | 72 | //设置IO线程的数量 73 | server_.setThreadNum(numThreads_); 74 | } 75 | 76 | //启动服务器 77 | void lkpServer ::start() 78 | { 79 | // muduo::Logger::setOutput(asyncOutput_server); //LOG_INFO调用asyncOutput_server 80 | server_.start(); 81 | 82 | //push的文件描述符 83 | fpMap.clear(); 84 | 85 | //logging 86 | running_ = true; //允许后端写日志 87 | thread_.start(); //启动后端线程threadFunc 88 | latch_.wait(); //等待后端线程threadFunc启动,否则服务器不能执行其他动作 89 | 90 | printf("lkp-extent server init: server start successfully!\n"); 91 | } 92 | 93 | //向客户端发送数据 94 | void lkpServer ::SendToClient(const google::protobuf::Message &message, const TcpConnectionPtr& conn) 95 | { 96 | if (conn && conn->connected()) 97 | { 98 | codec_.send(conn, message); 99 | } 100 | else{ 101 | // printf("No such client!\n"); 102 | LOG_INFO<<"No such client!"; 103 | } 104 | 105 | } 106 | 107 | //向命令行回复结果 108 | void lkpServer ::SendToCmdClient(const google::protobuf::Message &message) 109 | { 110 | if (CmdConnection_->connected()) 111 | { 112 | codec_.send(CmdConnection_, message); 113 | } 114 | } 115 | 116 | //客户端请求建立新的连接 117 | void lkpServer ::onConnection(const TcpConnectionPtr &conn) 118 | { 119 | LOG_INFO << conn->peerAddress().toIpPort() << " -> " 120 | << conn->localAddress().toIpPort() << " is " 121 | << (conn->connected() ? "UP" : "DOWN"); 122 | 123 | if (conn->connected()) 124 | { 125 | //如果是来自本地回环地址的连接,应该是唯一的命令行 126 | if (!conn->peerAddress().toIp().compare("127.0.0.1")) 127 | { 128 | if (!hasCmdConnected_) 129 | { 130 | CmdConnection_ = conn; 131 | hasCmdConnected_ = true; 132 | LOG_INFO<<"lkpServer: Has connected to cmdClient!"; 133 | } 134 | else 135 | { 136 | CmdConnection_->shutdown(); 137 | LOG_INFO<<"lkpServer Error: Has connected to a CmdClient!"; 138 | } 139 | } 140 | //和客户端建立连接 141 | else 142 | { 143 | int nodeID = clientPool_.add(conn); 144 | // printf("onConnection nodeID is:%d\n",nodeID); 145 | 146 | //time wheeling 147 | EntryPtr entry(new Entry(conn, this, nodeID)); //为新客户端分配Entry 148 | connectionBuckets_.back().insert(entry); 149 | WeakEntryPtr weakEntry(entry); //弱引用是为了避免增加引用计数 150 | conn->setContext(weakEntry); //把弱引用放入TcpConnectionPtr的setContext,从而可以取出 151 | } 152 | } 153 | else 154 | { 155 | if(hasCmdConnected_){ 156 | //取消cmd标志 157 | hasCmdConnected_ = false; 158 | } 159 | else{ 160 | //从clientpool中删除 161 | WeakEntryPtr weakEntry(boost::any_cast(conn->getContext())); //利用Context取出弱引用 162 | EntryPtr entry(weakEntry.lock()); 163 | int nodeID = entry->Entry_nodeID; 164 | clientPool_.del(nodeID); 165 | LOG_INFO<<"Client_pool: A connection unconnected, Del nodeID:"<testcase(); //文件名称 174 | //获取文件的大小 175 | struct stat statbuf; 176 | stat(fileName.c_str(), &statbuf); 177 | int fileSize = statbuf.st_size; 178 | 179 | //单播 180 | if (!message->send_to_all()) 181 | { 182 | clientNum_ = 1; 183 | 184 | FILE *fp = ::fopen(fileName.c_str(), "rb"); //打开文件 185 | if (!fp) 186 | { 187 | perror("lkp-ctl open push file error"); 188 | return; 189 | } 190 | 191 | int nodeID = message->node_id(); 192 | TcpConnectionPtr conn = clientPool_.getConn(nodeID); 193 | 194 | FilePtr ctx(fp, ::fclose); //多了::fclose参数,表示fp对象的引用计数器变成0时,调用::fclose来销毁fp 195 | fpMap[conn] = ctx; 196 | char buf[kBufSize_]; 197 | size_t nread = ::fread(buf, 1, sizeof buf, fp); //读取kBufSize的内容 198 | 199 | lkpMessage::File fileMessage; 200 | fileMessage.set_file_type(lkpMessage::File::TESTCASE); 201 | fileMessage.set_node_id(nodeID); 202 | fileMessage.set_file_size(fileSize); 203 | fileMessage.set_patch_len(nread); 204 | fileMessage.set_first_patch(true); 205 | fileMessage.set_content(buf); 206 | fileMessage.set_file_name(message->testcase()); 207 | 208 | conn->setWriteCompleteCallback(std::bind(&lkpServer::onWriteComplete, this, std::placeholders::_1)); //发完一次后继续发 209 | SendToClient(fileMessage, conn); 210 | } 211 | //广播 212 | else 213 | { 214 | clientNum_ = clientPool_.size(); 215 | 216 | //对所有节点作一次单播 217 | for (auto it : clientPool_.connections_) 218 | { 219 | FILE *fp = ::fopen(fileName.c_str(), "rb"); //打开文件 220 | if (!fp) 221 | { 222 | perror("lkp-ctl open push file error"); 223 | return; 224 | } 225 | 226 | int nodeID = it.first; 227 | TcpConnectionPtr conn = it.second; 228 | 229 | FilePtr ctx(fp, ::fclose); //多了::fclose参数,表示fp对象的引用计数器变成0时,调用::fclose来销毁fp 230 | fpMap[conn] = ctx; 231 | char buf[kBufSize_]; 232 | size_t nread = ::fread(buf, 1, sizeof buf, fp); //读取kBufSize的内容 233 | 234 | lkpMessage::File fileMessage; 235 | fileMessage.set_file_type(lkpMessage::File::TESTCASE); 236 | fileMessage.set_node_id(nodeID); 237 | fileMessage.set_file_size(fileSize); 238 | fileMessage.set_patch_len(nread); 239 | fileMessage.set_first_patch(true); 240 | fileMessage.set_content(buf); 241 | fileMessage.set_file_name(message->testcase()); 242 | 243 | conn->setWriteCompleteCallback(std::bind(&lkpServer::onWriteComplete, this, std::placeholders::_1)); //发完一次后继续发 244 | SendToClient(fileMessage, conn); 245 | } 246 | } 247 | } 248 | 249 | 250 | void lkpServer::BroadToClients(lkpMessage::Command message){ 251 | for (auto it = clientPool_.connections_.begin(); it != clientPool_.connections_.end(); ++it){ 252 | message.set_node_id(it->first); 253 | SendToClient(message, it->second); 254 | } 255 | } 256 | 257 | //收到命令的回调函数,server转发给client, client执行。并且回复命令行 258 | void lkpServer ::onCommandMsg(const TcpConnectionPtr &conn, const RecvCommandPtr &message, Timestamp time) 259 | { 260 | clientNum_ = clientOKNum_ = ackTimes_ = 0; 261 | clientPool_.clear_info(); 262 | 263 | //解析命令行的命令 264 | lkpMessage::commandID myCommand = message->command(); 265 | string myCommandString; 266 | lkpEnumToCmds(myCommand, myCommandString); 267 | LOG_INFO<<"Recv a command:"<send_to_all() && message->node_id()>=0 && !clientPool_.getConn(message->node_id())){ 270 | lkpMessage::Return ReturnToSend;//返回给命令行的回复 271 | ReturnToSend.set_command(myCommand); 272 | ReturnToSend.set_client_num(clientPool_.size()); 273 | ReturnToSend.set_client_ok_num(0); 274 | lkpMessage::Return::NodeInfo *NodeInfoPtr = ReturnToSend.add_node_info(); 275 | NodeInfoPtr->set_node_id(message->node_id()); 276 | NodeInfoPtr->set_node_msg("ERROR 1: This ID doesn't exist!"); 277 | } 278 | 279 | switch(myCommand){ 280 | case lkpMessage::UPDATE: 281 | case lkpMessage::RUN: 282 | case lkpMessage::RESULT:{ 283 | if (!message->send_to_all() && message->node_id()>=0){ 284 | SendToClient(*message, clientPool_.getConn(message->node_id())); 285 | clientNum_ = 1; 286 | } 287 | else{ 288 | BroadToClients(*message); 289 | clientNum_ = clientPool_.size(); 290 | } 291 | break; 292 | } 293 | case lkpMessage::PUSH:{ 294 | pushToClient(message); 295 | break; 296 | } 297 | case lkpMessage::LIST:{ 298 | lkpMessage::Return ReturnToSend;//返回给命令行的回复 299 | ReturnToSend.set_command(myCommand); 300 | ReturnToSend.set_client_num(clientPool_.size()); 301 | ReturnToSend.set_client_ok_num(clientPool_.size()); 302 | 303 | //所有在线客户端的信息 304 | lkpMessage::Return::NodeInfo *NodeInfoPtr; 305 | for (auto it = clientPool_.connections_.begin(); it != clientPool_.connections_.end(); ++it) 306 | { 307 | NodeInfoPtr = ReturnToSend.add_node_info(); 308 | NodeInfoPtr->set_node_id(it->first); 309 | NodeInfoPtr->set_node_msg(it->second->peerAddress().toIp()); 310 | } 311 | 312 | //回复给命令行 313 | SendToCmdClient(ReturnToSend); 314 | break; 315 | } 316 | } 317 | 318 | } 319 | 320 | //每次发送64kb 321 | void lkpServer ::onWriteComplete(const TcpConnectionPtr &conn) 322 | { 323 | FilePtr &fp = fpMap[conn]; 324 | 325 | char buf[kBufSize_]; 326 | size_t nread = ::fread(buf, 1, sizeof(buf), get_pointer(fp)); 327 | 328 | //续传 329 | if (nread > 0) 330 | { 331 | lkpMessage::File fileMessage; 332 | fileMessage.set_file_type(lkpMessage::File::TESTCASE); 333 | fileMessage.set_first_patch(false); 334 | fileMessage.set_patch_len(nread); 335 | fileMessage.set_content(buf); 336 | 337 | SendToClient(fileMessage,conn); 338 | } 339 | //结束 340 | else 341 | { 342 | //发送结束信号 343 | lkpMessage::File fileMessage; 344 | fileMessage.set_file_type(lkpMessage::File::END); 345 | 346 | conn->setWriteCompleteCallback(NULL); 347 | 348 | SendToClient(fileMessage,conn); 349 | 350 | LOG_INFO<<"push testcase to client end!"; 351 | } 352 | } 353 | 354 | //收到pushack的回调函数,应该开始发testecase的文件内容 355 | void lkpServer ::onPushACK(const TcpConnectionPtr &conn, const PushACKPtr &message, Timestamp time) 356 | { 357 | 358 | ackTimes_++; 359 | if(message->status()){ 360 | clientOKNum_++; 361 | } 362 | 363 | //收到错误才回复给命令行 364 | if(!message->status()){ 365 | clientPool_.update_info(message->node_id(),message->ack_message()); 366 | } 367 | 368 | //回复给命令行 369 | if(ackTimes_ == clientNum_){ 370 | lkpMessage::Return Return; 371 | Return.set_command(lkpMessage::commandID::PUSH); 372 | Return.set_client_num(clientNum_); 373 | Return.set_client_ok_num(clientOKNum_); 374 | 375 | //出错的节点记录在info 376 | for (auto it = clientPool_.node_info.begin(); it != clientPool_.node_info.end(); ++it){ 377 | lkpMessage::Return::NodeInfo *NodeInfoPtr = Return.add_node_info(); 378 | NodeInfoPtr->set_node_id(it->first); 379 | NodeInfoPtr->set_node_msg(it->second); 380 | } 381 | 382 | SendToCmdClient(Return); 383 | } 384 | } 385 | 386 | //收到command ACK的回调函数,应该使统计数量++ 387 | void lkpServer ::onCommandACK(const TcpConnectionPtr &conn, const CommandACKPtr &message, Timestamp time) 388 | { 389 | ackTimes_++; 390 | if(message->status()){ 391 | clientOKNum_++; 392 | } 393 | 394 | //收到错误才回复给命令行 395 | if(!message->status()){ 396 | clientPool_.update_info(message->node_id(),message->ack_message()); 397 | } 398 | 399 | //回复给命令行 400 | if(ackTimes_ == clientNum_){ 401 | lkpMessage::Return Return; 402 | Return.set_command(message->command()); 403 | Return.set_client_num(clientNum_); 404 | Return.set_client_ok_num(clientOKNum_); 405 | 406 | //出错的节点记录在info 407 | for (auto it = clientPool_.node_info.begin(); it != clientPool_.node_info.end(); ++it){ 408 | lkpMessage::Return::NodeInfo *NodeInfoPtr = Return.add_node_info(); 409 | NodeInfoPtr->set_node_id(it->first); 410 | NodeInfoPtr->set_node_msg(it->second); 411 | } 412 | 413 | SendToCmdClient(Return); 414 | } 415 | } 416 | 417 | //收到file message的回调函数,server收到的应该是result, client收到的应该是testcase 418 | void lkpServer ::onFileMsg(const TcpConnectionPtr &conn, const RecvFilePtr &message, Timestamp time) 419 | { 420 | //文件发送结束 421 | if (message->file_type() == lkpMessage::File::END) 422 | { 423 | ackTimes_++; 424 | 425 | ::fclose(outputfpMap_[conn]); //必须关闭,不然会错误 426 | 427 | //获取文件的大小 428 | struct stat statbuf; 429 | stat(fileNameMap_[conn].c_str(), &statbuf); 430 | int recvSize = statbuf.st_size; 431 | 432 | //检查文件是否完整 433 | if (recvSize != fileSizeMap_[conn]) 434 | { 435 | // printf("recvSize:%d,fileSize_:%d\n", recvSize, fileSizeMap_[conn]); 436 | // printf("node:%d file is not complete!\n",message->node_id()); 437 | LOG_INFO<<"recvSize:"<node_id()<<" file is not complete!"; 439 | 440 | clientPool_.update_info(message->node_id(),"file is not completed"); 441 | } 442 | else 443 | { 444 | // printf("recv a complete file\n"); 445 | LOG_INFO<<"recv a complete file"; 446 | 447 | //成功 448 | clientOKNum_++; 449 | } 450 | 451 | //回复给命令行 452 | if (ackTimes_ == clientNum_) 453 | { 454 | lkpMessage::Return Return; 455 | Return.set_command(lkpMessage::commandID::RESULT); 456 | Return.set_client_num(clientNum_); 457 | Return.set_client_ok_num(clientOKNum_); 458 | 459 | //出错的节点记录在info 460 | for (auto it = clientPool_.node_info.begin(); it != clientPool_.node_info.end(); ++it) 461 | { 462 | lkpMessage::Return::NodeInfo *NodeInfoPtr = Return.add_node_info(); 463 | NodeInfoPtr->set_node_id(it->first); 464 | NodeInfoPtr->set_node_msg(it->second); 465 | } 466 | 467 | SendToCmdClient(Return); 468 | } 469 | 470 | return; 471 | } 472 | //第一次接收 473 | else if (message->first_patch()) 474 | { 475 | int nodeID = message->node_id(); 476 | fileNameMap_[conn] = ROOT_DIR + "/results/remote/node" + std::to_string(nodeID) + "-" + message->file_name(); 477 | LOG_INFO<<"fileName_:"<file_size(); 480 | FILE *fp = ::fopen(fileNameMap_[conn].c_str(), "wb"); 481 | if (!fp) 482 | { 483 | perror("lkp-ctl receive file error"); 484 | return; 485 | } 486 | outputfpMap_[conn] = fp; 487 | } 488 | 489 | //每次接收的都输出 490 | fwrite(message->content().c_str(), 1, message->patch_len(), outputfpMap_[conn]); 491 | } 492 | 493 | //收到心跳包的回调函数 494 | void lkpServer ::onHeartBeat(const TcpConnectionPtr &conn, const HeartBeatPtr &message, Timestamp time) 495 | { 496 | //time wheeling 497 | WeakEntryPtr weakEntry(boost::any_cast(conn->getContext())); //利用Context取出弱引用 498 | 499 | EntryPtr entry(weakEntry.lock()); //引用一次,增加引用计数 500 | if (entry) 501 | { 502 | connectionBuckets_.back().insert(entry); //放入环形缓冲区,缓冲区的每个位置放置1个哈希表,哈系表的元素是shared_ptr 503 | } 504 | } 505 | 506 | //收到未知数据包的回调函数 507 | void lkpServer ::onUnknownMsg(const TcpConnectionPtr &conn, const MessagePtr &message, Timestamp time) 508 | { 509 | printf("lkp-extent warning: Unknown Message! Shut down the connection\n"); 510 | conn->shutdown(); 511 | LOG_INFO<<"Warning! shut down the connection"; 512 | } 513 | 514 | //计时器,前进tail 515 | void lkpServer::onTimer() 516 | { 517 | connectionBuckets_.push_back(Bucket()); //因为环形队列的大小已经固定,在队尾插入会导致删除 518 | // dumpConnectionBuckets(); 519 | } 520 | 521 | //打印心跳连接情况 522 | void lkpServer::dumpConnectionBuckets() const 523 | { 524 | int idx = 0; 525 | for (WeakConnectionList::const_iterator bucketI = connectionBuckets_.begin(); 526 | bucketI != connectionBuckets_.end(); 527 | ++bucketI, ++idx) 528 | { 529 | const Bucket &bucket = *bucketI; 530 | 531 | LOG_INFO<avail() > len) 550 | { 551 | currentBuffer_->append(logline, len); 552 | } 553 | //一级当前已满,把一级当前加入二级列表,把一级预备转正 554 | else 555 | { 556 | buffers_.push_back(std::move(currentBuffer_)); //一级当前加入二级列表 557 | 558 | if (nextBuffer_) 559 | { 560 | currentBuffer_ = std::move(nextBuffer_); //一级预备转正 561 | } 562 | else 563 | { 564 | currentBuffer_.reset(new Buffer_log); //基本上不会发生,预备空时,重新申请 565 | } 566 | 567 | currentBuffer_->append(logline, len); //向一级当前写 568 | cond_.notify(); //生产者释放条件变量,通知后端条件满足 569 | } 570 | } 571 | 572 | //后端调用,向日志文件写 muduo::Thread thread_ 绑定该函数,实现后端线程负责写 573 | void lkpServer::threadFunc() 574 | { 575 | assert(running_ == true); 576 | 577 | //让start()的latch_.wait()得到0,可以运行前端线程 578 | latch_.countDown(); 579 | 580 | LogFile output(basename_, rollSize_, false); 581 | 582 | //准备2块缓冲区,用于分配给一级 583 | BufferPtr newBuffer1(new Buffer_log); 584 | BufferPtr newBuffer2(new Buffer_log); 585 | newBuffer1->bzero(); 586 | newBuffer2->bzero(); 587 | 588 | //后端操作的二级 589 | BufferVector buffersToWrite; //写日志操作的缓冲区 590 | buffersToWrite.reserve(16); //预分配16个位置 591 | 592 | //真正运行的部分 593 | while (running_) 594 | { 595 | assert(newBuffer1 && newBuffer1->length() == 0); 596 | assert(newBuffer2 && newBuffer2->length() == 0); 597 | assert(buffersToWrite.empty()); 598 | 599 | //加锁,此时前端不能操作一级 600 | { 601 | muduo::MutexLockGuard lock(mutex_); 602 | //条件变量,如果二级列表是空的,就等待超时、前端释放条件变量。 603 | if (buffers_.empty()) 604 | { 605 | cond_.waitForSeconds(flushInterval_); 606 | } 607 | 608 | buffers_.push_back(std::move(currentBuffer_)); //未满的一级加入二级列表 609 | currentBuffer_ = std::move(newBuffer1); //一级当前分配空间 610 | buffersToWrite.swap(buffers_); //交换,快速释放对一级的占用 611 | if (!nextBuffer_) 612 | { 613 | nextBuffer_ = std::move(newBuffer2); 614 | } 615 | } 616 | 617 | assert(!buffersToWrite.empty()); 618 | 619 | //如果消息堆积,只保留前2块缓冲区 620 | if (buffersToWrite.size() > 25) 621 | { 622 | char buf[256]; 623 | snprintf(buf, sizeof buf, "Dropped log messages at %s, %zd larger buffers\n", 624 | Timestamp::now().toFormattedString().c_str(), 625 | buffersToWrite.size() - 2); 626 | fputs(buf, stderr); 627 | output.append(buf, static_cast(strlen(buf))); 628 | buffersToWrite.erase(buffersToWrite.begin() + 2, buffersToWrite.end()); //丢弃多余的日志,只保留前2个 629 | } 630 | 631 | for (const auto &buffer : buffersToWrite) 632 | { 633 | output.append(buffer->data(), buffer->length());//写日志 634 | } 635 | 636 | if (buffersToWrite.size() > 2) 637 | { 638 | //丢弃无用的缓冲区 639 | buffersToWrite.resize(2); //buffersToWrite的内容已经完成了写入,空闲了。只保留二级缓冲区列表的2个缓冲区,表示newbuffer1,newbuffer2 640 | } 641 | 642 | //为newBuffer1,newBuffer2分配空间 643 | if (!newBuffer1) 644 | { 645 | assert(!buffersToWrite.empty()); 646 | newBuffer1 = std::move(buffersToWrite.back()); 647 | buffersToWrite.pop_back(); 648 | newBuffer1->reset(); 649 | } 650 | //newBuffer2可能分配给了一级缓冲区的预备 651 | if (!newBuffer2) 652 | { 653 | assert(!buffersToWrite.empty()); 654 | newBuffer2 = std::move(buffersToWrite.back()); 655 | buffersToWrite.pop_back(); 656 | newBuffer2->reset(); 657 | } 658 | 659 | buffersToWrite.clear(); 660 | output.flush(); 661 | } 662 | } 663 | -------------------------------------------------------------------------------- /src/lkpServer.h: -------------------------------------------------------------------------------- 1 | #ifndef LKP_SERVER 2 | #define LKP_SERVER 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "muduo/base/Logging.h" 30 | #include "muduo/base/Mutex.h" 31 | #include "muduo/base/ThreadLocalSingleton.h" 32 | #include "muduo/net/EventLoop.h" 33 | #include "muduo/net/TcpServer.h" 34 | #include "muduo/base/CurrentThread.h" 35 | #include "muduo/net/EventLoopThread.h" 36 | #include "muduo/net/TcpClient.h" 37 | #include "muduo/base/Timestamp.h" 38 | #include "muduo/net/Callbacks.h" 39 | #include "muduo/net/Channel.h" 40 | #include "muduo/net/TimerId.h" 41 | #include "muduo/base/BlockingQueue.h" 42 | #include "muduo/base/BoundedBlockingQueue.h" 43 | #include "muduo/base/CountDownLatch.h" 44 | #include 45 | #include "muduo/base/Thread.h" 46 | #include "muduo/base/LogStream.h" 47 | #include "muduo/base/LogFile.h" 48 | #include 49 | 50 | 51 | #include "lib/lkpProto.pb.h" 52 | #include "lib/lkpCodec.h" 53 | #include "lib/lkpDispatcher.h" 54 | #include "lkpHelper.h" 55 | 56 | 57 | using namespace muduo; 58 | using namespace muduo::net; 59 | 60 | 61 | typedef std::shared_ptr PushACKPtr; 62 | typedef std::shared_ptr CommandACKPtr; 63 | typedef std::shared_ptr RecvFilePtr; 64 | typedef std::shared_ptr RecvCommandPtr; 65 | typedef std::shared_ptr HeartBeatPtr; 66 | typedef boost::shared_ptr FilePtr; 67 | 68 | class lkpServer : noncopyable 69 | { 70 | public: 71 | lkpServer(EventLoop *loop, 72 | const InetAddress &listenAddr, 73 | const lkpConfig &MyConfig, 74 | off_t rollSize); 75 | 76 | ~lkpServer() 77 | { 78 | if (running_) 79 | { 80 | running_ = false;//不允许后端继续写日志 81 | cond_.notify();//避免后端卡在条件变量处 82 | thread_.join();//回收后端线程 83 | } 84 | } 85 | 86 | //启动服务器 87 | void start(); 88 | 89 | //设置线程数量 90 | void setThreadNum(int num); 91 | 92 | void append(const char *logline, int len); //前端向一级缓冲区添加数据,操作一级缓冲区之前必须加锁 93 | 94 | private: 95 | 96 | //向客户端发送文件 97 | void pushToClient(const RecvCommandPtr &message); 98 | //向一个确定的客户端连接发送数据 99 | void SendToClient(const google::protobuf::Message& message, const TcpConnectionPtr& conn); 100 | //向命令行客户端发送数据 101 | void SendToCmdClient(const google::protobuf::Message& message); 102 | //向client pool中的所有客户端广播消息 103 | void BroadToClients(lkpMessage::Command message); 104 | 105 | // IPC 相关函数 106 | // 建立进程间的连接 107 | void onAcceptIPC(); 108 | //接收CMDclient的数据 109 | void onCMDmessage(int CMDcfd); 110 | 111 | 112 | void onTimer(); 113 | 114 | //客户端请求建立新的连接 115 | void onConnection(const TcpConnectionPtr &conn); 116 | 117 | //取消使用。 118 | void onMessage(const TcpConnectionPtr &conn, Buffer *buf, Timestamp time); 119 | 120 | void onWriteComplete(const TcpConnectionPtr &conn); 121 | 122 | //收到命令的回调函数,server转发给client, client执行 123 | void onCommandMsg(const TcpConnectionPtr &conn, const RecvCommandPtr& message, Timestamp time); 124 | //收到pushack的回调函数,应该开始发testecase的文件内容 125 | void onPushACK(const TcpConnectionPtr &conn, const PushACKPtr& message, Timestamp time); 126 | //收到command ACK的回调函数,应该使统计数量++ 127 | void onCommandACK(const TcpConnectionPtr &conn, const CommandACKPtr& message, Timestamp time); 128 | //收到file message的回调函数,server收到的应该是result, client收到的应该是testcase 129 | void onFileMsg(const TcpConnectionPtr &conn, const RecvFilePtr& message, Timestamp time); 130 | //收到心跳包的回调函数 131 | void onHeartBeat(const TcpConnectionPtr &conn, const HeartBeatPtr& message, Timestamp time); 132 | //收到未知数据包的回调函数 133 | void onUnknownMsg(const TcpConnectionPtr &conn, const MessagePtr& message, Timestamp time); 134 | 135 | 136 | void dumpConnectionBuckets() const; 137 | 138 | 139 | void threadFunc();//后端操作二级,向CMDcleint发送 140 | 141 | TcpServer server_; 142 | EventLoop *loop_; 143 | 144 | int numThreads_; 145 | 146 | lkpDispatcher dispatcher_; 147 | lkpCodec codec_; 148 | 149 | TcpConnectionPtr CmdConnection_; 150 | bool hasCmdConnected_ = false; 151 | 152 | 153 | 154 | //client pool nodeID -- cfd 155 | class lkpClientPool clientPool_; 156 | 157 | //conn -- fp 158 | std::unordered_mapfpMap; 159 | int kBufSize_; 160 | 161 | //result conn -- filename filesize 162 | std::unordered_mapfileNameMap_; 163 | std::unordered_mapfileSizeMap_; 164 | std::unordered_mapoutputfpMap_; 165 | 166 | //client_ok_num 167 | int clientNum_; 168 | int clientOKNum_; 169 | int ackTimes_; 170 | 171 | //time wheeling使用 172 | typedef std::weak_ptrWeakTcpConnectionPtr; 173 | //Entry的引用计数变成0时,关闭Entry对应客户端的连接 174 | struct Entry: public muduo::copyable 175 | { 176 | //记录Entry对应的客户端连接,传入的是客户端连接的弱引用 177 | Entry(const WeakTcpConnectionPtr &weakConn, lkpServer*server,int nodeID) 178 | : weakConn_(weakConn),Entry_server(server),Entry_nodeID(nodeID) 179 | { 180 | // printf("Entry,nodeID:%d\n",Entry_nodeID); 181 | } 182 | //计数是0时,关闭客户端的连接 183 | ~Entry(){ 184 | // printf("~Entry,nodeID:%d\n",Entry_nodeID); 185 | muduo::net::TcpConnectionPtr conn = weakConn_.lock();//weak_ptr没有*功能,只能这样取,得到的是share_ptr类型的指针 186 | if(conn){ 187 | conn->shutdown();//引用计数0,关闭连接 188 | } 189 | else{ 190 | return; 191 | } 192 | 193 | //关闭客户端连接时,产生空闲nodeID 194 | Entry_server->clientPool_.del(Entry_nodeID); 195 | } 196 | WeakTcpConnectionPtr weakConn_;//弱指针,不会导致计数增加 197 | lkpServer* Entry_server;//存放Entry对应的CMDserver 198 | int Entry_nodeID; 199 | }; 200 | 201 | typedef std::shared_ptr EntryPtr; 202 | typedef std::weak_ptr WeakEntryPtr; 203 | typedef std::unordered_set Bucket;//环形队列的元素 204 | typedef boost::circular_buffer WeakConnectionList;//环形队列 205 | WeakConnectionList connectionBuckets_;//环形队列 206 | 207 | 208 | //高速缓冲区使用 209 | // void threadFunc(); //后端线程,把二级缓冲区写入日志文件 210 | typedef muduo::detail::FixedBuffer Buffer_log;//缓冲区 211 | typedef std::vector> BufferVector;//缓冲列表 212 | typedef BufferVector::value_type BufferPtr; 213 | 214 | const int flushInterval_; //超时时间,到达时间后没满的缓冲区也必须把数据写入二级缓冲区 215 | std::atomic running_;//保证服务器停止时,后端线程一定停止 216 | const string basename_;//输出文件的名称 217 | const off_t rollSize_;//日志长度,过长需要roll 218 | muduo::Thread thread_;//后端线程 219 | muduo::CountDownLatch latch_; //确保后端线程启动之后,服务器才开始运行前端线程 220 | muduo::MutexLock mutex_; 221 | muduo::Condition cond_ GUARDED_BY(mutex_);//条件变量,触发后端线程开始写日志 222 | BufferPtr currentBuffer_ GUARDED_BY(mutex_); //一级当前缓冲区 223 | BufferPtr nextBuffer_ GUARDED_BY(mutex_); //一级预备缓冲区 224 | BufferVector buffers_ GUARDED_BY(mutex_); //二级缓冲区列表,后端和buffersToWrite交换后,操作buffersToWrite写日志,避免长时间占用buffers_阻塞前端 225 | }; 226 | extern lkpServer *g_asyncLog_server; 227 | void asyncOutput_server(const char *msg, int len); 228 | extern int childNum; 229 | #endif 230 | -------------------------------------------------------------------------------- /src/lkp_extent.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "lkpServer.h" 6 | #include "lkpClient.h" 7 | #include "lkpHelper.h" 8 | 9 | 10 | string ROOT_DIR; 11 | bool isServer = false; 12 | int childNum = 0; 13 | 14 | //回收子进程 15 | void handleChildExit(int sig){ 16 | int childStatus; 17 | childNum = std::max(childNum - 1,0); 18 | //一旦被唤醒,就持续尝试回收子进程 19 | printf("lkp-ctl: child process exit here\n"); 20 | while(waitpid(-1,&childStatus,WNOHANG) != -1); 21 | } 22 | 23 | int main(int argc, char *argv[]) 24 | { 25 | 26 | if(argc!=3){ 27 | std::cout << "lkp-ctl service start failed: Wrong argv" << std::endl; 28 | return 1; 29 | } 30 | 31 | //需要获得lkp-extent的root direction 32 | ROOT_DIR = string(argv[1]); 33 | string ServerNClient = string(argv[2]); 34 | 35 | std::map configMap; 36 | lkpConfig MyConfig; 37 | 38 | //配置初始化 39 | lkpConfigInit(configMap, MyConfig, ROOT_DIR); 40 | 41 | if(ServerNClient.compare("server")==0) 42 | isServer = true; 43 | else if(ServerNClient.compare("client")==0) 44 | isServer = false; 45 | else{ 46 | std::cout << "lkp-ctl service start failed: Not a valid input (server or client)" << std::endl; 47 | return 0; 48 | } 49 | 50 | if(daemon(1,1) < 0){ 51 | perror("lkp-extent error: cannot run as daemon!" ); 52 | exit(EXIT_FAILURE); 53 | } 54 | 55 | 56 | //注册子进程回收函数,由主线程负责 57 | sigset_t set; 58 | sigemptyset(&set); 59 | sigaddset(&set,SIGCHLD); 60 | sigprocmask(SIG_BLOCK,&set,NULL); 61 | struct sigaction act, oldact; 62 | act.sa_handler = handleChildExit; 63 | sigemptyset(&act.sa_mask); 64 | act.sa_flags = 0; 65 | sigaction(SIGCHLD, &act, &oldact); 66 | sigprocmask(SIG_UNBLOCK,&set,NULL); 67 | 68 | 69 | //创建Server类或client类,开启事件循环并守护运行 70 | 71 | if(isServer){ 72 | EventLoop loop; 73 | InetAddress serverAddr(MyConfig.ServerListenPort); 74 | 75 | off_t kRollSize = 500 * 1000 * 1000; 76 | lkpServer Server(&loop, serverAddr, MyConfig, kRollSize); 77 | 78 | g_asyncLog_server = &Server; 79 | 80 | muduo::Logger::setOutput(asyncOutput_server); //LOG_INFO调用asyncOutput_client 81 | 82 | Server.start(); 83 | 84 | loop.loop(); 85 | } 86 | else{ 87 | EventLoop loop; 88 | InetAddress serverAddr(MyConfig.ServerAddress, MyConfig.ServerPort); 89 | 90 | lkpClient client(&loop, serverAddr, MyConfig.HeartBeatTime); 91 | 92 | g_asyncLog_client = &client; 93 | 94 | muduo::Logger::setOutput(asyncOutput_client); //LOG_INFO调用asyncOutput_client 95 | 96 | client.connect(); 97 | 98 | loop.loop(); 99 | } 100 | return 0; 101 | } -------------------------------------------------------------------------------- /src/makefile: -------------------------------------------------------------------------------- 1 | ALL:lkp_extent lkp_extent_CLI 2 | 3 | lkp_extent:lkp_extent.cc lkpServer.cc lkpServer.h lkpClient.cc lkpClient.h lkpHelper.cc lkpHelper.h lib/lkpCodec.cc lib/lkpCodec.h lib/lkpDispatcher.h lib/lkpProto.pb.cc lib/lkpProto.pb.h 4 | -g++ $^ -o ./build/$@ -lmuduo_net -lmuduo_base -lpthread -lprotobuf -lz -std=c++11 -g 5 | 6 | lkp_extent_CLI:lkpCommand.cc lkpHelper.cc lkpHelper.h lib/lkpCodec.cc lib/lkpCodec.h lib/lkpDispatcher.h lib/lkpProto.pb.cc lib/lkpProto.pb.h 7 | -g++ $^ -o ./build/$@ -lmuduo_net -lmuduo_base -lpthread -lprotobuf -lz -std=c++11 -g 8 | 9 | clean: 10 | rm ./build/lkp_extent 11 | rm ./build/lkp_extent_CLI -------------------------------------------------------------------------------- /testcases/test.yaml: -------------------------------------------------------------------------------- 1 | # i am just a test file, don't use me 2 | # i am just a test file, don't use me 3 | # i am just a test file, don't use me 4 | # i am just a test file, don't use me 5 | # i am just a test file, don't use me 6 | # i am just a test file, don't use me 7 | # i am just a test file, don't use me 8 | # i am just a test file, don't use me 9 | # i am just a test file, don't use me 10 | # i am just a test file, don't use me 11 | # i am just a test file, don't use me 12 | # i am just a test file, don't use me 13 | # i am just a test file, don't use me 14 | # i am just a test file, don't use me 15 | # i am just a test file, don't use me 16 | # i am just a test file, don't use me 17 | # i am just a test file, don't use me 18 | # i am just a test file, don't use me 19 | # i am just a test file, don't use me 20 | # i am just a test file, don't use me 21 | # i am just a test file, don't use me 22 | # i am just a test file, don't use me 23 | # i am just a test file, don't use me 24 | # i am just a test file, don't use me 25 | # i am just a test file, don't use me 26 | # i am just a test file, don't use me 27 | # i am just a test file, don't use me 28 | # i am just a test file, don't use me 29 | # i am just a test file, don't use me 30 | # i am just a test file, don't use me 31 | # i am just a test file, don't use me 32 | # i am just a test file, don't use me 33 | # i am just a test file, don't use me 34 | # i am just a test file, don't use me 35 | # i am just a test file, don't use me 36 | # i am just a test file, don't use me 37 | # i am just a test file, don't use me 38 | # i am just a test file, don't use me 39 | # i am just a test file, don't use me 40 | # i am just a test file, don't use me 41 | # i am just a test file, don't use me 42 | # i am just a test file, don't use me 43 | # i am just a test file, don't use me 44 | # i am just a test file, don't use me 45 | # i am just a test file, don't use me 46 | # i am just a test file, don't use me 47 | # i am just a test file, don't use me 48 | # i am just a test file, don't use me 49 | # i am just a test file, don't use me 50 | # i am just a test file, don't use me 51 | # i am just a test file, don't use me 52 | # i am just a test file, don't use me 53 | # i am just a test file, don't use me 54 | # i am just a test file, don't use me 55 | # i am just a test file, don't use me 56 | # i am just a test file, don't use me 57 | # i am just a test file, don't use me 58 | # i am just a test file, don't use me 59 | # i am just a test file, don't use me 60 | # i am just a test file, don't use me 61 | # i am just a test file, don't use me 62 | # i am just a test file, don't use me 63 | # i am just a test file, don't use me 64 | # i am just a test file, don't use me 65 | # i am just a test file, don't use me 66 | # i am just a test file, don't use me 67 | # i am just a test file, don't use me 68 | # i am just a test file, don't use me 69 | # i am just a test file, don't use me 70 | # i am just a test file, don't use me 71 | # i am just a test file, don't use me 72 | # i am just a test file, don't use me 73 | # i am just a test file, don't use me 74 | # i am just a test file, don't use me 75 | # i am just a test file, don't use me 76 | # i am just a test file, don't use me 77 | # i am just a test file, don't use me 78 | # i am just a test file, don't use me 79 | # i am just a test file, don't use me 80 | # i am just a test file, don't use me 81 | # i am just a test file, don't use me 82 | # i am just a test file, don't use me 83 | # i am just a test file, don't use me 84 | # i am just a test file, don't use me 85 | # i am just a test file, don't use me 86 | # i am just a test file, don't use me 87 | # i am just a test file, don't use me 88 | # i am just a test file, don't use me 89 | # i am just a test file, don't use me 90 | # i am just a test file, don't use me 91 | # i am just a test file, don't use me 92 | # i am just a test file, don't use me 93 | # i am just a test file, don't use me 94 | # i am just a test file, don't use me 95 | # i am just a test file, don't use me 96 | # i am just a test file, don't use me 97 | # i am just a test file, don't use me 98 | # i am just a test file, don't use me 99 | # i am just a test file, don't use me 100 | # i am just a test file, don't use me 101 | # i am just a test file, don't use me 102 | # i am just a test file, don't use me 103 | # i am just a test file, don't use me 104 | # i am just a test file, don't use me 105 | # i am just a test file, don't use me 106 | # i am just a test file, don't use me 107 | # i am just a test file, don't use me 108 | # i am just a test file, don't use me 109 | # i am just a test file, don't use me 110 | # i am just a test file, don't use me 111 | # i am just a test file, don't use me 112 | # i am just a test file, don't use me 113 | # i am just a test file, don't use me 114 | # i am just a test file, don't use me 115 | # i am just a test file, don't use me 116 | # i am just a test file, don't use me 117 | # i am just a test file, don't use me 118 | # i am just a test file, don't use me 119 | # i am just a test file, don't use me 120 | # i am just a test file, don't use me 121 | # i am just a test file, don't use me 122 | # i am just a test file, don't use me 123 | # i am just a test file, don't use me 124 | # i am just a test file, don't use me 125 | # i am just a test file, don't use me 126 | # i am just a test file, don't use me 127 | # i am just a test file, don't use me 128 | # i am just a test file, don't use me 129 | # i am just a test file, don't use me 130 | # i am just a test file, don't use me 131 | # i am just a test file, don't use me 132 | # i am just a test file, don't use me 133 | # i am just a test file, don't use me 134 | # i am just a test file, don't use me 135 | # i am just a test file, don't use me 136 | # i am just a test file, don't use me 137 | # i am just a test file, don't use me 138 | # i am just a test file, don't use me 139 | # i am just a test file, don't use me 140 | # i am just a test file, don't use me 141 | # i am just a test file, don't use me 142 | # i am just a test file, don't use me 143 | # i am just a test file, don't use me 144 | # i am just a test file, don't use me 145 | # i am just a test file, don't use me 146 | # i am just a test file, don't use me 147 | # i am just a test file, don't use me 148 | # i am just a test file, don't use me 149 | # i am just a test file, don't use me 150 | # i am just a test file, don't use me 151 | # i am just a test file, don't use me 152 | # i am just a test file, don't use me 153 | # i am just a test file, don't use me 154 | # i am just a test file, don't use me 155 | # i am just a test file, don't use me 156 | # i am just a test file, don't use me 157 | # i am just a test file, don't use me 158 | # i am just a test file, don't use me 159 | # i am just a test file, don't use me 160 | # i am just a test file, don't use me 161 | # i am just a test file, don't use me 162 | # i am just a test file, don't use me 163 | # i am just a test file, don't use me 164 | # i am just a test file, don't use me 165 | # i am just a test file, don't use me 166 | # i am just a test file, don't use me 167 | # i am just a test file, don't use me 168 | # i am just a test file, don't use me 169 | # i am just a test file, don't use me 170 | # i am just a test file, don't use me 171 | # i am just a test file, don't use me 172 | # i am just a test file, don't use me 173 | # i am just a test file, don't use me 174 | # i am just a test file, don't use me 175 | # i am just a test file, don't use me 176 | # i am just a test file, don't use me 177 | # i am just a test file, don't use me 178 | # i am just a test file, don't use me 179 | # i am just a test file, don't use me 180 | # i am just a test file, don't use me 181 | # i am just a test file, don't use me 182 | # i am just a test file, don't use me 183 | # i am just a test file, don't use me 184 | # i am just a test file, don't use me 185 | # i am just a test file, don't use me 186 | # i am just a test file, don't use me 187 | # i am just a test file, don't use me 188 | # i am just a test file, don't use me 189 | # i am just a test file, don't use me 190 | # i am just a test file, don't use me 191 | # i am just a test file, don't use me 192 | # i am just a test file, don't use me 193 | # i am just a test file, don't use me 194 | # i am just a test file, don't use me 195 | # i am just a test file, don't use me 196 | # i am just a test file, don't use me 197 | # i am just a test file, don't use me 198 | # i am just a test file, don't use me 199 | # i am just a test file, don't use me 200 | # i am just a test file, don't use me 201 | # i am just a test file, don't use me 202 | # i am just a test file, don't use me 203 | # i am just a test file, don't use me 204 | # i am just a test file, don't use me 205 | # i am just a test file, don't use me 206 | # i am just a test file, don't use me 207 | # i am just a test file, don't use me 208 | # i am just a test file, don't use me 209 | # i am just a test file, don't use me 210 | # i am just a test file, don't use me 211 | # i am just a test file, don't use me 212 | # i am just a test file, don't use me 213 | # i am just a test file, don't use me 214 | # i am just a test file, don't use me 215 | # i am just a test file, don't use me 216 | # i am just a test file, don't use me 217 | # i am just a test file, don't use me 218 | # i am just a test file, don't use me 219 | # i am just a test file, don't use me 220 | # i am just a test file, don't use me 221 | # i am just a test file, don't use me 222 | # i am just a test file, don't use me 223 | # i am just a test file, don't use me 224 | # i am just a test file, don't use me 225 | # i am just a test file, don't use me 226 | # i am just a test file, don't use me 227 | # i am just a test file, don't use me 228 | # i am just a test file, don't use me 229 | # i am just a test file, don't use me 230 | # i am just a test file, don't use me 231 | # i am just a test file, don't use me 232 | # i am just a test file, don't use me 233 | # i am just a test file, don't use me 234 | # i am just a test file, don't use me 235 | # i am just a test file, don't use me 236 | # i am just a test file, don't use me 237 | # i am just a test file, don't use me 238 | # i am just a test file, don't use me 239 | # i am just a test file, don't use me 240 | # i am just a test file, don't use me 241 | # i am just a test file, don't use me 242 | # i am just a test file, don't use me 243 | # i am just a test file, don't use me 244 | # i am just a test file, don't use me 245 | # i am just a test file, don't use me 246 | # i am just a test file, don't use me 247 | # i am just a test file, don't use me 248 | # i am just a test file, don't use me 249 | # i am just a test file, don't use me 250 | # i am just a test file, don't use me 251 | # i am just a test file, don't use me 252 | # i am just a test file, don't use me 253 | # i am just a test file, don't use me 254 | # i am just a test file, don't use me 255 | # i am just a test file, don't use me 256 | # i am just a test file, don't use me 257 | # i am just a test file, don't use me 258 | # i am just a test file, don't use me 259 | # i am just a test file, don't use me 260 | # i am just a test file, don't use me 261 | --------------------------------------------------------------------------------