Repository: Tencent/libwxfreq Branch: master Commit: 8281a2d53058 Files: 64 Total size: 158.2 KB Directory structure: gitextract_qkvgk5na/ ├── AUTHORS ├── LICENSE.TXT ├── Makefile ├── README.md ├── TODO ├── freq/ │ ├── appid.h │ ├── appid_manager.cpp │ ├── appid_manager.h │ ├── appname.h │ ├── appname_manager.cpp │ ├── appname_manager.h │ ├── expression.h │ ├── freq_item.h │ ├── freq_manager.cpp │ ├── freq_manager.h │ ├── freqlib.cpp │ ├── libwxfreq.h │ ├── plain_expression.cpp │ ├── plain_expression.h │ ├── rule_item.h │ ├── rule_manager.cpp │ └── rule_manager.h ├── main.cpp ├── net/ │ ├── acceptor.cpp │ ├── acceptor.h │ ├── iothread.cpp │ ├── iothread.h │ ├── server.cpp │ ├── server.h │ ├── server_conf.cpp │ ├── server_conf.h │ ├── server_inner.cpp │ ├── server_inner.h │ ├── util.cpp │ ├── util.h │ ├── worker.cpp │ ├── worker.h │ ├── workerpool.cpp │ └── workerpool.h ├── server.conf ├── test/ │ ├── demo.cpp │ ├── performance_test.cpp │ ├── test.conf │ └── tools.cpp └── util/ ├── config.cpp ├── config.h ├── config_hash.cpp ├── config_hash.h ├── freq_stat.h ├── log.cpp ├── log.h ├── map_freq_stat.cpp ├── map_freq_stat.h ├── multi_hash_base.h ├── multi_hash_table.cpp ├── multi_hash_table.h ├── options.cpp ├── options.h ├── reload.cpp ├── reload.h ├── shm_freq_stat.cpp ├── shm_freq_stat.h ├── slice.cpp └── slice.h ================================================ FILE CONTENTS ================================================ ================================================ FILE: AUTHORS ================================================ # Names should be added to this file like so: # Name or Organization Tencent Inc. 2016 # Initial version authors: Jack Liang Robin Tang Arthur Zou # Partial list of contributors: ================================================ FILE: LICENSE.TXT ================================================ Tencent is pleased to support the open source community by making libwxfreq available. Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. If you have downloaded a copy of the libwxfreq binary from Tencent, please note that the libwxfreq binary is licensed under the BSD 3-Clause License. If you have downloaded a copy of the libwxfreq source code from Tencent, please note that libwxfreq source code is licensed under the BSD 3-Clause License, except for the third-party components listed below which are subject to different license terms. Your integration of libwxfreq into your own projects may require compliance with the BSD 3-Clause License, as well as the other licenses applicable to the third-party components included within libwxfreq. A copy of the BSD 3-Clause License is included in this file. Other dependencies and licenses: ===================================================================================== Open Source Software Licensed Under the BSD 3-Clause License: The below software in this distribution may have been modified by THL A29 Limited (Tencent Modifications). All Tencent Modifications are Copyright (C) 2017 THL A29 Limited. ------------------------------------------------------------------------------------- 1. LevelDB 1.20 Copyright (c) 2011 The LevelDB Authors. All rights reserved Terms of the BSD 3-Clause License: -------------------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of [copyright holder] nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: Makefile ================================================ NAME = libwxfreq SERVERNAME = WxFreq LIBNAME = libwxfreq.a OUTPUTDIR = ./output INCLUDE = $(OUTPUTDIR)/include/$(NAME) LIB64 = $(OUTPUTDIR)/lib64 LIBINSTALLDIR = /usr/local/lib64/ HEADERINSTALLDIR = /usr/local/include/ DIRLIBEVENT=/data1/mm64/arthurzou/archive CC = g++ LDFLAGS = -lwxfreq -pthread -L$(LIB64) -I $(dir $(INCLUDE)) CPPFLAGS = $(CFLAGS) CPPFLAGS += -g -O2 -Wall -std=c++11 INC = -I ./util -I ./freq -I ./net --std=c++11 CPPFILE += $(wildcard freq/*.cpp) CPPFILE += $(wildcard util/*.cpp) OBJ = $(patsubst %.cpp, %.o, $(CPPFILE)) DFILE = $(patsubst %.o, %.d, $(OBJ)) NETCPPFILE += main.cpp NETCPPFILE += $(wildcard net/*.cpp) NETOBJ = $(patsubst %.cpp, %.o, $(NETCPPFILE)) NETDFILE = $(patsubst %.o, %.d, $(NETOBJ)) .PHONY : all clean test $(SERVERNAME) : $(OBJ) $(NETOBJ) main.o @rm -rf $(DFILE) @rm -rf $(NETDFILE) $(CC) $(CPPFLAGS) $^ -o $@ -pthread -levent -lrt -static -L $(DIRLIBEVENT) $(LIBNAME) : $(OBJ) @rm -rf $(OUTPUTDIR) @rm -rf $(DFILE) @mkdir -p $(LIB64) @mkdir -p $(INCLUDE) ar scr $@ $(OBJ) mv $@ $(LIB64) cp freq/libwxfreq.h $(INCLUDE) @$(CC) -MM freq/libwxfreq.h $(INC) | \ tr " " "\n" | grep ".h" | xargs -I{} cp {} $(INCLUDE) @find $(INCLUDE) -name "*.h" | xargs sed -i 's;#include ";#include "$(NAME)/;' %: test/%.cpp $(LIBNAME) $(CC) $(CPPFLAGS) $< -o $@.out $(LDFLAGS) -include $(DFILE) -include $(NETDFILE) %.d: %.cpp @$(CC) $(INC) -MT $*.o -MM $< > $@ && \ echo -e '\t$$(CC) $$(CPPFLAGS) $(INC) -c $$< -o $$@' >> $@ clean: @echo -n "clean workspace ..." @rm -rf $(OUTPUTDIR) $(OBJ) $(NETOBJ) $(NETDFILE) $(DFILE) *.out $(SERVERNAME) @echo -e "\t\t\033[31m[done]\033[0m" install: $(LIBNAME) cp -r $(INCLUDE) $(HEADERINSTALLDIR) cp -r $(LIB64)/$(LIBNAME) $(LIBINSTALLDIR) ================================================ FILE: README.md ================================================ # libwxfreq ## 编译 1. 编译lib: make libwxfreq.a 2. 编译server: 依赖libevent库,所以要修改DIRLIBEVENT变量为libevent.a所在目录,并确定libevent相关头文件在头文件搜索路径中, 运行make ## 安装 1. 修改makefile文件中的HEADERINSTALLDIR和LIBINSTALLDIR变量 2. make install ## 单元测试 1. 以测试文件为目标make. 例如: make demo ## 简介 libwxfreq是一个高性能频率限制库。通过简洁的几个接口便可以实现通用的可配置的频率 限制功能。配合其他网络框架,便可以实现一个通用的高性能频率控制服务。 ## 特点: 1. 高度可配置。统计时长可配,规则可配。 2. 支持任意key类型。 ## 配置文件 1. 格式 appid的元信息,指明apppid的统计时长。默认第一个统计时长是60s,第二个统计时 时长是3600s, 第三个是86400s。可以手动修改任何一个统计时长为[0, 86400] [appid] 5 = 30, 60, 90 // appid为5的统计时长分别是30s 60s 90s 25 = 10, 60 // appid为25的统计时长分别是10s 60s 86400s 频率规则, 用于说明某个appid的阈值, 拦截等级等 [match_rule_name] // 规则名字,用户指明中了哪条规则 match_appid = 5 // 匹配的appid block_level = 1 // 拦截等级, 大于0 rule_type = user // 规则对应的key类型 item = min_interval >= 4 // 具体的阈值表达式, 支持大于和等于 ``` min_interval 表示第一个统计时长的统计值, mid_interval 表示第二个统计时长的统计值, max_interval 表示第三个统计时长的统计值. ``` 2. 例子 ``` [appid] 100 = 30, 60, 90 [rule1] match_appid = 100 item = min_interval >= 10 block_level = 1 rule_type = user [rule2] match_appid = 100 item = mid_interval >= 15 block_level = 1 rule_type = user [rule3] match_appid = 100 item = max_interval >= 20 block_level = 1 rule_type = user [rule4] match_appid = 100 item = min_interval >= 100 block_level = 1 rule_type = ip [rule5] match_appid = 100 item = mid_interval >= 150 block_level = 1 rule_type = ip [rule6] match_appid = 100 item = max_interval >= 200 block_level = 1 rule_type = ip ``` ## API接口 设置规则配置文件 > void SetRuleConfFile(const char *filename); 注册一个新的统计维度。type_name 指明类型名称, zero_init标志初始化时是否需要 初始化为0, key 是共享内存key,item_cnt 表示共享内存大小,最大能统计的item个 数。 > int RegisterNewShmStat(const char* type_name, bool zero_init, key_t key, > unsigned int item_cnt); 系统初始化 > bool InitFreq(); 上报一次频率到系统中。type_name 是统计类型,说明key的含义。 key是主体标识, appid 是业务标识, cnt 表示本次需要累加的次数。 例如,统计QQ号为3402393864的 用户在appid为5的服务上的频率,使用ReportAndCheck("user", 3402393864, 5, 1); 同样统计ip为202.204.105.8访问appid的5的频率,使用ReportAndCheck( "IP", 3402393864, 5, 1); 因为202.204.105.8的整形表示也是3402393864。type_name指明了 key的含义。 > struct BlockResult ReportAndCheck(const char* type_name, const char *key, > const uint32_t appid, const uint32_t cnt); 只检查当前是否中频率 > struct BlockResult OnlyCheck(const char* type_name, const char *key, > const uint32_t appid); 只上报,不检查 > int OnlyReport(const char* type_name, const char *key, const uint32_t appid, > const uint32_t cnt); 获取频率统计值, cnt为0获取当前统计值,不为零表示先累计再获取 > struct FreqCache GetCache(const char* type_name, const char *key, > const uint32_t appid, const uint32_t cnt = 0); 加白操作,linger_time表示加白有效期 > int AddWhite(const char* type_name, const char *key, const uint32_t appid, > const uint32_t linger_time); 删除白名单 > int DeleteWhite(const char* type_name, const char *key, const uint32_t appid); 手动加拦截 > int AddBlock(const char* type_name, const char *key, const uint32_t appid, > const uint32_t linger_time, const uint32_t block_level); 手动删除拦截 > int DeleteBlock(const char* type_name, const char *key, const uint32_t appid); 设置写日志方法,默认写本地文件/tmp/libwxfreq.log > void SetLogFunc(LogFunction logfunc); 设置重启时恢复白名单/拦截方法,默认从本地文件/tmp/libwxfreq_db.$type_name读取 > void SetLoadFunc(LoadFunc func); 设置白名单/加拦截数据持久化方法。默认写本地文件/tmp/libwxfreq_db.$type_name > void SetDumpFunc(DumpFunc func); ================================================ FILE: TODO ================================================ 1. 表达式支持逻辑运算 ================================================ FILE: freq/appid.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef FREQLIB_FREQ_APPID_H_ #define FREQLIB_FREQ_APPID_H_ #include #include #include namespace libwxfreq { class AppidMeta { public: AppidMeta() : min_interval_(60), mid_interval_(3600), max_interval_(86400) { } inline void set_min_interval(const uint32_t& min_interval) { min_interval_ = min_interval; } inline void set_mid_interval(const uint32_t& mid_interval) { mid_interval_ = mid_interval; } inline void set_max_interval(const uint32_t& max_interval) { max_interval_ = max_interval; } inline uint16_t min_interval() const { return min_interval_; } inline uint16_t mid_interval() const { return mid_interval_; } inline uint16_t max_interval() const { return max_interval_; } inline std::string DebugString() const { char buf[128]; snprintf(buf, sizeof(buf), "min_interval=%d, mid_interval=%d," " max_interval=%d", min_interval_, mid_interval_, max_interval_); return buf; } private: uint16_t min_interval_; uint16_t mid_interval_; uint32_t max_interval_; }; } // namespace libwxfreq #endif // FREQLIB_FREQ_APPID_H_ ================================================ FILE: freq/appid_manager.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include "appid_manager.h" #include #include #include #include #include "config.h" #include "log.h" namespace libwxfreq { static AppidMeta dummymeta; AppidMapVecAppidMeta AppidManager::appid_map_[2]; unsigned char AppidManager::index_ = 0; void AppidManager::UpdateAppidMeta(const Config& config) { int ret = 0; unsigned int appid = 0; std::string interval_value; //60, 3600, 86400 unsigned char new_index = (index_ + 1) % 2; AppidMapVecAppidMeta& tmp_appid = appid_map_[new_index]; tmp_appid.clear(); std::vector keys; config.GetKeysBySection("appid", keys); for (std::vector::iterator it = keys.begin(); it != keys.end(); ++it) { appid = atoi(it->c_str()); ret = config.ReadItem("appid", *it, "", interval_value); if (ret != 0 || appid == 0) { gLog("[%s][%d]: read %s appid %d failed %d\n", __FILE__, __LINE__, it->c_str(), appid, ret); continue; } int32_t min = 0, mid = 0, max = 0; char *save_ptr = NULL; char *p = NULL; char buf[128]; snprintf(buf, sizeof(buf), "%s", interval_value.c_str()); p = strtok_r(buf, ",", &save_ptr); if (p != NULL) { min = atoi(p); if (min > 0 && min <= 86400) { tmp_appid[appid].set_min_interval(min); } } p = strtok_r(NULL, ",", &save_ptr); if (p != NULL) { mid = atoi(p); if (mid > 0 && mid <= 86400) { tmp_appid[appid].set_mid_interval(mid); } } p = strtok_r(NULL, ",", &save_ptr); if (p != NULL) { max = atoi(p); if (max > 0 && max <= 86400) { tmp_appid[appid].set_max_interval(max); } } } index_ = new_index; gLog("[%s][%d]: index = %d\n", __FILE__, __LINE__, index_); for (AppidMapVecAppidMeta::iterator it = appid_map_[index_].begin(); it != appid_map_[index_].end(); ++it) { gLog("[%s][%d]: appid = %u, meta = %s\n", __FILE__, __LINE__, it->first, it->second.DebugString().c_str()); } } const AppidMeta* AppidManager::GetAppidMeta(const uint32_t appid) { AppidMapVecAppidMeta::iterator it = appid_map_[index_].find(appid); if (it == appid_map_[index_].end()) { gLog("[%s][%d]: can't find appid %d meta\n", __FILE__, __LINE__, appid); return NULL; } return &(it->second); } } // idspace libwxfreq ================================================ FILE: freq/appid_manager.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef FREQLIB_FREQ_APPID_MANAGER_H_ #define FREQLIB_FREQ_APPID_MANAGER_H_ #include #include #include #include "appid.h" namespace libwxfreq { class Config; typedef std::map AppidMapVecAppidMeta; class AppidManager { public: static const AppidMeta* GetAppidMeta(const uint32_t appid); static void UpdateAppidMeta(const Config& config); private: static AppidMapVecAppidMeta appid_map_[2]; static uint8_t index_; }; } // namespace libwxfreq #endif // FREQLIB_FREQ_APPID_MANAGER_H_ ================================================ FILE: freq/appname.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef FREQLIB_FREQ_APPNAME_H_ #define FREQLIB_FREQ_APPNAME_H_ #include #include #include namespace libwxfreq { class AppNameMeta { public: AppNameMeta() : appname_(), appid_(0), min_interval_(60), mid_interval_(3600), max_interval_(86400) { } inline void set_min_interval(const uint32_t& min_interval) { min_interval_ = min_interval; } inline void set_mid_interval(const uint32_t& mid_interval) { mid_interval_ = mid_interval; } inline void set_max_interval(const uint32_t& max_interval) { max_interval_ = max_interval; } inline void set_appid(const uint32_t& appid) { appid_ = appid; } inline void set_appname(const std::string& appname) { appname_ = appname; } inline std::string appname() const { return appname_; } inline uint16_t min_interval() const { return min_interval_; } inline uint16_t mid_interval() const { return mid_interval_; } inline uint16_t max_interval() const { return max_interval_; } inline uint32_t appid() const { return appid_; } inline std::string DebugString() const { char buf[128]; snprintf(buf, sizeof(buf), "appname=%s, appid=%d, min_interval=%d, " "mid_interval=%d, max_interval=%d", appname_.c_str(), appid_, min_interval_, mid_interval_, max_interval_); return buf; } private: std::string appname_; uint32_t appid_; uint16_t min_interval_; uint16_t mid_interval_; uint32_t max_interval_; }; } // namespace libwxfreq #endif // FREQLIB_FREQ_APPNAME_H_ ================================================ FILE: freq/appname_manager.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include "appname_manager.h" #include #include #include #include "config.h" #include "log.h" namespace libwxfreq { static AppNameMeta dummymeta; AppanmeMapVecAppnameMeta AppnameManager::appname_map_[2]; unsigned char AppnameManager::index_ = 0; void AppnameManager::UpdateAppNameMeta(const Config& config) { int ret = 0; unsigned int appid = 0, interval = 0; std::string appname, interval_key; unsigned char new_index = (index_ + 1) % 2; AppanmeMapVecAppnameMeta& tmp_appname = appname_map_[new_index]; tmp_appname.clear(); std::vector keys; config.GetKeysBySection("appname", keys); for (std::vector::iterator it = keys.begin(); it != keys.end(); ++it) { appid = 0; std::size_t pos = it->find(":"); if (pos == std::string::npos) { ret = config.ReadItem("appname", *it, 0, appid); if (ret != 0 || appid == 0) { gLog("[%s][%d]: read %s appid %d failed\n", __FILE__, __LINE__, it->c_str(), appid); continue; } tmp_appname[*it].set_appname(*it); tmp_appname[*it].set_appid(appid); } else { appname = it->substr(0, pos); interval_key = it->substr(pos + 1); AppNameMeta& meta = tmp_appname[appname]; ret = config.ReadItem("appname", *it, 0, interval); if (ret != 0) { gLog("[%s][%d]: read %s %s failed\n", __FILE__, __LINE__, appname.c_str(), interval_key.c_str()); continue; } if (interval_key == "min_interval") { meta.set_min_interval(interval); } else if (interval_key == "mid_interval") { meta.set_mid_interval(interval); } else if (interval_key == "max_interval") { meta.set_max_interval(interval); } } } index_ = new_index; gLog("[%s][%d]: index = %d\n", __FILE__, __LINE__, index_); for (AppanmeMapVecAppnameMeta::iterator it = appname_map_[index_].begin(); it != appname_map_[index_].end(); ++it) { gLog("[%s][%d]: appname = %s, meta = %s\n", __FILE__, __LINE__, it->first.c_str(), it->second.DebugString().c_str()); } } const AppNameMeta* AppnameManager::GetAppNameMeta(const std::string& appname) { AppanmeMapVecAppnameMeta::iterator it = appname_map_[index_].find(appname); if (it == appname_map_[index_].end()) { gLog("[%s][%d]: can't find appname %s meta\n", __FILE__, __LINE__, appname.c_str()); return NULL; } return &(it->second); } } // namespace libwxfreq ================================================ FILE: freq/appname_manager.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef FREQLIB_FREQ_APPNAME_MANAGER_H_ #define FREQLIB_FREQ_APPNAME_MANAGER_H_ #include #include #include #include "appname.h" namespace libwxfreq { class Config; typedef std::map AppanmeMapVecAppnameMeta; class AppnameManager { public: static const AppNameMeta* GetAppNameMeta(const std::string& appname); static void UpdateAppNameMeta(const Config& config); private: static AppanmeMapVecAppnameMeta appname_map_[2]; static uint8_t index_; }; } // namespace libwxfreq #endif // FREQLIB_FREQ_APPNAME_MANAGER_H_ ================================================ FILE: freq/expression.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef FREQLIB_FREQ_EXPRESSION_H_ #define FREQLIB_FREQ_EXPRESSION_H_ #include #include "freq_item.h" namespace libwxfreq { class Expression { public: virtual ~Expression() {} virtual bool ParseItem(const std::string& item) = 0; virtual bool IsMatch(const FreqItem& freqitem) const = 0; virtual std::string DebugString() const = 0; virtual Expression* Clone() const = 0; }; } // namespace libwxfreq #endif // FREQLIB_FREQ_EXPRESSION_H_ ================================================ FILE: freq/freq_item.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef FREQLIB_FREQ_FREQ_ITEM_H_ #define FREQLIB_FREQ_FREQ_ITEM_H_ #include #include #pragma pack(1) namespace libwxfreq { struct FreqKey { char key[32]; uint32_t appid; }; struct FreqItem { unsigned int level1_cnt; unsigned int level2_cnt; unsigned int level3_cnt; }; } // namespace libwxfreq #pragma pack() #endif // FREQLIB_FREQ_FREQ_ITEM_H_ ================================================ FILE: freq/freq_manager.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include "freq_manager.h" #include "freq_item.h" #include "appid.h" #include "freq_stat.h" #include "log.h" #include "appid_manager.h" namespace libwxfreq { TypeName2FreqStatMap FreqManager::type_name_map_; const uint32_t FreqManager::kWhiteFlag = 0xffffffff; const uint32_t FreqManager::kAddBlockFlag = 0xfffffffe; static AppidMeta dummy_appid_meta; inline uint32_t FreqManager::TimeSplit(time_t timestamp, uint32_t scale) { return timestamp/scale; } bool FreqManager::Init(const TypeName2FreqStatMap& type_name_map) { TypeName2FreqStatMap::iterator it = type_name_map_.begin(); while (it != type_name_map_.end()) { delete it->second; it->second = NULL; ++it; } type_name_map_ = type_name_map; it = type_name_map_.begin(); while (it != type_name_map_.end()) { if (it->second->TryReload() == false ) { gLog("[%s][%d]: ERROR type name %s TryReload failed\n", __FILE__, __LINE__, it->first.c_str()); } ++it; } return true; } const FreqItem* FreqManager::CommAdd(FreqStat *freq_stat, const std::string& key, const AppidMeta& appid_meta, const uint32_t appid, const uint32_t cnt) { FreqItem *freq_item = NULL; uint32_t& last_time = freq_stat->GetItem(key, appid, cnt, freq_item); if (freq_item == NULL) { gLog("[%s][%d]: appid %u key %s GetItem empty\n", __FILE__, __LINE__, appid, key.c_str()); return NULL; } if (freq_item->level1_cnt == kWhiteFlag) { gLog("[%s][%d]: appid %u key %s white\n", __FILE__, __LINE__, appid, key.c_str()); return freq_item; } else if (freq_item->level1_cnt == kAddBlockFlag) { gLog("[%s][%d]: appid %u key %s blocked\n", __FILE__, __LINE__, appid, key.c_str()); return freq_item; } time_t current_time = time(NULL); uint32_t current_interval_level3 = TimeSplit(current_time, appid_meta.max_interval()); uint32_t current_interval_level2 = TimeSplit(current_time, appid_meta.mid_interval()); uint32_t current_interval_level1 = TimeSplit(current_time, appid_meta.min_interval()); uint32_t last_interval_level3 = TimeSplit(last_time, appid_meta.max_interval()); uint32_t last_interval_level2 = TimeSplit(last_time, appid_meta.mid_interval()); uint32_t last_interval_level1 = TimeSplit(last_time, appid_meta.min_interval()); if (last_interval_level1 != current_interval_level1) { freq_item->level1_cnt = cnt; } else { __sync_fetch_and_add(&freq_item->level1_cnt, cnt); } if (last_interval_level2 != current_interval_level2) { freq_item->level2_cnt = cnt; } else { __sync_fetch_and_add(&freq_item->level2_cnt, cnt); } if (last_interval_level3 != current_interval_level3) { freq_item->level3_cnt = cnt; } else { __sync_fetch_and_add(&freq_item->level3_cnt, cnt); } last_time = current_time; return freq_item; } const FreqItem* FreqManager::Add(const char* type_name, const std::string& key, const uint32_t appid, const uint32_t cnt) { if (type_name == NULL) { gLog("[%s][%d]: type name empty\n", __FILE__, __LINE__); return NULL; } if (appid == 0) { gLog("[%s][%d]: appid = 0\n", __FILE__, __LINE__); return NULL; } TypeName2FreqStatMap::iterator it = type_name_map_.find(type_name); if (it == type_name_map_.end()) { gLog("[%s][%d]: type name %s not exists\n", __FILE__, __LINE__, type_name); return NULL; } const AppidMeta *meta = AppidManager::GetAppidMeta(appid); if (meta == NULL) { return CommAdd(it->second, key, dummy_appid_meta, appid, cnt); } else { return CommAdd(it->second, key, *meta, appid, cnt); } } bool FreqManager::AddWhite(const char* type_name, const std::string& key, const uint32_t appid, const uint32_t linger_time) { if (type_name == NULL) { gLog("[%s][%d]: type name empty\n", __FILE__, __LINE__); return false; } if (appid == 0) { gLog("[%s][%d]: appid = 0\n", __FILE__, __LINE__); return false; } TypeName2FreqStatMap::iterator it = type_name_map_.find(type_name); if (it == type_name_map_.end()) { gLog("[%s][%d]: type name %s not exists\n", __FILE__, __LINE__, type_name); return false; } FreqStat *freq_stat = it->second; if (freq_stat == NULL) { gLog("[%s][%d]: type name %s freq_stat NULL\n", __FILE__, __LINE__, type_name); return false; } FreqItem *freq_item = NULL; uint32_t& last_time = freq_stat->GetItem(key, appid, 1, freq_item); if (freq_item == NULL) { gLog("[%s][%d]: appid %u key %s GetItem empty\n", __FILE__, __LINE__, appid, key.c_str()); return false; } unsigned int expired_time = time(NULL) + linger_time; freq_item->level1_cnt = kWhiteFlag; last_time = expired_time - 90000; return true; } bool FreqManager::DeleteWhite(const char* type_name, const std::string& key, const uint32_t appid) { if (type_name == NULL) { gLog("[%s][%d]: type name empty\n", __FILE__, __LINE__); return false; } TypeName2FreqStatMap::iterator it = type_name_map_.find(type_name); if (it == type_name_map_.end()) { gLog("[%s][%d]: type name %s not exists\n", __FILE__, __LINE__, type_name); return false; } FreqStat *freq_stat = it->second; if (freq_stat == NULL) { gLog("[%s][%d]: type name %s freq_stat NULL\n", __FILE__, __LINE__, type_name); return false; } FreqItem *freq_item = NULL; uint32_t& last_time = freq_stat->GetItem(key, appid, 0, freq_item); if (freq_item == NULL) { return true; } if (GetWhiteLevel(freq_item) > 0) { last_time = 1; //expired } return true; } bool FreqManager::AddBlock(const char* type_name, const std::string& key, const uint32_t appid, const uint32_t linger_time, const uint32_t block_level) { if (type_name == NULL) { gLog("[%s][%d]: type name empty\n", __FILE__, __LINE__); return false; } TypeName2FreqStatMap::iterator it = type_name_map_.find(type_name); if (it == type_name_map_.end()) { gLog("[%s][%d]: type name %s not exists\n", __FILE__, __LINE__, type_name); return false; } FreqStat *freq_stat = it->second; FreqItem *freq_item = NULL; uint32_t& last_time = freq_stat->GetItem(key, appid, 1, freq_item); if (freq_item == NULL) { gLog("[%s][%d]: appid %d key %s GetItem empty\n", __FILE__, __LINE__, appid, key.c_str()); return false; } if (freq_stat == NULL) { gLog("[%s][%d]: type name %s freq_stat NULL\n", __FILE__, __LINE__, type_name); return false; } if (GetWhiteLevel(freq_item) > 0) { return true; } unsigned int expired_time = time(NULL) + linger_time; freq_item->level1_cnt = kAddBlockFlag; freq_item->level2_cnt = block_level; last_time = expired_time - 90000; return true; } bool FreqManager::DeleteBlock(const char* type_name, const std::string& key, const uint32_t appid) { if (type_name == NULL) { gLog("[%s][%d]: type name empty\n", __FILE__, __LINE__); return false; } TypeName2FreqStatMap::iterator it = type_name_map_.find(type_name); if (it == type_name_map_.end()) { gLog("[%s][%d]: type name %s not exists\n", __FILE__, __LINE__, type_name); return false; } FreqStat *freq_stat = it->second; if (freq_stat == NULL) { gLog("[%s][%d]: type name %s freq_stat NULL\n", __FILE__, __LINE__, type_name); return false; } FreqItem *freq_item = NULL; uint32_t& last_time = freq_stat->GetItem(key, appid, 0, freq_item); if (freq_item == NULL) { return true; } if (GetWhiteLevel(freq_item) > 0) { return true; } last_time = 1; return true; } uint32_t FreqManager::GetWhiteLevel(const FreqItem* item) { return item->level1_cnt == kWhiteFlag ? 1 : 0; } uint32_t FreqManager::GetBlackLevel(const FreqItem* item) { if (item->level1_cnt == kAddBlockFlag) { return item->level2_cnt; } return 0; } } // namespace libwxfreq ================================================ FILE: freq/freq_manager.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef FREQLIB_FREQ_FREQ_MANAGER_H_ #define FREQLIB_FREQ_FREQ_MANAGER_H_ #include #include #include namespace libwxfreq { class FreqStat; class AppidMeta; class FreqItem; typedef std::map TypeName2FreqStatMap; class FreqManager { public: static bool Init(const TypeName2FreqStatMap& type_name_map); static const FreqItem* Add(const char* type_name, const std::string& key, const uint32_t appid, const uint32_t cnt); static bool AddWhite(const char* type_name, const std::string& key, const uint32_t appid, const uint32_t linger_time); static bool DeleteWhite(const char* type_name, const std::string& key, const uint32_t appid); static bool AddBlock(const char* type_name, const std::string& key, const uint32_t appid, const uint32_t linger_time, const uint32_t block_level); static bool DeleteBlock(const char* type_name, const std::string& key, const uint32_t appid); static uint32_t GetWhiteLevel(const FreqItem* item); static uint32_t GetBlackLevel(const FreqItem* item); private: static const uint32_t kWhiteFlag; static const uint32_t kAddBlockFlag; static const FreqItem* CommAdd(FreqStat *freq_stat, const std::string& key, const AppidMeta& appid_meta, const uint32_t appid, const uint32_t cnt); static uint32_t TimeSplit(time_t timestamp, uint32_t scale); static TypeName2FreqStatMap type_name_map_; }; } // namespace libwxfreq #endif // FREQLIB_FREQ_FREQ_MANAGER_H_ ================================================ FILE: freq/freqlib.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include "libwxfreq.h" #include #include #include "appid_manager.h" #include "freq_manager.h" #include "rule_manager.h" #include "map_freq_stat.h" #include "shm_freq_stat.h" #include "options.h" #include "freq_stat.h" #include "log.h" #include "reload.h" using namespace libwxfreq; const static uint32_t kDeleteTime = 86400; TypeName2FreqStatMap type_name_map; int RegisterNewMapStat(const char* type_name, bool /*zero_init*/, key_t /*key*/, unsigned int /*item_cnt*/) { if (type_name == NULL) { gLog("[%s][%d]: type name empty\n", __FILE__, __LINE__); return kErrorInput; } TypeName2FreqStatMap::iterator it = type_name_map.find(type_name); if (it != type_name_map.end()) delete it->second; FreqStat * tmp_map = new MapFreqStat(); if (tmp_map == NULL) { gLog("[%s][%d]: alloc stat memory error, type name:%s\n", __FILE__, __LINE__, type_name); return kErrorSystem; } tmp_map->set_type_name(type_name); type_name_map[type_name] = tmp_map; return kOK; } int RegisterNewShmStat(const char* type_name, bool zero_init, key_t key, unsigned int item_cnt) { if (type_name == NULL) { gLog("[%s][%d]: type name empty\n", __FILE__, __LINE__); return kErrorInput; } TypeName2FreqStatMap::iterator it = type_name_map.find(type_name); if (it != type_name_map.end()) delete it->second; FreqStat * tmp_map = new ShmFreqStat(zero_init, key, item_cnt); if (tmp_map == NULL) { gLog("[%s][%d]: alloc stat memory error, type name:%s\n", __FILE__, __LINE__, type_name); return kErrorSystem; } tmp_map->set_type_name(type_name); type_name_map[type_name] = tmp_map; return kOK; } void SetRuleConfFile(const char *filename) { RuleManager::set_rule_conf_file(filename); } bool InitFreq() { RuleManager::Init(); return FreqManager::Init(type_name_map); } static BlockResult MakeBlockResult(unsigned int block_level, const char* match_rule) { BlockResult result; result.block_level = block_level; strncpy(result.match_rule, match_rule, sizeof(result.match_rule)); return result; } BlockResult ReportAndCheck(const char* type_name, const char *key, const uint32_t appid, const uint32_t cnt) { const FreqItem* p = NULL; p = FreqManager::Add(type_name, key, appid, cnt); if (p == NULL) return MakeBlockResult(kErrorOutOfMemory, ""); RuleManager::Result res = RuleManager::IsMatchRule(type_name, appid, *p); return MakeBlockResult(res.block_level, res.match_rule.c_str()); } struct BlockResult OnlyCheck(const char* type_name, const char *key, const uint32_t appid) { return ReportAndCheck(type_name, key, appid, 0); } int OnlyReport(const char* type_name, const char *key, const uint32_t appid, const uint32_t cnt) { if (FreqManager::Add(type_name, key, appid, cnt) == NULL) return kErrorOutOfMemory; return 0; } static FreqCache MakeFreqCache(const uint32_t level1, const uint32_t level2, const uint32_t level3) { FreqCache freqcache = {level1, level2, level3}; return freqcache; } FreqCache GetCache(const char* type_name, const char *key, const uint32_t appid, const uint32_t cnt) { const FreqItem* p = NULL; p = FreqManager::Add(type_name, key, appid, cnt); if (p == NULL) return MakeFreqCache(0, 0, 0); return MakeFreqCache(p->level1_cnt, p->level2_cnt, p->level3_cnt); } void SetLogFunc(LogFunction logfunc) { SetLog(logfunc); } int AddWhite(const char* type_name, const char *key, const uint32_t appid, const uint32_t linger_time) { if (gDumpFunc("AddWhite", type_name, key, appid, linger_time, 1) != 0) return kErrorSystem; if (FreqManager::AddWhite(type_name, key, appid, linger_time) == false) return kErrorOutOfMemory; return 0; } int DeleteWhite(const char* type_name, const char *key, const uint32_t appid) { if (gDumpFunc("DeleteWhite", type_name, key, appid, kDeleteTime, 1) != 0) return kErrorSystem; if (FreqManager::DeleteWhite(type_name, key, appid) == false) return kErrorOutOfMemory; return 0; } int AddBlock(const char* type_name, const char *key, const uint32_t appid, const uint32_t linger_time, const uint32_t block_level) { if (gDumpFunc("AddBlock", type_name, key, appid, linger_time, block_level) != 0) return kErrorSystem; if (FreqManager::AddBlock(type_name, key, appid, linger_time, block_level) == false) return kErrorOutOfMemory; return 0; } int DeleteBlock(const char* type_name, const char *key, const uint32_t appid) { if (gDumpFunc("DeleteBlock", type_name, key, appid, kDeleteTime, 1) != 0) return kErrorSystem; if (FreqManager::DeleteBlock(type_name, key, appid) == false) return kErrorOutOfMemory; return 0; } void SetLoadFunc(LoadFunc func) { libwxfreq::SetLoadFunc(func); } void SetDumpFunc(DumpFunc func) { libwxfreq::SetDumpFunc(func); } ================================================ FILE: freq/libwxfreq.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef FREQLIB_FREQ_FREQLIB_H_ #define FREQLIB_FREQ_FREQLIB_H_ #include #include #ifdef __cplusplus extern "C" { #endif enum { kOK = 0, kErrorOutOfMemory = -1, kErrorNoAppName = -2, kErrorSystem = -3, kErrorInput = -4, }; struct BlockResult { int block_level; char match_rule[32]; }; struct FreqCache { uint32_t level1_cnt; uint32_t level2_cnt; uint32_t level3_cnt; }; int RegisterNewShmStat(const char* type_name, bool zero_init, key_t key, unsigned int item_cnt); int RegisterNewMapStat(const char* type_name, bool zero_init, key_t key, unsigned int item_cnt); void SetRuleConfFile(const char *filename); bool InitFreq(); struct BlockResult ReportAndCheck(const char* type_name, const char *key, const uint32_t appid, const uint32_t cnt); struct BlockResult OnlyCheck(const char* type_name, const char *key, const uint32_t appid); int OnlyReport(const char* type_name, const char *key, const uint32_t appid, const uint32_t cnt); struct FreqCache GetCache(const char* type_name, const char *key, const uint32_t appid, const uint32_t cnt = 0); int AddWhite(const char* type_name, const char *key, const uint32_t appid, const uint32_t linger_time); int DeleteWhite(const char* type_name, const char *key, const uint32_t appid); int AddBlock(const char* type_name, const char *key, const uint32_t appid, const uint32_t linger_time, const uint32_t block_level); int DeleteBlock(const char* type_name, const char *key, const uint32_t appid); typedef int (*LogFunction)(const char* format, ...); void SetLogFunc(LogFunction logfunc); typedef int (*LoadFunc)(const char* type_name); void SetLoadFunc(LoadFunc func); typedef int (*DumpFunc)(const char* opname, const char* type_name, const char *key, const uint32_t appid, const unsigned int linger_time, const uint32_t block_level); void SetDumpFunc(DumpFunc func); #ifdef __cplusplus } #endif #endif // FREQLIB_FREQ_FREQLIB_H_ ================================================ FILE: freq/plain_expression.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include "plain_expression.h" #include #include #include #include "slice.h" #include "log.h" namespace libwxfreq { static bool Greater(const FreqItem& freqitem, const unsigned int index, const unsigned int threshold) { if (index >= 3) return false; const unsigned int *p = (const unsigned int *)&freqitem; return p[index] > threshold; } static bool GreaterOrEqual(const FreqItem& freqitem, const unsigned int index, const unsigned int threshold) { if (index >= 3) return false; const unsigned int *p = (const unsigned int *)&freqitem; return p[index] >= threshold; } bool PlainExpression::ParseItem(const std::string& item) { const char *ptr = NULL; ptr = strstr(item.c_str(), ">"); if (ptr == NULL) return false; Slice keyword(item.c_str(), ptr); keyword.StrTrim(" "); if (keyword == "min_interval") { key_index_ = 0; } else if (keyword == "mid_interval") { key_index_ = 1; } else if (keyword == "max_interval") { key_index_ = 2; } else { gLog("[%s][%d]: wrong keyword %s, item %s\n", __FILE__, __LINE__, keyword.ToStr().c_str(), item.c_str()); return false; } ptr++; if (*ptr == '=') { ptr++; cmp_ = GreaterOrEqual; } else { cmp_ = Greater; } if (*ptr == '\0') { gLog("[%s][%d]: wrong syntax item %s\n", __FILE__, __LINE__, item.c_str()); return false; } threshold_ = strtoul(ptr, NULL, 10); return threshold_ > 0; } bool PlainExpression::IsMatch(const FreqItem& freqitem) const { return cmp_(freqitem, key_index_, threshold_); } std::string PlainExpression::DebugString() const { std::string op = "NULL"; if (cmp_ == GreaterOrEqual) op = "GreaterOrEqual"; else if (cmp_ == Greater) op = "Greater"; char buf[128]; snprintf(buf, sizeof(buf), "key_index:%u\tthreshold:%u\tcmp:%s\taddr:%lx", key_index_, threshold_, op.c_str(), (unsigned long int)cmp_); return std::string(buf); } Expression* PlainExpression::Clone() const { return new PlainExpression(cmp_, threshold_, key_index_); } } // namespace libwxfreq ================================================ FILE: freq/plain_expression.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef FREQLIB_FREQ_PLAIN_EXPRESSION_H_ #define FREQLIB_FREQ_PLAIN_EXPRESSION_H_ #include #include "expression.h" #include "log.h" namespace libwxfreq { class PlainExpression: public Expression { public: PlainExpression() { } bool ParseItem(const std::string& item); bool IsMatch(const FreqItem& freqitem) const; std::string DebugString() const; Expression* Clone() const; private: typedef bool (*cmp)(const FreqItem&, const unsigned int, const unsigned int); PlainExpression(const cmp func, const unsigned int threshold, const unsigned char key_index) : cmp_(func), threshold_(threshold), key_index_(key_index) { } // parse item cmp cmp_; unsigned int threshold_; uint8_t key_index_; }; } // namespace libwxfreq #endif // FREQLIB_FREQ_PLAIN_EXPRESSION_H_ ================================================ FILE: freq/rule_item.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef FREQLIB_FREQ_RULE_ITEM_H_ #define FREQLIB_FREQ_RULE_ITEM_H_ #include #include #include "expression.h" namespace libwxfreq { class FreqItem; class RuleItem { public: RuleItem(const std::string& rulename, uint16_t blocklevel) : match_rulename_(rulename), block_level_(blocklevel), expression_(NULL) { } RuleItem(const RuleItem& other) { *this = other; expression_ = other.expression_->Clone(); } ~RuleItem() { if (expression_ != NULL) delete expression_; } inline uint16_t block_level() const { return block_level_; } inline const std::string& match_rulename() const { return match_rulename_; } inline void set_match_rulename(const std::string& match_rulename) { match_rulename_ = match_rulename; } inline void set_block_level(uint16_t block_level) { block_level_ = block_level; } inline void set_expression(Expression* p) { if (expression_ != NULL) delete expression_; expression_ = p; } inline Expression* expression() { return expression_; } inline bool ParseItem(const std::string& item) { return expression_->ParseItem(item); } inline bool IsMatch(const FreqItem& freqitem) const { return expression_->IsMatch(freqitem); } inline std::string DebugString() { std::string expression = expression_->DebugString(); char buf[512]; snprintf(buf, sizeof(buf), "match_rulename:%s\tblock_level:%u\t" "expression:%s", match_rulename_.c_str(), block_level_, expression.c_str()); return std::string(buf); } private: std::string match_rulename_; uint16_t block_level_; Expression* expression_; }; } // namespace libwxfreq #endif // FREQLIB_FREQ_RULE_ITEM_H_ ================================================ FILE: freq/rule_manager.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include "rule_manager.h" #include #include #include #include "plain_expression.h" #include "config.h" #include "log.h" #include "appid_manager.h" #include "freq_item.h" #include "rule_item.h" #include "freq_manager.h" namespace libwxfreq { std::string RuleManager::rule_conf_file_; bool RuleManager::is_loading_ = false; time_t RuleManager::last_modify_time_ = 0; unsigned char RuleManager::index_ = 0; TypeNameMap RuleManager::map_[2]; int RuleManager::Init() { return TryLoadFile(); } int RuleManager::TryLoadFile() { if (rule_conf_file_.empty()) { gLog("[%s][%d]: rule confile empty\n", __FILE__, __LINE__); return -1; } struct stat _filestat; if (stat(rule_conf_file_.c_str(), &_filestat) < 0) { gLog("[%s][%d]: stat confile %s failed\n", __FILE__, __LINE__, rule_conf_file_.c_str()); return -2; } if (_filestat.st_mtime > last_modify_time_ && time(NULL) - _filestat.st_mtime >= 2) { if (__sync_bool_compare_and_swap(&is_loading_, false, true)) { last_modify_time_ = _filestat.st_mtime; LoadFile(); is_loading_ = false; } } return 0; } int RuleManager::LoadFile() { gLog("[%s][%d]: Load confile %s\n", __FILE__, __LINE__, rule_conf_file_.c_str()); Config cfg(rule_conf_file_); if (cfg.Init() != 0) { gLog("[%s][%d]: int confile %s failed\n", __FILE__, __LINE__, rule_conf_file_.c_str()); return -1; } unsigned char new_index = (index_ + 1) % 2; map_[new_index].clear(); std::vector sectionList; cfg.section_list(sectionList); for (std::vector::iterator it = sectionList.begin(); it != sectionList.end(); ++it) { if (*it != "appid") InsertRule(cfg, it->c_str()); } AppidManager::UpdateAppidMeta(cfg); index_ = new_index; gLog("[%s][%d]: new index %d\n", __FILE__, __LINE__, index_); return 0; } int RuleManager::InsertRule(const Config& config, const std::string& section) { std::string item; std::string rule_type; unsigned int block_level = 0; unsigned int match_appid; unsigned int new_index = (index_ + 1) % 2; int ret1 = config.ReadItem(section, "item", "", item); int ret2 = config.ReadItem(section, "match_appid", 0, match_appid); int ret3 = config.ReadItem(section, "block_level", 0, block_level); int ret4 = config.ReadItem(section, "rule_type", "user", rule_type); if (ret1 != 0 || ret2 != 0 || ret3 != 0 || ret4 < 0) { gLog("[%s][%d]: insert rule section %s failed %d|%d|%d|%d\n", __FILE__, __LINE__, section.c_str(), ret1, ret2, ret3, ret4); return -1; } if (block_level <= 0) { gLog("[%s][%d]: insert rule section %s block_level %d, skip\n", __FILE__, __LINE__, section.c_str(), block_level); return -2; } RuleItem rule_item(section, block_level); rule_item.set_expression(new PlainExpression()); if (rule_item.ParseItem(item) == false) { gLog("[%s][%d]: insert rule section %s parse failed skip\n", __FILE__, __LINE__, section.c_str()); return -3; } map_[new_index][rule_type][match_appid].push_back(rule_item); gLog("[%s][%d]: insert rule section %s match_appid %u block_level %d" " rule_type %s item %s rule_item %s\n", __FILE__, __LINE__, section.c_str(), match_appid, block_level, rule_type.c_str(), item.c_str(), rule_item.DebugString().c_str()); return 0; } std::string RuleManager::DebugString() { TryLoadFile(); TypeNameMap& current_map = map_[index_]; std::string rule_string; for (TypeNameMap::iterator cit = current_map.begin(); cit != current_map.end(); ++cit) { for (AppidMapVecRuleItem::iterator it = cit->second.begin(); it != cit->second.end(); ++it) { for (std::vector::iterator vit = it->second.begin(); vit != it->second.end(); ++vit) { rule_string.append("match_appid:\t"); rule_string.append(std::to_string(it->first)); rule_string.append("\n"); rule_string.append(vit->DebugString()); } } } return rule_string; } RuleManager::Result RuleManager::IsMatch(const uint32_t appid, const FreqItem& freq_item, const AppidMapVecRuleItem& map) { TryLoadFile(); AppidMapVecRuleItem::const_iterator it = map.find(appid); if (it == map.end()) { return RuleManager::Result(0, ""); } for (std::vector::const_iterator vit = it->second.begin(); vit != it->second.end(); ++vit) { if (vit->IsMatch(freq_item)) { RuleManager::Result res(vit->block_level(), vit->match_rulename()); return res; } } return RuleManager::Result(0, ""); } RuleManager::Result RuleManager::IsMatchRule(const char * type_name, const uint32_t appid, const FreqItem& freq_item) { if (type_name == NULL || FreqManager::GetWhiteLevel(&freq_item) > 0) { return RuleManager::Result(0, ""); } if (FreqManager::GetBlackLevel(&freq_item) > 0) { return RuleManager::Result(FreqManager::GetBlackLevel(&freq_item), "black"); } TypeNameMap::iterator it = map_[index_].find(type_name); if (it == map_[index_].end()) { return RuleManager::Result(0, ""); } return IsMatch(appid, freq_item, it->second); } } // namespace libwxfreq ================================================ FILE: freq/rule_manager.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef FREQLIB_FREQ_RULE_MANAGER_H_ #define FREQLIB_FREQ_RULE_MANAGER_H_ #include #include #include #include namespace libwxfreq { class Config; class FreqItem; class RuleItem; typedef std::map > AppidMapVecRuleItem; typedef std::map TypeNameMap; class RuleManager { public: struct Result { int block_level; std::string match_rule; Result(): block_level(0), match_rule() { } Result(int b, const std::string& matchrule) : block_level(b), match_rule(matchrule) { } }; public: static inline void set_rule_conf_file(const std::string& filename) { rule_conf_file_ = filename; } static int Init(); static std::string DebugString(); static Result IsMatchRule(const char * type_name, const uint32_t appid, const FreqItem& freq_item); private: static int LoadFile(); static int TryLoadFile(); static int InsertRule(const Config& config, const std::string& section); static Result IsMatch(const uint32_t appid, const FreqItem& freq_item, const AppidMapVecRuleItem& map); private: static std::string rule_conf_file_; static bool is_loading_; static time_t last_modify_time_; static TypeNameMap map_[2]; static unsigned char index_; }; } // namespace libwxfreq #endif // FREQLIB_FREQ_RULE_MANAGER_H_ ================================================ FILE: main.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include #include #include #include #include "server.h" #include "worker.h" #include "libwxfreq.h" using std::cout; using std::endl; static inline int Log(const char* format, ...) { return 0; } int main(int argc, char* argv[]) { libwxfreq::ServerConf& conf = libwxfreq::ServerConf::GetInstance(); conf.LoadFile("./server.conf"); SetLogFunc(Log); SetRuleConfFile(conf.libwxfreq_conf_path().c_str()); const std::vector& type = conf.stat_vec(); for (std::vector::const_iterator it = type.cbegin(); it != type.cend(); ++it) { int ret = RegisterNewShmStat(it->GetTypeName().c_str(), it->init() > 0, it->shm_key(), it->item_count()); if (ret != 0) { cout << "RegisterNewShmStat failed, ret = " << ret << endl; return -1; } } if (InitFreq() == false) { cout << "InitFreq failed" << endl; return -2; } libwxfreq::Server server(libwxfreq::TxtFreqReq); // libwxfreq::Server server(ip, port, libwxfreq::Echo, worker_num); server.Run(); return 0; } ================================================ FILE: net/acceptor.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include #include #include #include #include #include "acceptor.h" #include "server.h" namespace libwxfreq { Acceptor::Acceptor(Server* s) :s_(s) { } void Acceptor::LoopAccept(const char *ip, const int port) { int listen_fd = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(ip); if (bind(listen_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0) { close(listen_fd); exit(-1); } if (listen(listen_fd, 1024) < 0) { close(listen_fd); exit(-1); } while (true) { struct sockaddr_in addr_in; socklen_t socklen = sizeof(addr_in); int accepted_fd = accept(listen_fd, (struct sockaddr*) &addr_in, &socklen); if (accepted_fd > 0) { s_->pool().AddNewConn(accepted_fd); } } close(listen_fd); } } // namespace libwxfreq ================================================ FILE: net/acceptor.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef LIBFEQ_NET_ACCEPTOR_H_ #define LIBFEQ_NET_ACCEPTOR_H_ namespace libwxfreq { class Server; class Acceptor { public: explicit Acceptor(Server *s); void LoopAccept(const char *ip, const int port); private: Server* s_; }; } // namespace libwxfreq #endif // LIBFEQ_NET_ACCEPTOR_H_ ================================================ FILE: net/iothread.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include "iothread.h" #include #include #include #include #include #include #include #include #include #include "util.h" #include "server_conf.h" namespace libwxfreq { using std::string; using std::max; static NotifySessionStat notify_stat; static CloseSessionStat close_stat; static ReadSessionStat read_stat; static CheckSessionStat check_stat; static WriteSessionStat write_stat; static ProcessSessionStat process_stat; static size_t ValidatePkg(const char* buf, size_t len) { const char *pn = static_cast(memchr(buf, '\n', len)); const char *pr = static_cast(memchr(buf, '\r', len)); if (pn == NULL && pr == NULL) { return -1; } const char *p = pn != NULL ? pn : pr; if (pr != NULL && pr < p) p = pr; while ((*p == '\0' || *p == '\r' || *p == '\n' || *p == ' ' || *p == '\t') && p < buf + len) p++; return p - buf; } SKBuff::SKBuff():buffer_(array_), write_pos_(0), read_pos_(0), capacity_(LIBFREQ_BUFFER_SIZE) { buffer_[0] ='\0'; } SKBuff::~SKBuff() { if (buffer_ != array_) { delete[] buffer_; } } char* SKBuff::GetWritePos() { return buffer_ + write_pos_; } char* SKBuff::GetReadPos() { return buffer_ + read_pos_; } size_t SKBuff::AddWritePos(size_t size) { write_pos_ += size; return write_pos_; } size_t SKBuff::AddReadPos(size_t size) { read_pos_ += size; return read_pos_; } size_t SKBuff::GetUseableSize() { if (capacity_ - write_pos_ < 32) { ExpandSize(capacity_); } return capacity_ - write_pos_; } void SKBuff::Attach(SKBuff& buff) { Reset(); write_pos_ = buff.write_pos_; read_pos_ = buff.read_pos_; capacity_ = buff.capacity_; if (buff.array_ == buff.buffer_) { buffer_ = array_; memcpy(buffer_, buff.GetReadPos(), buff.GetUnReadSize()); read_pos_ = 0; write_pos_ = buff.GetUnReadSize(); } else { buffer_ = buff.buffer_; buff.buffer_ = NULL; } } void SKBuff::Attach(const char* buff, size_t len) { Reset(); ExpandSize(len); memcpy(buffer_, buff, len); write_pos_ = len; } char* SKBuff::GetBuffer() { return buffer_; } size_t SKBuff::GetBufferLen() { return write_pos_; } size_t SKBuff::GetUnReadSize() { return write_pos_ - read_pos_; } void SKBuff::Reset() { if (buffer_ != array_) delete[] buffer_; buffer_ = array_; write_pos_ = 0; read_pos_ = 0; capacity_ = LIBFREQ_BUFFER_SIZE; buffer_[0] = '\0'; } void SKBuff::Shrink() { memmove(buffer_, buffer_ + read_pos_, GetUnReadSize()); write_pos_ -= read_pos_; read_pos_ = 0; } void SKBuff::ExpandSize(size_t len) { if (len > capacity_ - write_pos_) { capacity_ = max(capacity_ * 2, len + write_pos_); char * tmp = new char[capacity_]; memcpy(tmp, buffer_, write_pos_); if (buffer_ != array_) delete[] buffer_; buffer_ = tmp; } } void IOThread::run() { thread_->base = event_base_new(); ConnSession *session = new ConnSession(); session->fd = thread_->receive_fd; session->iothread = this; session->stat = ¬ify_stat; SetSockNonBlock(session->fd); event_set(&session->event, thread_->receive_fd, EV_READ | EV_PERSIST, ConnSession::Handler, session); event_base_set(thread_->base, &session->event); if (event_add(&session->event, 0) != 0) { exit(-1); } // run thread if (pthread_create(&thread_->tid, NULL, IOThread::ThreadEntry, thread_) != 0) { exit(-1); } } IOThread::IOThread(Thread * t) :thread_(t) { } Thread& IOThread::thread() { return *thread_; } void* IOThread::ThreadEntry(void *args) { Thread *thread = static_cast(args); event_base_loop(thread->base, 0); event_base_free(thread->base); return NULL; } void ConnSession::Handler(int fd, int16_t event, void* args) { ConnSession *session = static_cast(args); if (event & EV_TIMEOUT) { session->stat = &close_stat; } while (session->stat->Handler(event, session) > 0) { continue; } } ConnSession::~ConnSession() { event_del(&event); event_del(&timeout_event); close(fd); } const std::string& NotifySessionStat::GetName() const { static std::string name = "notify"; return name; } int NotifySessionStat::Handler(int16_t event, ConnSession* session) { char buf[1]; int count = read(session->fd, buf, sizeof(buf)); if (count <= 0) return kDone; ConnItem *item = session->iothread->thread().queue.DeQueue(); if (item == NULL) return kDone; ConnSession *new_conn_session = new ConnSession(); new_conn_session->fd = item->fd; SetSockNonBlock(item->fd); new_conn_session->iothread = session->iothread; new_conn_session->stat = &read_stat; new_conn_session->keep_alive = false; event_set(&new_conn_session->event, new_conn_session->fd, EV_READ | EV_PERSIST, ConnSession::Handler, new_conn_session); event_base_set(session->iothread->thread().base, &new_conn_session->event); event_set(&new_conn_session->timeout_event, -1, 0, ConnSession::Handler, new_conn_session); event_base_set(session->iothread->thread().base, &new_conn_session->timeout_event); ServerConf& conf = ServerConf::GetInstance(); struct timeval tv = {conf.timeout(), 0}; if (event_add(&new_conn_session->event, 0) != 0 || event_add(&new_conn_session->timeout_event, &tv) != 0) { new_conn_session->stat = &close_stat; return kContinue; } return kDone; } const std::string& CloseSessionStat::GetName() const { static std::string name = "close"; return name; } int CloseSessionStat::Handler(int16_t event, ConnSession* session) { delete session; return kDone; } const std::string& ReadSessionStat::GetName() const { static std::string name = "read"; return name; } int ReadSessionStat::Handler(int16_t event, ConnSession* session) { int read_size = read(session->fd, session->recv.GetWritePos(), session->recv.GetUseableSize()); if (read_size <= 0) { session->stat = &close_stat; return kContinue; } session->recv.AddWritePos(read_size); session->stat = &check_stat; return kContinue; } const std::string& CheckSessionStat::GetName() const { static std::string name = "check"; return name; } int CheckSessionStat::Handler(int16_t event, ConnSession* session) { int pkglen = ValidatePkg(session->recv.GetBuffer(), session->recv.GetBufferLen()); if (pkglen <= 0) { session->stat = &read_stat; return kDone; // continue read more data } session->in.Attach(session->recv.GetReadPos(), pkglen); session->recv.AddReadPos(pkglen); session->recv.Shrink(); session->stat = &process_stat; return kContinue; } const std::string& WriteSessionStat::GetName() const { static std::string name = "write"; return name; } int WriteSessionStat::Handler(int16_t event, ConnSession* session) { size_t size = write(session->fd, session->out.GetReadPos(), session->out.GetUnReadSize()); if (size < 0) { session->stat = &close_stat; return kContinue; } if (size < session->out.GetUnReadSize()) { session->out.AddReadPos(size); return kDone; // continue to write; } if (session->keep_alive) { event_del(&session->event); event_set(&session->event, session->fd, EV_READ | EV_PERSIST, ConnSession::Handler, session); event_base_set(session->iothread->thread().base, &session->event); if (event_add(&session->event, 0) != 0) { session->stat = &close_stat; return kContinue; } session->stat = &check_stat; session->out.Reset(); return kContinue; } else { session->stat = &close_stat; return kContinue; } return kDone; } const std::string& ProcessSessionStat::GetName() const { static std::string name = "process"; return name; } int ProcessSessionStat::Handler(int16_t event, ConnSession* session) { if (strncmp(session->in.GetBuffer(), "keep_alive", 10) == 0) { session->keep_alive = true; session->in.Reset(); event_del(&session->timeout_event); session->stat = &check_stat; return kContinue; } string req(session->in.GetBuffer(), session->in.GetBufferLen()); string resp; session->iothread->thread().dispatch(req, resp); session->out.Attach(resp.data(), resp.size()); event_del(&session->event); event_set(&session->event, session->fd, EV_WRITE | EV_PERSIST, ConnSession::Handler, session); event_base_set(session->iothread->thread().base, &session->event); if (event_add(&session->event, 0) != 0) { session->stat = &close_stat; return kContinue; } session->stat = &write_stat; return kDone; } } // namespace libwxfreq ================================================ FILE: net/iothread.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef LIBFREQ_NET_IOTHREAD_H_ #define LIBFREQ_NET_IOTHREAD_H_ #include #include #include "server_inner.h" #define LIBFREQ_BUFFER_SIZE 128 namespace libwxfreq { class IOThread { public: explicit IOThread(Thread * t); void run(); Thread& thread(); private: static void* ThreadEntry(void *); Thread *thread_; }; class ConnSession; class SessionStat { public: virtual const std::string& GetName() const = 0; virtual int Handler(int16_t event, ConnSession* session) = 0; protected: enum { kDone = 0, kContinue = 1, }; }; class NotifySessionStat:public SessionStat { public: const std::string& GetName() const; int Handler(int16_t event, ConnSession* session); }; class CloseSessionStat:public SessionStat { public: const std::string& GetName() const; int Handler(int16_t event, ConnSession* session); }; class ReadSessionStat:public SessionStat { public: const std::string& GetName() const; int Handler(int16_t event, ConnSession* session); }; class CheckSessionStat:public SessionStat { public: const std::string& GetName() const; int Handler(int16_t event, ConnSession* session); }; class WriteSessionStat:public SessionStat { public: const std::string& GetName() const; int Handler(int16_t event, ConnSession* session); }; class ProcessSessionStat:public SessionStat { public: const std::string& GetName() const; int Handler(int16_t event, ConnSession* session); }; class SKBuff { public: SKBuff(); ~SKBuff(); char* GetWritePos(); char* GetReadPos(); size_t GetUseableSize(); void Attach(SKBuff& buff); void Attach(const char* buff, size_t len); char* GetBuffer(); size_t GetBufferLen(); size_t GetUnReadSize(); void Reset(); void Shrink(); size_t AddWritePos(size_t size); size_t AddReadPos(size_t size); private: void ExpandSize(size_t len); private: char array_[LIBFREQ_BUFFER_SIZE]; char* buffer_; size_t write_pos_; size_t read_pos_; size_t capacity_; }; struct ConnSession { int fd; bool keep_alive; SessionStat *stat; SKBuff recv; SKBuff in; SKBuff out; IOThread* iothread; struct event event; struct event timeout_event; static void Handler(int, int16_t, void *); ~ConnSession(); }; } // namespace libwxfreq #endif // LIBFREQ_NET_IOTHREAD_H_ ================================================ FILE: net/server.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include "server.h" #include "util.h" namespace libwxfreq { Server::Server(const char *ip, const int port, Dispatch func, const int worker_num) :server_ip_(ip), listent_port_(port), pool_(func, worker_num), acceptor_(this) { } Server::Server(Dispatch func) :pool_(func), acceptor_(this) { const ServerConf& conf = ServerConf::GetInstance(); server_ip_ = conf.listen_ip(); listent_port_ = conf.listen_port(); pool_.SetWorkerNum(conf.worker_num()); } void Server::Run() { if (Daemonize() != 0) exit(-1); if (!pool_.Run()) exit(-1); acceptor_.LoopAccept(server_ip_.c_str(), listent_port_); } WorkerPool& Server::pool() { return pool_; } } // namespace libwxfreq ================================================ FILE: net/server.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef LIBFREQ_NET_SERVER_H_ #define LIBFREQ_NET_SERVER_H_ #include #include #include "acceptor.h" #include "workerpool.h" #include "server_conf.h" namespace libwxfreq { class Server { public: Server(const char *ip, const int port, Dispatch func, const int worker_num = 4); explicit Server(Dispatch func); void Run(); WorkerPool& pool(); private: int worker_num_; std::string server_ip_; int listent_port_; WorkerPool pool_; Acceptor acceptor_; }; } // namespace libwxfreq #endif // LIBFREQ_NET_SERVER_H_ ================================================ FILE: net/server_conf.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include "server_conf.h" #include "config.h" namespace libwxfreq { using std::string; using std::to_string; StatType::StatType(const StatType& left):typename_(left.typename_), init_(left.init_), shm_key_(left.shm_key_), item_count_(left.item_count_) { } StatType::StatType(const std::string& tyname, uint32_t init, uint32_t shm_key, uint32_t item_count) :typename_(tyname), init_(init), shm_key_(shm_key), item_count_(item_count) { } const std::string& StatType::GetTypeName() const { return typename_; } uint32_t StatType::init() const { return init_; } uint32_t StatType::shm_key() const { return shm_key_; } uint32_t StatType::item_count() const { return item_count_; } ServerConf& ServerConf::GetInstance() { static ServerConf conf_; return conf_; } ServerConf::ServerConf() { has_init_ = false; } bool ServerConf::LoadFile(const std::string& file) { if (has_init_) return true; Config config(file); if (config.Init() != 0) return false; int32_t stat_num = 0; config.ReadItem("General", "libwxfreq_conf_path", "", libwxfreq_conf_path_); config.ReadItem("General", "stat_type_num", 0, stat_num); config.ReadItem("Server", "listen_ip", "", listen_ip_); config.ReadItem("Server", "listen_port", 0, listen_port_); config.ReadItem("Server", "worke_num", 0, worke_num_); config.ReadItem("Server", "timeout", 1, timeout_); stat_vec_.clear(); for (int i = 0; i < stat_num; i++) { string typename_, section_name = "Stat_"; uint32_t init = 0, shm_key = 0, item_count; section_name += to_string(i); config.ReadItem(section_name, "typename", "", typename_); config.ReadItem(section_name, "init", 0, init); config.ReadItem(section_name, "shm_key", 0, shm_key); config.ReadItem(section_name, "item_count", 0, item_count); StatType type(typename_, init, shm_key, item_count); stat_vec_.push_back(type); } if (stat_num > 0) { has_init_ = true; } return has_init_; } const std::string ServerConf::listen_ip() const { return listen_ip_; } const std::string ServerConf::libwxfreq_conf_path() const { return libwxfreq_conf_path_; } uint32_t ServerConf::listen_port() const { return listen_port_; } uint32_t ServerConf::worker_num() const { return worke_num_; } const std::vector& ServerConf::stat_vec() const { return stat_vec_; } uint32_t ServerConf::timeout() const { return timeout_; } } // namespace libwxfreq ================================================ FILE: net/server_conf.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef LIBFREQ_NET_SERVER_CONF_H_ #define LIBFREQ_NET_SERVER_CONF_H_ #include #include #include namespace libwxfreq { class StatType { public: StatType(const StatType& left); StatType(const std::string& tyname, uint32_t init, uint32_t shm_key, uint32_t item_count); const std::string& GetTypeName() const; uint32_t init() const; uint32_t shm_key() const; uint32_t item_count() const; private: std::string typename_; uint32_t init_; uint32_t shm_key_; uint32_t item_count_; }; class ServerConf { public: static ServerConf& GetInstance(); ServerConf(const ServerConf& a) = delete; bool LoadFile(const std::string& file); const std::string listen_ip() const; const std::string libwxfreq_conf_path() const; uint32_t listen_port() const; uint32_t worker_num() const; const std::vector& stat_vec() const; uint32_t timeout() const; private: ServerConf(); private: std::string libwxfreq_conf_path_; uint32_t stat_type_num_; std::string listen_ip_; uint32_t listen_port_; uint32_t worke_num_; uint32_t timeout_; std::vector stat_vec_; bool has_init_; }; } // namespace libwxfreq #endif // LIBFREQ_NET_SERVER_CONF_H_ ================================================ FILE: net/server_inner.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include "server_inner.h" namespace libwxfreq { void ConnQueue::EnQueue(int fd) { if ((head_ + 1) % 1024 != tail_) { array_[head_++].fd = fd; head_ %= 1024; } } ConnItem* ConnQueue::DeQueue() { ConnItem* item = NULL; if (tail_ != head_) { item = &array_[tail_++]; tail_ %= 1024; } return item; } } // namespace libwxfreq ================================================ FILE: net/server_inner.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef FREQLIB_NET_SERVER_INNER_H_ #define FREQLIB_NET_SERVER_INNER_H_ #include #include #include #include #include #include #include #include #include #include #include namespace libwxfreq { typedef std::function< void(const std::string&, std::string& resp) > Dispatch; struct ConnItem { int fd; }; class ConnQueue { public: ConnQueue() :head_(0), tail_(0) { } void EnQueue(int fd); ConnItem* DeQueue(); private: struct ConnItem array_[1024]; int head_; int tail_; }; class IOThread; struct Thread { pthread_t tid; IOThread *iothread; struct event_base *base; int receive_fd; // worker end int send_fd; // control end struct ConnQueue queue; Dispatch dispatch; }; } // namespace libwxfreq #endif // FREQLIB_NET_SERVER_INNER_H_ ================================================ FILE: net/util.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include #include #include #include #include namespace libwxfreq { int Daemonize() { int fd = 0; if (fork() != 0) exit(0); // child process, create a new session if (setsid() == -1) return -1; umask(0); chdir("/"); if ((fd = open("/dev/null", O_RDWR, 0)) != -1) { if (dup2(fd, STDIN_FILENO) < 0) return -1; if (dup2(fd, STDOUT_FILENO) < 0) return -1; if (dup2(fd, STDERR_FILENO) < 0) return -1; } signal(SIGPIPE, SIG_IGN); return 0; } void SetSockNonBlock(int sock) { int flags; flags = fcntl(sock, F_GETFL, 0); if (flags >= 0) { fcntl(sock, F_SETFL, flags | O_NONBLOCK); } } } // namespace libwxfreq ================================================ FILE: net/util.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef LIBFREQ_NET_UTIL_H_ #define LIBFREQ_NET_UTIL_H_ namespace libwxfreq { int Daemonize(); void SetSockNonBlock(int sock); } // namespace libwxfreq #endif // LIBFREQ_NET_UTIL_H_ ================================================ FILE: net/worker.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include #include #include #include #include #include #include "libwxfreq.h" namespace libwxfreq { using std::string; using std::vector; using std::ostringstream; void Echo(const string& req, string& resp) { resp = req; } void SplitReq(const char* req, vector& cmd) { const char* end = req; const char* start = NULL; while(*end != '\n' && *end != '\r' && *end != '\0') { if (*end == ' ' || *end == '\t') { if (start != NULL) { cmd.push_back(string(start, end - start)); start = NULL; } } else { if (start == NULL) { start = end; } } end++; } if (start != NULL) { cmd.push_back(string(start, end - start)); } } void TxtFreqReq(const string& req, string& resp) { vector parsed_req; SplitReq(req.c_str(), parsed_req); if (parsed_req.size() == 0) return; string cmd = parsed_req[0]; ostringstream ostr; if (strcasecmp(cmd.c_str(), "ReportAndCheck") == 0) { if (parsed_req.size() != 5) { ostr << "{\"code\": -1, \"msg\":\"wrong cmd, [ReportAndCheck type user key appid cnt]\"}\n\n"; } else { uint32_t appid = strtoul(parsed_req[3].c_str(), NULL, 10); uint32_t cnt = strtoul(parsed_req[4].c_str(), NULL, 10); BlockResult bs = ReportAndCheck(parsed_req[1].c_str(), parsed_req[2].c_str(), appid, cnt); ostr << "{\"code\": 0, \"block_level\": " << bs.block_level << ", \"match_rule\": \"" << bs.match_rule <<"\"}\n\n"; } } else if (strcasecmp(cmd.c_str(), "OnlyCheck") == 0) { if (parsed_req.size() != 4) { ostr << "{\"code\": -1, \"msg\":\"wrong cmd, [OnlyCheck type user key appid]\"}\n\n"; } else { uint32_t appid = strtoul(parsed_req[3].c_str(), NULL, 10); BlockResult bs = OnlyCheck(parsed_req[1].c_str(), parsed_req[2].c_str(), appid); ostr << "{\"code\": 0, \"block_level\": " << bs.block_level << ", \"match_rule\": \"" << bs.match_rule << "\"}\n\n"; } } else if (strcasecmp(cmd.c_str(), "OnlyReport") == 0) { if (parsed_req.size() != 5) { ostr << "{\"code\": -1, \"msg\":\"wrong cmd, [OnlyReport type user key appid cnt]\"}\n\n"; } else { uint32_t appid = strtoul(parsed_req[3].c_str(), NULL, 10); uint32_t cnt = strtoul(parsed_req[4].c_str(), NULL, 10); int ret = OnlyReport(parsed_req[1].c_str(), parsed_req[2].c_str(), appid, cnt); ostr << "{\"code\": " << ret << "}\n\n"; } } else if (strcasecmp(cmd.c_str(), "GetCache") == 0) { if (parsed_req.size() != 4) { ostr << "{\"code\": -1, \"msg\":\"wrong cmd, [GetCache type user key appid]\"}\n\n"; } else { uint32_t appid = strtoul(parsed_req[3].c_str(), NULL, 10); FreqCache cache = GetCache(parsed_req[1].c_str(), parsed_req[2].c_str(), appid); ostr << "{\"code\": 0, \"cnt1\": " << cache.level1_cnt <<", \"cnt2\": " << cache.level2_cnt <<", \"cnt3\": " << cache.level3_cnt << "}\n\n"; } } else if (strcasecmp(cmd.c_str(), "AddWhite") == 0) { if (parsed_req.size() != 5) { ostr << "{\"code\": -1, \"msg\":\"wrong cmd, [AddWhite type user key appid linger_time]\"}\n\n"; } else { uint32_t appid = strtoul(parsed_req[3].c_str(), NULL, 10); uint32_t linger_time = strtoul(parsed_req[4].c_str(), NULL, 10); int ret = AddWhite(parsed_req[1].c_str(), parsed_req[2].c_str(), appid, linger_time); ostr << "{\"code\": " << ret << "}\n\n"; } } else if (strcasecmp(cmd.c_str(), "DeleteWhite") == 0) { if (parsed_req.size() != 4) { ostr << "{\"code\": -1, \"msg\":\"wrong cmd, [DeleteWhite type user key appid]\"}\n\n"; } else { uint32_t appid = strtoul(parsed_req[3].c_str(), NULL, 10); int ret = DeleteWhite(parsed_req[1].c_str(), parsed_req[2].c_str(), appid); ostr << "{\"code\": " << ret << "}\n\n"; } } else if (strcasecmp(cmd.c_str(), "AddBlock") == 0) { if (parsed_req.size() != 6) { ostr << "{\"code\": -1, \"msg\":\"wrong cmd, [AddBlock type user key appid linger_time block_level]\"}\n\n"; } else { uint32_t appid = strtoul(parsed_req[3].c_str(), NULL, 10); uint32_t linger_time = strtoul(parsed_req[4].c_str(), NULL, 10); uint32_t block_level = strtoul(parsed_req[5].c_str(), NULL, 10); int ret = AddBlock(parsed_req[1].c_str(), parsed_req[2].c_str(), appid, linger_time, block_level); ostr << "{\"code\": " << ret << "}\n\n"; } } else if (strcasecmp(cmd.c_str(), "DeleteBlock") == 0) { if (parsed_req.size() != 4) { ostr << "{\"code\": -1, \"msg\":\"wrong cmd, [DeleteBlock type user key appid]\"}\n\n"; } else { uint32_t appid = strtoul(parsed_req[3].c_str(), NULL, 10); int ret = DeleteBlock(parsed_req[1].c_str(), parsed_req[2].c_str(), appid); ostr << "{\"code\": " << ret << "}\n\n"; } } else if (strcasecmp(cmd.c_str(), "Help") == 0) { ostr << "cmdlist:\n1: ReportAndCheck\n2: OnlyCheck\n3: OnlyReport\n" "4: GetCache\n5: AddWhite\n6: DeleteWhite\n7: AddBlock\n" "8: DeleteBlock\n\n"; } else { ostr << "{\"code\": -1, \"msg\":\"unkown cmd " << cmd << ", try [help]\"}\n\n"; } resp = ostr.str(); } } // namespace libwxfreq ================================================ FILE: net/worker.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef LIBFREQ_NET_WORKER_H_ #define LIBFREQ_NET_WORKER_H_ #include namespace libwxfreq { void Echo(const std::string& req, std::string& resp); void TxtFreqReq(const std::string& req, std::string& resp); } // namespace libwxfreq #endif // LIBFREQ_NET_WORKER_H_ ================================================ FILE: net/workerpool.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include "workerpool.h" #include #include #include #include "iothread.h" namespace libwxfreq { WorkerPool::WorkerPool(Dispatch func, int num) :pool_(NULL), pool_size_(num), last_accept_worker_index_(0), func_(func) { } void WorkerPool::SetWorkerNum(int num) { pool_size_ = num; } bool WorkerPool::Run() { pool_ = static_cast(malloc(pool_size_ * sizeof(Thread))); memset(reinterpret_cast(pool_), 0, pool_size_ * sizeof(Thread)); for (int i = 0; i < pool_size_; i++) { int fds[2] = {0}; if (pipe(fds) != 0) { return false; } pool_[i].receive_fd = fds[0]; pool_[i].send_fd = fds[1]; pool_[i].dispatch = func_; pool_[i].iothread = new IOThread(&pool_[i]); pool_[i].iothread->run(); } return true; } WorkerPool::~WorkerPool() { delete[] pool_; } void WorkerPool::AddNewConn(int fd) { last_accept_worker_index_ = (last_accept_worker_index_ + 1) % pool_size_; Thread &cur = pool_[last_accept_worker_index_]; cur.queue.EnQueue(fd); Notify(cur); } void WorkerPool::Notify(Thread& thread) { int fd = thread.send_fd; char cmd[1] = {'c'}; write(fd, cmd, 1); } } // namespace libwxfreq ================================================ FILE: net/workerpool.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef LIBFREQ_NET_WORKERPOOL_H_ #define LIBFREQ_NET_WORKERPOOL_H_ #include "server_inner.h" namespace libwxfreq { class WorkerPool { public: explicit WorkerPool(Dispatch func, int num = 0); void SetWorkerNum(int num); ~WorkerPool(); void AddNewConn(int fd); bool Run(); private: void Notify(Thread& thread); private: Thread* pool_; int pool_size_; size_t last_accept_worker_index_; Dispatch func_; }; } // namespace libwxfreq #endif // LIBFREQ_NET_WORKERPOOL_H_ ================================================ FILE: server.conf ================================================ [General] libwxfreq_conf_path = ./test.conf stat_type_num = 2 [Server] listen_ip = 10.0.0.1 listen_port = 5678 worke_num = 5 timeout = 10 [Stat_0] typename = user init = 0 shm_key = 20180313 item_count = 100000000 [Stat_1] typename = ip init = 0 shm_key = 20180314 item_count = 100000000 ================================================ FILE: test/demo.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include "libwxfreq/libwxfreq.h" #include #include #include #include int main(int argc, char* argv[]) { if (argc != 7){ printf("%s conf appid key keytype shm_key sleep_time(ms)\n", argv[0]); return 0; } SetRuleConfFile(argv[1]); int appid = strtoul(argv[2], NULL, 10); const char* key = argv[3]; const char* keytype = argv[4]; int shm_key = strtoul(argv[5], NULL, 10); int sleep_time = strtoul(argv[6], NULL, 10); sleep_time *= 1000; int ret = RegisterNewShmStat(keytype, false, shm_key, 1000000); if (ret != 0) { printf("RegisterNewShmStat failed, ret = %d\n", ret); return -1; } if (InitFreq() == false) { printf("InitFreq failed\n"); return -2; } while (true) { struct BlockResult res; res = ReportAndCheck(keytype, key, appid, 1); printf("time %lu blocklevel %u matchrule %s\n", time(NULL), res.block_level, res.match_rule); usleep(sleep_time); } } ================================================ FILE: test/performance_test.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include "libwxfreq/libwxfreq.h" #include #include #include #include #include #include #include static inline int Log(const char* format, ...) { } int main(int argc, char* argv[]) { if (argc != 3){ printf("%s conf item_count\n", argv[0]); return 0; } SetRuleConfFile(argv[1]); SetLogFunc(Log); int item_count = strtoul(argv[2], NULL, 10); int ret = RegisterNewShmStat("user", false, rand(), item_count); if (ret != 0) { printf("RegisterNewShmStat failed, ret = %d\n", ret); return -1; } if (InitFreq() == false) { printf("InitFreq failed\n"); return -2; } int oom_num = 0, first_time = 0; struct timeval start, end; gettimeofday(&start, NULL); printf("start time %u %u\n", start.tv_sec, start.tv_usec); for (int i = 0; i < item_count; i++) { struct BlockResult res; res = ReportAndCheck("user", "test", rand(), 1); if (res.block_level == kErrorOutOfMemory) { oom_num ++; if (first_time == 0) first_time = i + 1; } } gettimeofday(&end, NULL); printf("end time %u %u\n", end.tv_sec, end.tv_usec); printf("average time %u per second\n", (unsigned int)(item_count/(end.tv_sec-start.tv_sec))); printf("oom count %u first oom %u memory usage %.3f\n", oom_num, first_time, 100 - 100.0 * oom_num/item_count); return 0; } ================================================ FILE: test/test.conf ================================================ [appid] 100 = 30, 60, 90 [rule1] match_appid = 100 item = min_interval >= 10 block_level = 1 rule_type = user [rule2] match_appid = 100 item = mid_interval >= 15 block_level = 1 rule_type = user [rule3] match_appid = 100 item = max_interval >= 20 block_level = 1 rule_type = user [rule4] match_appid = 100 item = min_interval >= 100 block_level = 1 rule_type = ip [rule5] match_appid = 100 item = mid_interval >= 150 block_level = 1 rule_type = ip [rule6] match_appid = 100 item = max_interval >= 200 block_level = 1 rule_type = ip ================================================ FILE: test/tools.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include "libwxfreq/libwxfreq.h" #include #include #include #include #include int main(int argc, char* argv[]) { if (argc != 9){ printf("%s conf appid key keytype shm_key func level time\n", argv[0]); return 0; } SetRuleConfFile(argv[1]); int appid = strtoul(argv[2], NULL, 10); const char* key = argv[3]; const char* keytype = argv[4]; int shm_key = strtoul(argv[5], NULL, 10); const char* func = argv[6]; int block_level = strtoul(argv[7], NULL, 10); int linger_time = strtoul(argv[8], NULL, 10); int ret = RegisterNewShmStat(keytype, false, shm_key, 1000000); if (ret != 0) { printf("RegisterNewShmStat failed, ret = %d\n", ret); return -1; } if (InitFreq() == false) { printf("InitFreq failed\n"); return -2; } if (strcmp(func, "addblock") == 0) { ret = AddBlock(keytype, key, appid, linger_time, block_level); } else if (strcmp(func, "deleteblock") == 0) { ret = DeleteBlock(keytype, key, appid); } else if (strcmp(func, "addwhite") == 0) { ret = AddWhite(keytype, key, appid, linger_time); } else if (strcmp(func, "deletewhite") == 0) { ret = DeleteWhite(keytype, key, appid); } else { printf("unknown func\n"); return -3; } printf("%s return ret %d\n", func, ret); return ret; } ================================================ FILE: util/config.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include "config.h" #include #include #include #include #include #include #include #include "log.h" #include "slice.h" namespace libwxfreq { Config::Config(const std::string& conf_filename) { conf_filename_ = conf_filename; } const std::string & Config::conf_filename() { return conf_filename_; } void Config::set_conf_filename(const std::string &conf_filename) { conf_filename_ = conf_filename; } int Config::Init(void) { int ret = LoadFile(); if (0 != ret) { gLog("[%s][%d]: init config %s error return %d\n", __FILE__, __LINE__, conf_filename_.c_str(), ret); Reset(); } return ret; } int Config::Reset(void) { conf_filename_buf_.clear(); section_list_.clear(); table_.Clear(); } int Config::ParserConfig() { Slice section, key, value; const char *eol = NULL, *tmp = NULL; const char *ptr = conf_filename_buf_.c_str(); const char *endptr = conf_filename_buf_.c_str() + conf_filename_buf_.size(); while (ptr < endptr) { eol = strchr(ptr, '\n'); // getline if (eol == NULL) eol = endptr; // last line while (*ptr == ' ' || *ptr == '\t') ptr++; // ltrim if (*ptr == '[') { // section ptr += 1; tmp = ptr; while (*ptr != ']' && ptr < eol) ptr++; section = Slice(tmp, ptr); section.StrTrim("\t "); section_list_.push_back(section); } else if (NULL == strchr("#;\n", *ptr)) { // item tmp = ptr; while (*ptr != '=' && ptr < eol) ptr++; key = Slice(tmp, ptr); key.StrTrim("\t "); if (*ptr == '=' && section.start() != NULL) { ptr += 1; tmp = ptr; while (ptr < eol) ptr++; value = Slice(tmp, ptr); value.StrTrim("\t "); table_.Add(section, key, value); } } ptr = eol + 1; // next line } return section_list_.size() > 0 ? 0 : -1; } int Config::LoadFile(void) { FILE * fp = fopen(conf_filename_.c_str(), "r"); if (NULL != fp) { struct stat fileStat; if (0 == fstat(fileno(fp), &fileStat)) { Reset(); if (fileStat.st_size == 0) return 0; char *tmp = reinterpret_cast(malloc(fileStat.st_size + 64)); fread(tmp, fileStat.st_size, 1, fp); tmp[fileStat.st_size] = '\0'; // append '\0' make strchr happy conf_filename_buf_ = tmp; free(tmp); ParserConfig(); } else { gLog("[%s][%d]: open confile %s error\n", __FILE__, __LINE__, conf_filename_.c_str()); } fclose(fp); fp = NULL; } return section_list_.size() == 0 ? -1 : 0; } void Config::section_list(std::vector& sectionlist) { for (size_t i = 0; i < section_list_.size(); i++) { sectionlist.push_back(std::string(section_list_[i].start(), section_list_[i].end() - section_list_[i].start())); } } void Config::GetKeysBySection(const std::string §ion, std::vector& keys) const { std::vector slice_keys; table_.GetKeysBySection(section, slice_keys); for (std::vector::iterator it = slice_keys.begin(); it != slice_keys.end(); ++it) { keys.push_back(it->ToStr()); } } int Config::ReadItem(const std::string& section, const std::string& key, const char* defaultvalue, std::string& itemvalue) const { if (section.size() <= 0 || key.size() <= 0 ) return -1; std::string value; Slice idxsec = section; Slice idxkey = key; Slice val = table_.Get(idxsec, idxkey); if (val.start() != NULL) { value.assign(val.start(), val.end() - val.start()); std::stringstream ss(value, std::ios_base::in); itemvalue = ss.str(); return 0; } else { std::stringstream ss; ss << defaultvalue; itemvalue = ss.str(); return 1; } } } // namespace libwxfreq ================================================ FILE: util/config.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef FREQLIB_UTIL_CONFIG_H_ #define FREQLIB_UTIL_CONFIG_H_ #include #include #include #include "config_hash.h" namespace libwxfreq { class Config { public: Config() { } ~Config() { } explicit Config(const std::string &configfile); int Init(); const std::string & conf_filename(); void set_conf_filename(const std::string &conf_filename); void section_list(std::vector& sectionlist); void GetKeysBySection(const std::string §ion, std::vector& keys) const; template int ReadItem(const std::string& section, const std::string& key, const T1& defaultvalue, T2& itemvalue) const; int ReadItem(const std::string& section, const std::string& key, const char* defaultvalue, std::string& itemvalue) const; private: int Reset(); int ParserConfig(); int LoadFile(void); std::string conf_filename_; std::string conf_filename_buf_; std::vector section_list_; ConfigHashTable table_; }; template int Config::ReadItem(const std::string& section, const std::string& key, const T1& defaultvalue, T2& itemvalue) const { if (section.size() <= 0 || key.size() <= 0 ) return -1; std::string value; Slice idxsec = section; Slice idxkey = key; Slice val = table_.Get(idxsec, idxkey); if (val.start() != NULL) { value.assign(val.start(), val.end() - val.start()); std::stringstream ss(value, std::ios_base::in); ss >> itemvalue; return 0; } else { std::stringstream ss; ss << defaultvalue; ss >> itemvalue; return 1; } } } // namespace libwxfreq #endif // FREQLIB_UTIL_CONFIG_H_ ================================================ FILE: util/config_hash.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include #include "config_hash.h" namespace libwxfreq { // ConfigHashNode ConfigHashNode::ConfigHashNode():hash_num_(0) { } ConfigHashNode::ConfigHashNode(const unsigned int hash_num, const Slice &sec, const Slice &key, const Slice &val) { hash_num_ = hash_num; section_ = sec; key_ = key; value_ = val; } inline unsigned ConfigHashNode::hash_num() const { return hash_num_; } inline const Slice& ConfigHashNode::section() const { return section_; } inline const Slice& ConfigHashNode::key() const { return key_; } inline const Slice & ConfigHashNode::value() const { return value_; } // ConfigHashTable ConfigHashTable::ConfigHashTable() { } ConfigHashTable::ConfigHashTable(const ConfigHashTable &other) { table_ = other.table_; } ConfigHashTable::~ConfigHashTable() { } void ConfigHashTable::Clear() { table_.clear(); } // using FNV1 hash function inline unsigned int ConfigHashTable::HashFun(const Slice &sec, const Slice &key) const { static const unsigned int FNV1_BASIS = 2166136261lu; static const unsigned int FNV1_PRIME = 16777619; unsigned int ret = FNV1_BASIS; const char *ptr, *endptr; endptr = sec.end(); for (ptr = sec.start(); ptr < endptr; ptr++) { ret *= FNV1_PRIME; ret ^= tolower(*ptr); } endptr = key.end(); for (ptr = key.start(); ptr < endptr; ptr++) { ret *= FNV1_PRIME; ret ^= tolower(*ptr); } return ret; } void ConfigHashTable::Add(const Slice &sec, const Slice &key, const Slice &val) { unsigned int hashnum = HashFun(sec, key); table_[hashnum].push_back(ConfigHashNode(hashnum, sec, key, val)); std::vector::iterator it = table_[hashnum].end() - 1; unsigned int sec_hashnum = HashFun(sec, Slice()); keys_table_[sec_hashnum].push_back(it); } Slice ConfigHashTable::Get(const Slice &sec, const Slice &key) const { unsigned int hashnum = HashFun(sec, key); HashTable::const_iterator tit = table_.find(hashnum); if (tit == table_.end()) return Slice(); for (std::vector::const_iterator it = tit->second.begin(); it != tit->second.end(); ++it) { if (it->hash_num() == hashnum && it->section() == sec && it->key() == key) { return it->value(); } } return Slice(); } void ConfigHashTable::GetKeysBySection(const Slice &sec, std::vector &keys) const { unsigned int hashnum = HashFun(sec, Slice()); HashIteratorTable::const_iterator tit = keys_table_.find(hashnum); if (tit == keys_table_.end()) return; for (std::vector::iterator>::const_iterator it = tit->second.begin(); it != tit->second.end(); ++it) { if ((*it)->section() == sec) { keys.push_back((*it)->key()); } } } bool ConfigHashTable::Empty() { return table_.empty(); } } // namespace libwxfreq ================================================ FILE: util/config_hash.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef FREQLIB_UTIL_CONFIG_HASH_H_ #define FREQLIB_UTIL_CONFIG_HASH_H_ #include #include #include #include "slice.h" namespace libwxfreq { class ConfigHashNode { public: ConfigHashNode(); ConfigHashNode(const unsigned int hash_num, const Slice &sec, const Slice &key, const Slice &val); unsigned hash_num() const; const Slice & section() const; const Slice & key() const; const Slice & value() const; private: unsigned int hash_num_; Slice section_, key_, value_; }; class ConfigHashTable { public: ConfigHashTable(); ConfigHashTable(const ConfigHashTable &other); ~ConfigHashTable(); void Clear(); void Add(const Slice &sec, const Slice &key, const Slice &val); Slice Get(const Slice &sec, const Slice &key) const; void GetKeysBySection(const Slice &sec, std::vector &keys) const; bool Empty(); private: typedef std::map > HashTable; typedef std::map::iterator> > HashIteratorTable; // using FNV1 hash function inline unsigned int HashFun(const Slice &sec, const Slice &key) const; HashTable table_; HashIteratorTable keys_table_; }; } // namespace libwxfreq #endif // FREQLIB_UTIL_CONFIG_HASH_H_ ================================================ FILE: util/freq_stat.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef FREQLIB_UTIL_FREQ_STAT_H_ #define FREQLIB_UTIL_FREQ_STAT_H_ #include #include namespace libwxfreq { class FreqItem; class FreqStat { public: virtual uint32_t& GetItem(const std::string& key, const uint32_t appid, const uint32_t cnt, FreqItem* &freq_item) = 0; virtual bool TryReload() = 0; void set_type_name(const std::string& type_name) { type_name_ = type_name; } const std::string& type_name() const { return type_name_; } virtual ~FreqStat() { } protected: std::string type_name_; }; } // namespace libwxfreq #endif // FREQLIB_UTIL_FREQ_STAT_H_ ================================================ FILE: util/log.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include "log.h" #include #include #include #include #include #include #include #include #include #include namespace libwxfreq { static const char* kDefaultLogFileName = "/tmp/libwxfreq.log"; static inline pid_t gettid() { return syscall(SYS_gettid); } static void Logv(FILE *file, const char* format, va_list ap) { const uint64_t thread_id = gettid(); char buffer[500]; for (int iter = 0; iter < 2; iter++) { char* base; int bufsize; if (iter == 0) { bufsize = sizeof(buffer); base = buffer; } else { bufsize = 30000; base = new char[bufsize]; } char* p = base; char* limit = base + bufsize; struct timeval now_tv; gettimeofday(&now_tv, NULL); const time_t seconds = now_tv.tv_sec; struct tm t; localtime_r(&seconds, &t); p += snprintf(p, limit - p, "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, static_cast(now_tv.tv_usec), static_cast(thread_id)); // Print the message if (p < limit) { va_list backup_ap; va_copy(backup_ap, ap); p += vsnprintf(p, limit - p, format, backup_ap); va_end(backup_ap); } // Truncate to available space if necessary if (p >= limit) { if (iter == 0) { continue; // Try again with larger buffer } else { p = limit - 1; } } // Add newline if necessary if (p == base || p[-1] != '\n') { *p++ = '\n'; } assert(p <= limit); fwrite(base, 1, p - base, file); fflush(file); if (base != buffer) { delete[] base; } break; } } static int Log(const char* format, ...) { static FILE* file = fopen(kDefaultLogFileName, "a"); if (file == NULL) return -1; va_list ap; va_start(ap, format); Logv(file, format, ap); va_end(ap); return 0; } LogFunc gLog = Log; } // namespace libwxfreq ================================================ FILE: util/log.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef FREQLIB_UTIL_LOG_H_ #define FREQLIB_UTIL_LOG_H_ namespace libwxfreq { typedef int (*LogFunc)(const char* format, ...); extern LogFunc gLog; } // namespace libwxfreq #endif // FREQLIB_UTIL_LOG_H_ ================================================ FILE: util/map_freq_stat.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include "map_freq_stat.h" #include #include "reload.h" namespace libwxfreq { static uint32_t dummy_timestamp = 0; bool FreqKeyCmp(const FreqKey&a, const FreqKey&b) { if (a.appid < b.appid) { return true; } else if (a.appid == b.appid) { return strncmp(a.key, b.key, sizeof(a.key)) < 0; } return false; } uint32_t& MapFreqStat::GetItem(const std::string& key, const uint32_t appid, const uint32_t cnt, FreqItem* &freq_item) { FreqKey freqkey; freqkey.appid = appid; strncpy(freqkey.key, key.c_str(), sizeof(freqkey.key)); if (cnt != 0) { FreqItemForMap& freqitemformap = item_map[freqkey]; freq_item = reinterpret_cast(&freqitemformap); return freqitemformap.timestamp; } else { ItemMap::iterator it = item_map.find(freqkey); if (it == item_map.end()) { freq_item = NULL; return dummy_timestamp; } else { freq_item = reinterpret_cast(&(it->second)); return it->second.timestamp; } } } bool MapFreqStat::TryReload() { return gLoadFunc(type_name_.c_str()) == 0; } } // namespace libwxfreq ================================================ FILE: util/map_freq_stat.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef FREQLIB_UTIL_MAP_FREQ_STAT_H_ #define FREQLIB_UTIL_MAP_FREQ_STAT_H_ #include #include #include "freq_item.h" #include "freq_stat.h" namespace libwxfreq { #pragma pack(1) struct FreqItemForMap : public FreqItem { uint32_t timestamp; }; #pragma pack() bool FreqKeyCmp(const FreqKey&a, const FreqKey&b); class MapFreqStat : public FreqStat { public: MapFreqStat() : item_map(FreqKeyCmp) { } virtual uint32_t& GetItem(const std::string& key, const uint32_t appid, const uint32_t cnt, FreqItem* &freq_item); virtual bool TryReload(); private: typedef bool (*cmp) (const FreqKey&a, const FreqKey&b); typedef std::map ItemMap; ItemMap item_map; }; } // namespace libwxfreq #endif // FREQLIB_UTIL_MAP_FREQ_STAT_H_ ================================================ FILE: util/multi_hash_base.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef FREQLIB_UTIL_MULTI_HASH_BASE_H_ #define FREQLIB_UTIL_MULTI_HASH_BASE_H_ #include #include #include #include #include #include #include #include #include "log.h" namespace libwxfreq { static const unsigned int MAX_LEVEL_CNT = 30; static const unsigned int MAIN_LEVEL_CNT = 5; static const float MAIN_LEVEL_ITEM_RATE = 0.9; template class MultiHashBase { enum MultiHashRet { enMultiHashKeyNotFound = -3, enMultiHashBucketFull = -2, enMultiHashNotInit = -1, enMultiHashOK = 0, enMultiHashFoundEmptyItem = 1, enMultiHashFoundExpiredItem = 2, }; public: MultiHashBase(); virtual ~MultiHashBase(); typedef Key KeyType; typedef Value ValueType; public: int MultiHashInit(char *base, size_t len, unsigned int max_level = MAX_LEVEL_CNT, unsigned int main_level = MAIN_LEVEL_CNT); int GetValueForRead(const KeyType &input_key, ValueType *&value); int GetValueForWrite(const KeyType &input_key, ValueType *&value); protected: virtual int InitLevelHash(); unsigned int item_size() { return item_size_ ;} virtual size_t HashKey(const KeyType &input_key) = 0; virtual bool KeyCmp(const KeyType &input_key, const KeyType &key_in_mem) = 0; virtual bool IsExpired(const KeyType &key, const ValueType &value, void *old_value) = 0; virtual bool ExpiredOccupy(const KeyType &input_key, KeyType &key_in_mem, ValueType &value_in_mem, void *old_value) = 0; virtual bool IsEmpty(const KeyType &key, const ValueType &value) = 0; virtual bool EmptyOccupy(const KeyType &input_key, KeyType &key_in_mem) = 0; virtual void AfterFindReadItem(ValueType &value) = 0; virtual void AfterFindWriteItem(ValueType &value) = 0; private: char *shm_mem_base_; unsigned int max_level_; unsigned int main_level_; unsigned int item_size_; size_t shm_mem_len_; size_t max_item_cnt_; std::vector size_meta_; private: static size_t GetBiggestPrimer(size_t ulluppervalue); static bool IsPrimer(size_t ullvalue); }; template MultiHashBase::MultiHashBase() : shm_mem_base_(NULL), shm_mem_len_(0), max_level_(MAX_LEVEL_CNT), main_level_(MAIN_LEVEL_CNT) { item_size_ = sizeof(KeyType) + sizeof(ValueType); } template MultiHashBase::~MultiHashBase() { } template int MultiHashBase::MultiHashInit(char *base, size_t len, unsigned int max_level, unsigned int main_level) { shm_mem_base_ = base; shm_mem_len_ = len; max_level_ = max_level >= 2 * MAX_LEVEL_CNT ? 2 * MAX_LEVEL_CNT : max_level; max_level_ = max_level_ <= MAX_LEVEL_CNT / 2 ? MAX_LEVEL_CNT/ 2 : max_level_; main_level_ = main_level >= MAIN_LEVEL_CNT ? MAIN_LEVEL_CNT : main_level; main_level_ = main_level_<= MAIN_LEVEL_CNT / 2 ? MAIN_LEVEL_CNT / 2 : main_level_; main_level_ = main_level_ <= max_level_ ? main_level_ : max_level_ - 1; max_item_cnt_ = len / item_size_; size_meta_.reserve(max_level_); int ret = InitLevelHash(); if (0 != ret) { return -__LINE__; } return enMultiHashOK; } template int MultiHashBase::InitLevelHash() { unsigned int conflict_level = max_level_ - main_level_; size_t level_size = (size_t)(MAIN_LEVEL_ITEM_RATE * max_item_cnt_ / main_level_); gLog("[%s][%d]: level_size %llu rate %f cnt %llu\n", __FILE__, __LINE__, level_size, MAIN_LEVEL_ITEM_RATE, max_item_cnt_); size_t current_level_size = 0; size_t had_push_item_cnt = 0; for (int i = 0; i < max_level_; i++) { if (i == max_level_ -1) { size_meta_[i] = max_item_cnt_ - had_push_item_cnt; break; } if (level_size <= 2) { max_level_ = i + 1; size_meta_[i] = max_item_cnt_ - had_push_item_cnt; return enMultiHashOK; } current_level_size = GetBiggestPrimer(level_size); size_meta_[i] = current_level_size; had_push_item_cnt += current_level_size; if (i + 1 == main_level_) { level_size = (max_item_cnt_ - had_push_item_cnt) / conflict_level; } else { level_size = current_level_size - 1; } } for (int i = 0; i < max_level_; i++) { gLog("[%s][%d]: level %d size %llu\n", __FILE__, __LINE__, i, size_meta_[i]); } return enMultiHashOK; } template int MultiHashBase::GetValueForRead(const KeyType &input_key, ValueType *&value) { int ret = enMultiHashKeyNotFound; size_t offset = 0; unsigned int find_level = 0; size_t hash_key = HashKey(input_key); for (find_level = 0; find_level < max_level_; find_level++) { size_t index = hash_key % size_meta_[find_level]; KeyType* key_in_mem = reinterpret_cast(shm_mem_base_ + offset + (item_size_ * index)); ValueType* value_in_mem = reinterpret_cast( reinterpret_cast(key_in_mem) + sizeof(KeyType)); if (KeyCmp(input_key, *key_in_mem) == true) { uint32_t timestamp = 0; if (IsExpired(*key_in_mem, *value_in_mem, ×tamp)) { ret = enMultiHashKeyNotFound; break; } value = value_in_mem; ret = enMultiHashOK; AfterFindReadItem(*value_in_mem); break; } else if (IsEmpty(*key_in_mem, *value_in_mem) == true) { ret = enMultiHashKeyNotFound; break; } offset += size_meta_[find_level] * item_size_; } return ret; } template int MultiHashBase::GetValueForWrite(const KeyType &input_key, ValueType *&value) { int ret = enMultiHashBucketFull; ValueType * read_value_ptr; ret = GetValueForRead(input_key, read_value_ptr); if (ret == enMultiHashOK) { value = read_value_ptr; AfterFindWriteItem(*value); return ret; } size_t offset = 0; unsigned int find_level = 0; ret = enMultiHashBucketFull; size_t hash_key = HashKey(input_key); for (find_level = 0; find_level < max_level_; find_level++) { size_t index = hash_key % size_meta_[find_level]; KeyType* key_in_mem = reinterpret_cast(shm_mem_base_ + offset + (item_size_ * index)); ValueType* value_in_mem = reinterpret_cast( reinterpret_cast(key_in_mem) + sizeof(KeyType)); uint32_t timestamp = 0; if (IsEmpty(*key_in_mem, *value_in_mem) == true) { if (EmptyOccupy(input_key, *key_in_mem) == true) { memset(reinterpret_cast(value_in_mem), 0 , sizeof(ValueType)); ret = enMultiHashOK; value = value_in_mem; break; } } else if (IsExpired(*key_in_mem, *value_in_mem, ×tamp) == true) { if (ExpiredOccupy(input_key, *key_in_mem, *value_in_mem, ×tamp) == true) { memset(reinterpret_cast(value_in_mem), 0 , sizeof(ValueType)); ret = enMultiHashOK; value = value_in_mem; break; } } offset += size_meta_[find_level] * item_size_; } if (ret == enMultiHashOK) { gLog("[%s][%d]: level %d hash %llu\n", __FILE__, __LINE__, find_level, hash_key); } else { gLog("[%s][%d]: not found hash %llu\n", __FILE__, __LINE__, hash_key); } return ret; } template bool MultiHashBase::IsPrimer(size_t ullValue) { if (0 == (ullValue % 2)) { return false; } size_t ullEnd = (size_t)sqrt(ullValue) + 1; if (ullEnd > (ullValue / 2)) { ullEnd = ullValue / 2; } for (size_t i = 3; i <= ullEnd; i++) { if (0 == (ullValue % i)) { return false; } } return true; } template size_t MultiHashBase::GetBiggestPrimer( size_t ullUpperValue) { for (size_t i = ullUpperValue; i > 1; i--) { if (IsPrimer(i)) { return i; } } return 1; } } // namespace libwxfreq #endif // FREQLIB_UTIL_MULTI_HASH_BASE_H_ ================================================ FILE: util/multi_hash_table.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include "multi_hash_table.h" #include #include #include #include #include namespace libwxfreq { static size_t BKDRHash(const char *str) { unsigned int seed = 131; // 31 131 1313 13131 131313 etc.. unsigned int hash = 0; while (*str) { hash = hash * seed + (*str++); } return hash; } static size_t IntHash(uint32_t appid) { register size_t key = appid; return key * 2654435761; } MultiHashTable::MultiHashTable():init_flag_(NULL) { } MultiHashTable::~MultiHashTable() { } int MultiHashTable::MultiHashTableInit(bool zero_init, key_t shmkey, int shmflag, uint64_t item_cnt) { size_t shm_size = (size_t)(item_size() * item_cnt + 1); int iShmID = 0; iShmID = ::shmget(shmkey, shm_size, shmflag | IPC_CREAT); if (iShmID < 0 && errno == EINVAL) { // 共享内存大小发生变化 iShmID = ::shmget(shmkey, 0, 0); if (iShmID == -1) return -__LINE__; if (::shmctl(iShmID, IPC_RMID, NULL) == -1) return -__LINE__; iShmID = ::shmget(shmkey, shm_size, shmflag | IPC_CREAT); } if (iShmID <0) return -__LINE__; char *base = NULL; base = reinterpret_cast(::shmat(iShmID, NULL, 0)); if (reinterpret_cast(-1) == base) { return -__LINE__; } init_flag_ = base + shm_size - 1; if (zero_init) { memset(base, 0, shm_size); } return MultiHashInit(base, shm_size); } size_t MultiHashTable::HashKey(const KeyType &input_key) { return BKDRHash(input_key.key) * IntHash(input_key.appid); } bool MultiHashTable::KeyCmp(const KeyType &input_key, const KeyType &key_in_mem) { size_t size = sizeof(input_key.key); uint32_t input_hash = *reinterpret_cast( input_key.key + size - sizeof(uint32_t)); uint32_t mem_hash = *reinterpret_cast( key_in_mem.key + size - sizeof(uint32_t)); return input_key.appid == key_in_mem.appid && input_hash == mem_hash && strncmp(key_in_mem.key, input_key.key, size) == 0; } bool MultiHashTable::IsExpired(const KeyType &input_key, const ValueType &value, void *old_value) { *reinterpret_cast(old_value) = value.timestamp; return value.timestamp != 0 && time(NULL) - value.timestamp >= 90000; } bool MultiHashTable::IsEmpty(const KeyType &input_key, const ValueType &/*value*/) { return input_key.appid == 0; } void MultiHashTable::AfterFindReadItem(ValueType &value) { } void MultiHashTable::AfterFindWriteItem(ValueType &value) { } bool MultiHashTable::ExpiredOccupy(const KeyType &input_key, KeyType &key_in_mem, ValueType &value_in_mem, void *old_value) { if (__sync_bool_compare_and_swap(&value_in_mem.timestamp, *reinterpret_cast(old_value), 0)) { memcpy(key_in_mem.key, input_key.key, sizeof(input_key.key)); key_in_mem.appid = input_key.appid; return true; } return false; } bool MultiHashTable::EmptyOccupy(const KeyType &input_key, KeyType &key_in_mem) { if (__sync_bool_compare_and_swap(&key_in_mem.appid, 0, input_key.appid)) { memcpy(key_in_mem.key, input_key.key, sizeof(input_key.key)); return true; } return false; } bool MultiHashTable::IsValid() { return init_flag_!= NULL && *init_flag_ == 17; } void MultiHashTable::MarkAsValid() { if (init_flag_ != NULL) *init_flag_ = 17; } void MultiHashTable::MarkAsInValid() { if (init_flag_ != NULL) *init_flag_ = 0; } } // namespace libwxfreq ================================================ FILE: util/multi_hash_table.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef FREQLIB_UTIL_MULTI_HASH_TABLE_H_ #define FREQLIB_UTIL_MULTI_HASH_TABLE_H_ #include #include #include "multi_hash_base.h" #include "freq_item.h" namespace libwxfreq { #pragma pack(1) struct FreqItemForShm:public libwxfreq::FreqItem { uint32_t timestamp; }; #pragma pack() class MultiHashTable : public MultiHashBase { public: MultiHashTable(); virtual ~MultiHashTable(); public: int MultiHashTableInit(bool zero_init, key_t shmkey, int shmflag, uint64_t item_cnt); bool IsValid(); void MarkAsValid(); void MarkAsInValid(); protected: size_t HashKey(const KeyType &input_key); bool KeyCmp(const KeyType &input_key, const KeyType &key_in_mem); bool IsExpired(const KeyType &input_key, const ValueType &value, void *old_value); bool IsEmpty(const KeyType &input_key, const ValueType &value); void AfterFindReadItem(ValueType &value); void AfterFindWriteItem(ValueType &value); bool ExpiredOccupy(const KeyType &input_key, KeyType &key_in_mem, ValueType &value_in_mem, void *old_value); bool EmptyOccupy(const KeyType &input_key, KeyType &key_in_mem); private: char * init_flag_; }; } // namespace libwxfreq #endif // FREQLIB_UTIL_MULTI_HASH_TABLE_H_ ================================================ FILE: util/options.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include "options.h" namespace libwxfreq { extern LogFunc gLog; extern LoadFunc gLoadFunc; extern DumpFunc gDumpFunc; void SetLog(LogFunc log) { gLog = log; } void SetLoadFunc(LoadFunc func) { gLoadFunc = func; } void SetDumpFunc(DumpFunc func) { gDumpFunc = func; } } // namespace libwxfreq ================================================ FILE: util/options.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef FREQLIB_UTIL_OPTIONS_H_ #define FREQLIB_UTIL_OPTIONS_H_ #include "log.h" #include "reload.h" namespace libwxfreq { void SetLog(LogFunc log); void SetLoadFunc(LoadFunc func); void SetDumpFunc(DumpFunc func); } // namespace libwxfreq #endif // FREQLIB_UTIL_OPTIONS_H_ ================================================ FILE: util/reload.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include "reload.h" #include #include #include #include #include #include #include #include "freq_manager.h" #include "appid_manager.h" #include "log.h" namespace libwxfreq { static const char* kDefaultWhiteFileNamePrefix = "/tmp/libwxfreq_db."; static int LoadFromLocalFile(const char* type_name) { char filename[64]; snprintf(filename, sizeof(filename), "%s%s", kDefaultWhiteFileNamePrefix, type_name); std::ifstream ifs; ifs.open(filename, std::fstream::in); if (!ifs.is_open()) { gLog("[%s][%d]: can not open %s\n", __FILE__, __LINE__, filename); return -1; } char line[128]; std::string opname, key; uint32_t appid = 0; unsigned int expire_time = 0, block_level = 0; unsigned int now = time(NULL); while (ifs.getline(line, sizeof(line))) { std::stringstream ss(line); ss >> opname >> key >> appid >> expire_time >> block_level; if (opname == "AddWhite") { if (expire_time > now) { if (FreqManager::AddWhite(type_name, key, appid, expire_time - now) == false) { gLog("[%s][%d]: reload whitelist failed, typename %s key %s" " appid %u expiretime %u\n", __FILE__, __LINE__, type_name, key.c_str(), appid, expire_time); ifs.close(); return -1; } } } else if (opname == "DeleteWhite") { if (FreqManager::DeleteWhite(type_name, key, appid) == false) { gLog("[%s][%d]: reload deletewhite failed, typename %s key %s" " appid %u\n", __FILE__, __LINE__, type_name, key.c_str(), appid); ifs.close(); return -1; } } else if (opname == "AddBlock") { if (expire_time > now) { if (FreqManager::AddBlock(type_name, key, appid, expire_time - now, block_level) == false) { gLog("[%s][%d]: reload block failed, typename %s key %s appid %u" " expiretime %u blocklevel %u\n", __FILE__, __LINE__, type_name, key.c_str(), appid, expire_time, block_level); ifs.close(); return -1; } } } else if (opname == "DeleteBlock") { if (FreqManager::DeleteBlock(type_name, key, appid) == false) { gLog("[%s][%d]: reload deleteblock failed, typename %s key %s" " appid %u\n", __FILE__, __LINE__, type_name, key.c_str(), appid); ifs.close(); return -1; } } else { gLog("[%s][%d]: reload unknow typename %s\n", type_name); } } ifs.close(); return 0; } static int DumpToLocalFile(const char* opname, const char* type_name, const char *key, const uint32_t appid, const uint32_t linger_time, const uint32_t block_level) { char filename[64]; snprintf(filename, sizeof(filename), "%s%s", kDefaultWhiteFileNamePrefix, type_name); static std::ofstream ofs(filename, std::fstream::out | std::fstream::app); if (!ofs.is_open()) { gLog("[%s][%d]: can not open %s\n", __FILE__, __LINE__, filename); return -1; } if (linger_time <= 600) return 0; ofs << opname << "\t" << key << "\t" << appid << "\t" << time(NULL) + linger_time << "\t" << block_level << std::endl; return 0; } LoadFunc gLoadFunc = LoadFromLocalFile; DumpFunc gDumpFunc = DumpToLocalFile; } // namespace libwxfreq ================================================ FILE: util/reload.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef FREQLIB_UTIL_RELOAD_H_ #define FREQLIB_UTIL_RELOAD_H_ #include namespace libwxfreq { typedef int (*LoadFunc)(const char* type_name); typedef int (*DumpFunc)(const char* opname, const char* type_name, const char *key, const uint32_t appid, const uint32_t linger_time, const uint32_t block_level); extern LoadFunc gLoadFunc; extern DumpFunc gDumpFunc; } // namespace libwxfreq #endif // FREQLIB_UTIL_RELOAD_H_ ================================================ FILE: util/shm_freq_stat.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include "shm_freq_stat.h" #include #include #include #include #include "freq_item.h" #include "log.h" #include "reload.h" namespace libwxfreq { static uint32_t dummy_timestamp = 0; bool ShmKeyLessCmp(const FreqKey& left, const FreqKey& right) { size_t size = sizeof(left.key); uint32_t lef_hash = *reinterpret_cast( left.key + size - sizeof(uint32_t)); uint32_t right_hash = *reinterpret_cast( right.key + size - sizeof(uint32_t)); if (lef_hash < right_hash) return true; if (lef_hash > right_hash) return false; if (left.appid < right.appid) return true; if (left.appid > right.appid) return false; return strncmp(right.key, left.key, size) < 0; } uint32_t APHash(const char *str) { uint32_t hash = 0; int i; for (i=0; *str; i++) { if ((i & 1) == 0) { hash ^= ((hash << 7) ^ (*str++) ^ (hash >> 3)); } else { hash ^= (~((hash << 11) ^ (*str++) ^ (hash >> 5))); } } return (hash & 0x7FFFFFFF); } ShmFreqStat::ShmFreqStat(bool zero_init, key_t key, unsigned int item_cnt) : shrink_(false), last_shrink_time_(0), item_map_(ShmKeyLessCmp) { int ret = table_.MultiHashTableInit(zero_init, key, S_IRUSR | S_IWUSR, item_cnt); if (ret != 0) { gLog("[%s][%d]: ShmFreqStat constuct failed, key %u ret %d exit %d\n", __FILE__, __LINE__, key, ret, ret); exit(ret); } count_= 0; pthread_rwlock_init(&lock_, NULL); } void ShmFreqStat::ShrinkMap(time_t now) { if (now - last_shrink_time_ > 3600 && __sync_bool_compare_and_swap(&shrink_, false, true)) { for (ItemMap::iterator it = item_map_.begin(); it != item_map_.end(); ++it) { ItemMap::iterator dit = it; if (static_cast(now - it->second.timestamp) < 90000) { FreqItemForShm* freqitemforshm = NULL; table_.GetValueForWrite(it->first, freqitemforshm); if (freqitemforshm != NULL) { memcpy(freqitemforshm, &it->second, sizeof(FreqItemForShm)); pthread_rwlock_wrlock(&lock_); item_map_.erase(dit); pthread_rwlock_unlock(&lock_); } else { // TODO(arthurzou) } } else { pthread_rwlock_wrlock(&lock_); item_map_.erase(dit); pthread_rwlock_unlock(&lock_); } } last_shrink_time_ = now; shrink_ = false; gLog("[%s][%d]: ShmFreqStat shrinkmap type_name %s size = %u\n", __FILE__, __LINE__, type_name().c_str(), item_map_.size()); } } uint32_t& ShmFreqStat::GetItem(const std::string& key, const uint32_t appid, const uint32_t cnt, FreqItem* &freq_item) { FreqKey freqkey; freqkey.appid = appid; uint32_t* key_hash_ptr = reinterpret_cast( freqkey.key + sizeof(freqkey.key) - sizeof(uint32_t)); *key_hash_ptr = APHash(key.c_str()); strncpy(freqkey.key, key.c_str(), sizeof(freqkey.key)); time_t now = time(NULL); FreqItemForShm* freqitemforshm = NULL; if (cnt != 0) { table_.GetValueForWrite(freqkey, freqitemforshm); } else { table_.GetValueForRead(freqkey, freqitemforshm); } #ifdef USING_MAP ShrinkMap(now); if (freqitemforshm == NULL) { // sad face, find in map if (cnt != 0) { pthread_rwlock_wrlock(&lock_); freqitemforshm = &item_map_[freqkey]; table_.MarkAsInValid(); gLog("[%s][%d]: item_map_ type_name %s size %u\n", __FILE__, __LINE__, type_name().c_str(), item_map_.size()); pthread_rwlock_unlock(&lock_); freq_item = reinterpret_cast(freqitemforshm); return freqitemforshm->timestamp; } else { pthread_rwlock_rdlock(&lock_); ItemMap::iterator it = item_map_.find(freqkey); gLog("[%s][%d]: item_map_ type_name %s size %u\n", __FILE__, __LINE__, type_name().c_str(), item_map_.size()); if (item_map_.size() > 0) { table_.MarkAsInValid(); } else { table_.MarkAsValid(); } if (it == item_map_.end() || static_cast(now - it->second.timestamp) >= 90000) { freq_item = NULL; pthread_rwlock_unlock(&lock_); return dummy_timestamp; } else { freq_item = reinterpret_cast(&(it->second)); pthread_rwlock_unlock(&lock_); return it->second.timestamp; } } } else { freq_item = reinterpret_cast(freqitemforshm); if (freq_item->level3_cnt == 0) { count_++; gLog("[%s][%d]: using shm type_name %s count %u\n", __FILE__, __LINE__, type_name().c_str(), count_); } return freqitemforshm->timestamp; } #else if (freqitemforshm == NULL) { freq_item = NULL; return dummy_timestamp; } else { freq_item = reinterpret_cast(freqitemforshm); return freqitemforshm->timestamp; } #endif } ShmFreqStat::~ShmFreqStat() { } bool ShmFreqStat::TryReload() { if (!table_.IsValid()) { if (gLoadFunc(type_name_.c_str()) == 0) { table_.MarkAsValid(); return true; } else { return false; } } return true; } } // namespace libwxfreq ================================================ FILE: util/shm_freq_stat.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef FREQLIB_UTIL_SHM_FREQ_STAT_H_ #define FREQLIB_UTIL_SHM_FREQ_STAT_H_ #include #include #include #include "freq_stat.h" #include "multi_hash_table.h" namespace libwxfreq { class FreqItem; class ShmFreqStat : public FreqStat { public: ShmFreqStat(bool zero_init, key_t key, unsigned int item_cnt); virtual uint32_t& GetItem(const std::string& key, const uint32_t appid, const uint32_t cnt, FreqItem* &freq_item); virtual bool TryReload(); virtual ~ShmFreqStat(); private: typedef bool (*cmp) (const FreqKey&a, const FreqKey&b); typedef std::map ItemMap; void ShrinkMap(time_t now); ItemMap item_map_; pthread_rwlock_t lock_; unsigned int shrink_; unsigned int last_shrink_time_; unsigned int count_; MultiHashTable table_; }; } // namespace libwxfreq #endif // FREQLIB_UTIL_SHM_FREQ_STAT_H_ ================================================ FILE: util/slice.cpp ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #include "slice.h" #include #include using namespace std; namespace libwxfreq { Slice::Slice() { start_ = end_ = NULL; } Slice::Slice(const char *start, const char *end) { start_ = start; end_ = end; } Slice::Slice(const std::string &other_slice) { start_ = other_slice.c_str(); end_ = other_slice.c_str() + other_slice.size(); } std::string Slice::ToStr() const { std::string ret(start_, end_- start_); return ret; } void Slice::StrTrim(const char *delimiter) { while (start_ < end_ && strchr(delimiter, *start_) != 0) start_++; while (start_ < end_ && strchr(delimiter, *(end_-1)) != 0) end_--; } bool Slice::operator!=(const Slice &other_slice) const { return !(*this == other_slice); } bool Slice::operator==(const Slice &other_slice) const { if (end_ - start_ != other_slice.end_ - other_slice.start_) return false; return strncasecmp(start_, other_slice.start_, end_ - start_) == 0; } bool Slice::operator==(const std::string &other_slice) const { if (end_ - start_ != static_cast(other_slice.size())) return false; return strncasecmp(start_, other_slice.c_str(), end_ - start_) == 0; } bool Slice::operator<(const Slice &other_slice) const { if (start_ == other_slice.start_) return false; int minlen = end_ - start_, res = 0; if (other_slice.end_ - other_slice.start_ < minlen ) minlen = other_slice.end_ - other_slice.start_; if ((res = strncasecmp( start_, other_slice.start_, minlen )) < 0) return true; else if (res > 0) return false; else return end_ - start_ < other_slice.end_ - other_slice.start_; } } // namespace libwxfreq ================================================ FILE: util/slice.h ================================================ /* * Tencent is pleased to support the open source community by making libwxfreq available. * * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ #ifndef FREQLIB_UTIL_SLICE_H_ #define FREQLIB_UTIL_SLICE_H_ #include namespace libwxfreq { class Slice { public: Slice(); Slice(const char *start, const char *end); Slice(const std::string &other_str); std::string ToStr() const; void StrTrim(const char *delimiter); inline const char *start() const { return start_; } inline const char *end() const { return end_; } bool operator!=(const Slice &other_slice) const; bool operator==(const Slice &other_slice) const; bool operator==(const std::string &other_str) const; bool operator<(const Slice &other_slice) const; private: const char *start_, *end_; }; } // namespace libwxfreq #endif // FREQLIB_UTIL_SLICE_H_