漫话Redis源码之七十二

2024-02-06 09:38
文章标签 源码 redis 漫话 七十二

本文主要是介绍漫话Redis源码之七十二,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这里主要是枚举和配置相关的:

configEnum syslog_facility_enum[] = {{"user",    LOG_USER},{"local0",  LOG_LOCAL0},{"local1",  LOG_LOCAL1},{"local2",  LOG_LOCAL2},{"local3",  LOG_LOCAL3},{"local4",  LOG_LOCAL4},{"local5",  LOG_LOCAL5},{"local6",  LOG_LOCAL6},{"local7",  LOG_LOCAL7},{NULL, 0}
};configEnum loglevel_enum[] = {{"debug", LL_DEBUG},{"verbose", LL_VERBOSE},{"notice", LL_NOTICE},{"warning", LL_WARNING},{NULL,0}
};configEnum supervised_mode_enum[] = {{"upstart", SUPERVISED_UPSTART},{"systemd", SUPERVISED_SYSTEMD},{"auto", SUPERVISED_AUTODETECT},{"no", SUPERVISED_NONE},{NULL, 0}
};configEnum aof_fsync_enum[] = {{"everysec", AOF_FSYNC_EVERYSEC},{"always", AOF_FSYNC_ALWAYS},{"no", AOF_FSYNC_NO},{NULL, 0}
};configEnum repl_diskless_load_enum[] = {{"disabled", REPL_DISKLESS_LOAD_DISABLED},{"on-empty-db", REPL_DISKLESS_LOAD_WHEN_DB_EMPTY},{"swapdb", REPL_DISKLESS_LOAD_SWAPDB},{NULL, 0}
};configEnum tls_auth_clients_enum[] = {{"no", TLS_CLIENT_AUTH_NO},{"yes", TLS_CLIENT_AUTH_YES},{"optional", TLS_CLIENT_AUTH_OPTIONAL},{NULL, 0}
};configEnum oom_score_adj_enum[] = {{"no", OOM_SCORE_ADJ_NO},{"yes", OOM_SCORE_RELATIVE},{"relative", OOM_SCORE_RELATIVE},{"absolute", OOM_SCORE_ADJ_ABSOLUTE},{NULL, 0}
};configEnum acl_pubsub_default_enum[] = {{"allchannels", USER_FLAG_ALLCHANNELS},{"resetchannels", 0},{NULL, 0}
};configEnum sanitize_dump_payload_enum[] = {{"no", SANITIZE_DUMP_NO},{"yes", SANITIZE_DUMP_YES},{"clients", SANITIZE_DUMP_CLIENTS},{NULL, 0}
};/* Output buffer limits presets. */
clientBufferLimitsConfig clientBufferLimitsDefaults[CLIENT_TYPE_OBUF_COUNT] = {{0, 0, 0}, /* normal */{1024*1024*256, 1024*1024*64, 60}, /* slave */{1024*1024*32, 1024*1024*8, 60}  /* pubsub */
};/* OOM Score defaults */
int configOOMScoreAdjValuesDefaults[CONFIG_OOM_COUNT] = { 0, 200, 800 };/* Generic config infrastructure function pointers* int is_valid_fn(val, err)*     Return 1 when val is valid, and 0 when invalid.*     Optionally set err to a static error string.* int update_fn(val, prev, err)*     This function is called only for CONFIG SET command (not at config file parsing)*     It is called after the actual config is applied,*     Return 1 for success, and 0 for failure.*     Optionally set err to a static error string.*     On failure the config change will be reverted.*//* Configuration values that require no special handling to set, get, load or* rewrite. */
typedef struct boolConfigData {int *config; /* The pointer to the server config this value is stored in */const int default_value; /* The default value of the config on rewrite */int (*is_valid_fn)(int val, const char **err); /* Optional function to check validity of new value (generic doc above) */int (*update_fn)(int val, int prev, const char **err); /* Optional function to apply new value at runtime (generic doc above) */
} boolConfigData;typedef struct stringConfigData {char **config; /* Pointer to the server config this value is stored in. */const char *default_value; /* Default value of the config on rewrite. */int (*is_valid_fn)(char* val, const char **err); /* Optional function to check validity of new value (generic doc above) */int (*update_fn)(char* val, char* prev, const char **err); /* Optional function to apply new value at runtime (generic doc above) */int convert_empty_to_null; /* Boolean indicating if empty strings shouldbe stored as a NULL value. */
} stringConfigData;typedef struct sdsConfigData {sds *config; /* Pointer to the server config this value is stored in. */const char *default_value; /* Default value of the config on rewrite. */int (*is_valid_fn)(sds val, const char **err); /* Optional function to check validity of new value (generic doc above) */int (*update_fn)(sds val, sds prev, const char **err); /* Optional function to apply new value at runtime (generic doc above) */int convert_empty_to_null; /* Boolean indicating if empty SDS strings shouldbe stored as a NULL value. */
} sdsConfigData;typedef struct enumConfigData {int *config; /* The pointer to the server config this value is stored in */configEnum *enum_value; /* The underlying enum type this data represents */const int default_value; /* The default value of the config on rewrite */int (*is_valid_fn)(int val, const char **err); /* Optional function to check validity of new value (generic doc above) */int (*update_fn)(int val, int prev, const char **err); /* Optional function to apply new value at runtime (generic doc above) */
} enumConfigData;typedef enum numericType {NUMERIC_TYPE_INT,NUMERIC_TYPE_UINT,NUMERIC_TYPE_LONG,NUMERIC_TYPE_ULONG,NUMERIC_TYPE_LONG_LONG,NUMERIC_TYPE_ULONG_LONG,NUMERIC_TYPE_SIZE_T,NUMERIC_TYPE_SSIZE_T,NUMERIC_TYPE_OFF_T,NUMERIC_TYPE_TIME_T,
} numericType;typedef struct numericConfigData {union {int *i;unsigned int *ui;long *l;unsigned long *ul;long long *ll;unsigned long long *ull;size_t *st;ssize_t *sst;off_t *ot;time_t *tt;} config; /* The pointer to the numeric config this value is stored in */int is_memory; /* Indicates if this value can be loaded as a memory value */numericType numeric_type; /* An enum indicating the type of this value */long long lower_bound; /* The lower bound of this numeric value */long long upper_bound; /* The upper bound of this numeric value */const long long default_value; /* The default value of the config on rewrite */int (*is_valid_fn)(long long val, const char **err); /* Optional function to check validity of new value (generic doc above) */int (*update_fn)(long long val, long long prev, const char **err); /* Optional function to apply new value at runtime (generic doc above) */
} numericConfigData;typedef union typeData {boolConfigData yesno;stringConfigData string;sdsConfigData sds;enumConfigData enumd;numericConfigData numeric;
} typeData;typedef struct typeInterface {/* Called on server start, to init the server with default value */void (*init)(typeData data);/* Called on server startup and CONFIG SET, returns 1 on success, 0 on error* and can set a verbose err string, update is true when called from CONFIG SET */int (*set)(typeData data, sds value, int update, const char **err);/* Called on CONFIG GET, required to add output to the client */void (*get)(client *c, typeData data);/* Called on CONFIG REWRITE, required to rewrite the config state */void (*rewrite)(typeData data, const char *name, struct rewriteConfigState *state);
} typeInterface;typedef struct standardConfig {const char *name; /* The user visible name of this config */const char *alias; /* An alias that can also be used for this config */const unsigned int flags; /* Flags for this specific config */typeInterface interface; /* The function pointers that define the type interface */typeData data; /* The type specific data exposed used by the interface */
} standardConfig;#define MODIFIABLE_CONFIG 0 /* This is the implied default for a standard * config, which is mutable. */
#define IMMUTABLE_CONFIG (1ULL<<0) /* Can this value only be set at startup? */
#define SENSITIVE_CONFIG (1ULL<<1) /* Does this value contain sensitive information */standardConfig configs[];/*-----------------------------------------------------------------------------* Enum access functions*----------------------------------------------------------------------------*//* Get enum value from name. If there is no match INT_MIN is returned. */
int configEnumGetValue(configEnum *ce, char *name) {while(ce->name != NULL) {if (!strcasecmp(ce->name,name)) return ce->val;ce++;}return INT_MIN;
}/* Get enum name from value. If no match is found NULL is returned. */
const char *configEnumGetName(configEnum *ce, int val) {while(ce->name != NULL) {if (ce->val == val) return ce->name;ce++;}return NULL;
}/* Wrapper for configEnumGetName() returning "unknown" instead of NULL if* there is no match. */
const char *configEnumGetNameOrUnknown(configEnum *ce, int val) {const char *name = configEnumGetName(ce,val);return name ? name : "unknown";
}/* Used for INFO generation. */
const char *evictPolicyToString(void) {return configEnumGetNameOrUnknown(maxmemory_policy_enum,server.maxmemory_policy);
}/*-----------------------------------------------------------------------------* Config file parsing*----------------------------------------------------------------------------*/int yesnotoi(char *s) {if (!strcasecmp(s,"yes")) return 1;else if (!strcasecmp(s,"no")) return 0;else return -1;
}void appendServerSaveParams(time_t seconds, int changes) {server.saveparams = zrealloc(server.saveparams,sizeof(struct saveparam)*(server.saveparamslen+1));server.saveparams[server.saveparamslen].seconds = seconds;server.saveparams[server.saveparamslen].changes = changes;server.saveparamslen++;
}void resetServerSaveParams(void) {zfree(server.saveparams);server.saveparams = NULL;server.saveparamslen = 0;
}void queueLoadModule(sds path, sds *argv, int argc) {int i;struct moduleLoadQueueEntry *loadmod;loadmod = zmalloc(sizeof(struct moduleLoadQueueEntry));loadmod->argv = zmalloc(sizeof(robj*)*argc);loadmod->path = sdsnew(path);loadmod->argc = argc;for (i = 0; i < argc; i++) {loadmod->argv[i] = createRawStringObject(argv[i],sdslen(argv[i]));}listAddNodeTail(server.loadmodule_queue,loadmod);
}/* Parse an array of CONFIG_OOM_COUNT sds strings, validate and populate* server.oom_score_adj_values if valid.*/static int updateOOMScoreAdjValues(sds *args, const char **err, int apply) {int i;int values[CONFIG_OOM_COUNT];for (i = 0; i < CONFIG_OOM_COUNT; i++) {char *eptr;long long val = strtoll(args[i], &eptr, 10);if (*eptr != '\0' || val < -2000 || val > 2000) {if (err) *err = "Invalid oom-score-adj-values, elements must be between -2000 and 2000.";return C_ERR;}values[i] = val;}/* Verify that the values make sense. If they don't omit a warning but* keep the configuration, which may still be valid for privileged processes.*/if (values[CONFIG_OOM_REPLICA] < values[CONFIG_OOM_MASTER] ||values[CONFIG_OOM_BGCHILD] < values[CONFIG_OOM_REPLICA]) {serverLog(LOG_WARNING,"The oom-score-adj-values configuration may not work for non-privileged processes! ""Please consult the documentation.");}/* Store values, retain previous config for rollback in case we fail. */int old_values[CONFIG_OOM_COUNT];for (i = 0; i < CONFIG_OOM_COUNT; i++) {old_values[i] = server.oom_score_adj_values[i];server.oom_score_adj_values[i] = values[i];}/* When parsing the config file, we want to apply only when all is done. */if (!apply)return C_OK;/* Update */if (setOOMScoreAdj(-1) == C_ERR) {/* Roll back */for (i = 0; i < CONFIG_OOM_COUNT; i++)server.oom_score_adj_values[i] = old_values[i];if (err)*err = "Failed to apply oom-score-adj-values configuration, check server logs.";return C_ERR;}return C_OK;
}void initConfigValues() {for (standardConfig *config = configs; config->name != NULL; config++) {config->interface.init(config->data);}
}void loadServerConfigFromString(char *config) {const char *err = NULL;int linenum = 0, totlines, i;int slaveof_linenum = 0;sds *lines;int save_loaded = 0;lines = sdssplitlen(config,strlen(config),"\n",1,&totlines);for (i = 0; i < totlines; i++) {sds *argv;int argc;linenum = i+1;lines[i] = sdstrim(lines[i]," \t\r\n");/* Skip comments and blank lines */if (lines[i][0] == '#' || lines[i][0] == '\0') continue;/* Split into arguments */argv = sdssplitargs(lines[i],&argc);if (argv == NULL) {err = "Unbalanced quotes in configuration line";goto loaderr;}/* Skip this line if the resulting command vector is empty. */if (argc == 0) {sdsfreesplitres(argv,argc);continue;}sdstolower(argv[0]);/* Iterate the configs that are standard */int match = 0;for (standardConfig *config = configs; config->name != NULL; config++) {if ((!strcasecmp(argv[0],config->name) ||(config->alias && !strcasecmp(argv[0],config->alias)))){if (argc != 2) {err = "wrong number of arguments";goto loaderr;}if (!config->interface.set(config->data, argv[1], 0, &err)) {goto loaderr;}match = 1;break;}}if (match) {sdsfreesplitres(argv,argc);continue;}/* Execute config directives */if (!strcasecmp(argv[0],"bind") && argc >= 2) {int j, addresses = argc-1;if (addresses > CONFIG_BINDADDR_MAX) {err = "Too many bind addresses specified"; goto loaderr;}/* Free old bind addresses */for (j = 0; j < server.bindaddr_count; j++) {zfree(server.bindaddr[j]);}for (j = 0; j < addresses; j++)server.bindaddr[j] = zstrdup(argv[j+1]);server.bindaddr_count = addresses;} else if (!strcasecmp(argv[0],"unixsocketperm") && argc == 2) {errno = 0;server.unixsocketperm = (mode_t)strtol(argv[1], NULL, 8);if (errno || server.unixsocketperm > 0777) {err = "Invalid socket file permissions"; goto loaderr;}} else if (!strcasecmp(argv[0],"save")) {/* We don't reset save params before loading, because if they're not part* of the file the defaults should be used.*/if (!save_loaded) {save_loaded = 1;resetServerSaveParams();}if (argc == 3) {int seconds = atoi(argv[1]);int changes = atoi(argv[2]);if (seconds < 1 || changes < 0) {err = "Invalid save parameters"; goto loaderr;}appendServerSaveParams(seconds,changes);} else if (argc == 2 && !strcasecmp(argv[1],"")) {resetServerSaveParams();}} else if (!strcasecmp(argv[0],"dir") && argc == 2) {if (chdir(argv[1]) == -1) {serverLog(LL_WARNING,"Can't chdir to '%s': %s",argv[1], strerror(errno));exit(1);}} else if (!strcasecmp(argv[0],"logfile") && argc == 2) {FILE *logfp;zfree(server.logfile);server.logfile = zstrdup(argv[1]);if (server.logfile[0] != '\0') {/* Test if we are able to open the file. The server will not* be able to abort just for this problem later... */logfp = fopen(server.logfile,"a");if (logfp == NULL) {err = sdscatprintf(sdsempty(),"Can't open the log file: %s", strerror(errno));goto loaderr;}fclose(logfp);}} else if (!strcasecmp(argv[0],"include") && argc == 2) {loadServerConfig(argv[1], 0, NULL);} else if ((!strcasecmp(argv[0],"slaveof") ||!strcasecmp(argv[0],"replicaof")) && argc == 3) {slaveof_linenum = linenum;sdsfree(server.masterhost);if (!strcasecmp(argv[1], "no") && !strcasecmp(argv[2], "one")) {server.masterhost = NULL;continue;}server.masterhost = sdsnew(argv[1]);char *ptr;server.masterport = strtol(argv[2], &ptr, 10);if (server.masterport < 0 || server.masterport > 65535 || *ptr != '\0') {err = "Invalid master port"; goto loaderr;}server.repl_state = REPL_STATE_CONNECT;} else if (!strcasecmp(argv[0],"list-max-ziplist-entries") && argc == 2){/* DEAD OPTION */} else if (!strcasecmp(argv[0],"list-max-ziplist-value") && argc == 2) {/* DEAD OPTION */} else if (!strcasecmp(argv[0],"rename-command") && argc == 3) {struct redisCommand *cmd = lookupCommand(argv[1]);int retval;if (!cmd) {err = "No such command in rename-command";goto loaderr;}/* If the target command name is the empty string we just* remove it from the command table. */retval = dictDelete(server.commands, argv[1]);serverAssert(retval == DICT_OK);/* Otherwise we re-add the command under a different name. */if (sdslen(argv[2]) != 0) {sds copy = sdsdup(argv[2]);retval = dictAdd(server.commands, copy, cmd);if (retval != DICT_OK) {sdsfree(copy);err = "Target command name already exists"; goto loaderr;}}} else if (!strcasecmp(argv[0],"cluster-config-file") && argc == 2) {zfree(server.cluster_configfile);server.cluster_configfile = zstrdup(argv[1]);} else if (!strcasecmp(argv[0],"client-output-buffer-limit") &&argc == 5){int class = getClientTypeByName(argv[1]);unsigned long long hard, soft;int soft_seconds;if (class == -1 || class == CLIENT_TYPE_MASTER) {err = "Unrecognized client limit class: the user specified ""an invalid one, or 'master' which has no buffer limits.";goto loaderr;}hard = memtoll(argv[2],NULL);soft = memtoll(argv[3],NULL);soft_seconds = atoi(argv[4]);if (soft_seconds < 0) {err = "Negative number of seconds in soft limit is invalid";goto loaderr;}server.client_obuf_limits[class].hard_limit_bytes = hard;server.client_obuf_limits[class].soft_limit_bytes = soft;server.client_obuf_limits[class].soft_limit_seconds = soft_seconds;} else if (!strcasecmp(argv[0],"oom-score-adj-values") && argc == 1 + CONFIG_OOM_COUNT) {if (updateOOMScoreAdjValues(&argv[1], &err, 0) == C_ERR) goto loaderr;} else if (!strcasecmp(argv[0],"notify-keyspace-events") && argc == 2) {int flags = keyspaceEventsStringToFlags(argv[1]);if (flags == -1) {err = "Invalid event class character. Use 'g$lshzxeA'.";goto loaderr;}server.notify_keyspace_events = flags;} else if (!strcasecmp(argv[0],"user") && argc >= 2) {int argc_err;if (ACLAppendUserForLoading(argv,argc,&argc_err) == C_ERR) {char buf[1024];const char *errmsg = ACLSetUserStringError();snprintf(buf,sizeof(buf),"Error in user declaration '%s': %s",argv[argc_err],errmsg);err = buf;goto loaderr;}} else if (!strcasecmp(argv[0],"loadmodule") && argc >= 2) {queueLoadModule(argv[1],&argv[2],argc-2);} else if (!strcasecmp(argv[0],"sentinel")) {/* argc == 1 is handled by main() as we need to enter the sentinel* mode ASAP. */if (argc != 1) {if (!server.sentinel_mode) {err = "sentinel directive while not in sentinel mode";goto loaderr;}queueSentinelConfig(argv+1,argc-1,linenum,lines[i]);}} else {err = "Bad directive or wrong number of arguments"; goto loaderr;}sdsfreesplitres(argv,argc);}/* Sanity checks. */if (server.cluster_enabled && server.masterhost) {linenum = slaveof_linenum;i = linenum-1;err = "replicaof directive not allowed in cluster mode";goto loaderr;}/* To ensure backward compatibility and work while hz is out of range */if (server.config_hz < CONFIG_MIN_HZ) server.config_hz = CONFIG_MIN_HZ;if (server.config_hz > CONFIG_MAX_HZ) server.config_hz = CONFIG_MAX_HZ;sdsfreesplitres(lines,totlines);return;loaderr:fprintf(stderr, "\n*** FATAL CONFIG FILE ERROR (Redis %s) ***\n",REDIS_VERSION);fprintf(stderr, "Reading the configuration file, at line %d\n", linenum);fprintf(stderr, ">>> '%s'\n", lines[i]);fprintf(stderr, "%s\n", err);exit(1);
}/* Load the server configuration from the specified filename.* The function appends the additional configuration directives stored* in the 'options' string to the config file before loading.** Both filename and options can be NULL, in such a case are considered* empty. This way loadServerConfig can be used to just load a file or* just load a string. */
void loadServerConfig(char *filename, char config_from_stdin, char *options) {sds config = sdsempty();char buf[CONFIG_MAX_LINE+1];FILE *fp;/* Load the file content */if (filename) {if ((fp = fopen(filename,"r")) == NULL) {serverLog(LL_WARNING,"Fatal error, can't open config file '%s': %s",filename, strerror(errno));exit(1);}while(fgets(buf,CONFIG_MAX_LINE+1,fp) != NULL)config = sdscat(config,buf);fclose(fp);}/* Append content from stdin */if (config_from_stdin) {serverLog(LL_WARNING,"Reading config from stdin");fp = stdin;while(fgets(buf,CONFIG_MAX_LINE+1,fp) != NULL)config = sdscat(config,buf);}/* Append the additional options */if (options) {config = sdscat(config,"\n");config = sdscat(config,options);}loadServerConfigFromString(config);sdsfree(config);
}

这篇关于漫话Redis源码之七十二的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/683873

相关文章

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

音视频入门基础:WAV专题(10)——FFmpeg源码中计算WAV音频文件每个packet的pts、dts的实现

一、引言 从文章《音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道,通过FFprobe命令可以打印WAV音频文件每个packet(也称为数据包或多媒体包)的信息,这些信息包含该packet的pts、dts: 打印出来的“pts”实际是AVPacket结构体中的成员变量pts,是以AVStream->time_base为单位的显

kubelet组件的启动流程源码分析

概述 摘要: 本文将总结kubelet的作用以及原理,在有一定基础认识的前提下,通过阅读kubelet源码,对kubelet组件的启动流程进行分析。 正文 kubelet的作用 这里对kubelet的作用做一个简单总结。 节点管理 节点的注册 节点状态更新 容器管理(pod生命周期管理) 监听apiserver的容器事件 容器的创建、删除(CRI) 容器的网络的创建与删除

Redis中使用布隆过滤器解决缓存穿透问题

一、缓存穿透(失效)问题 缓存穿透是指查询一个一定不存在的数据,由于缓存中没有命中,会去数据库中查询,而数据库中也没有该数据,并且每次查询都不会命中缓存,从而每次请求都直接打到了数据库上,这会给数据库带来巨大压力。 二、布隆过滤器原理 布隆过滤器(Bloom Filter)是一种空间效率很高的随机数据结构,它利用多个不同的哈希函数将一个元素映射到一个位数组中的多个位置,并将这些位置的值置

red5-server源码

red5-server源码:https://github.com/Red5/red5-server