精华内容
下载资源
问答
  • 游戏服务器是一个较复杂的系统,涉及登录、数据存储、游戏逻辑、好友逻辑、充值,对于每个独立模块是否可以使用一个全局数组来存储,数组的中的每一个成员又是由数组构成的,一切数据结构只有数组,保证任何一个数组...
            游戏服务器是一个较复杂的系统,涉及登录、数据存储、游戏逻辑、好友逻辑、充值,对于每个独立模块是否可以使用一个全局数组来存储,数组的中的每一个成员又是由数组构成的,一切数据结构只有数组,保证任何一个数组中涉及查找的都保证有序,查找使用二分查找,这样的服务器虽然灵活性不是很大,但是这样的服务器在效率上是不是很优秀,也不需要去管理内存,是不是不错的想法呢。
    
    展开全文
  • 要求设计一个DNS的Cache结构,要求能够满足每秒5000以上的查询,满足IP数据的快速插入,查询的速度要快。(题目还给出了一系列的数据,比如:站点数总共为5000万,IP地址有1000万...可以考虑的数据结构包括hash_map,.

    在这里插入图片描述
    要求设计一个DNS的Cache结构,要求能够满足每秒5000以上的查询,满足IP数据的快速插入,查询的速度要快。(题目还给出了一系列的数据,比如:站点数总共为5000万,IP地址有1000万,等等)
    DNS服务器实现域名到IP地址的转换。
    每个域名的平均长度为25个字节(估计值),每个IP为4个字节,所以Cache的每个条目需要大概30个字节。
    总共50M个条目,所以需要1.5G个字节的空间。可以放置在内存中。(考虑到每秒5000次操作的限制,也只能放在内存中。)
    可以考虑的数据结构包括hash_map,字典树,红黑树等等。在这里插入图片描述

    展开全文
  • redis数据结构介绍

    千次阅读 2015-09-21 21:13:59
    redis不只是一个简单的键(key)-值(value)数据库,实际上它是一个数据结构服务器,支持各种类型的值。也就是说,在传统的键-值数据库中,你把字符串键与字符串值联系起来,而在redis,值不仅限于一个简单的字符串,还...

    redis不只是一个简单的键(key)-值(value)数据库,实际上它是一个数据结构服务器,支持各种类型的值。也就是说,在传统的键-值数据库中,你把字符串键与字符串值联系起来,而在redis,值不仅限于一个简单的字符串,还可以是更复杂的数据结构。下面列出了所有redis支持的数据结构,下文会分别对这些结构进行介绍:

    • 二进制安全字符串
    • 队列(lists):基于插入顺序有序存储的字符串元素集合。主要是链式的list。
    • 集(sets):元素唯一的、无序的字符串元素集合。
    • 有序集(sorted sets):与sets相似,但是每个字符串元素都与一个被称为分数(score)的浮点数相关联。和sets不同的是,元素能够基于分数排序,因此可以检索某个范围内的元素(比如你可以查询前10个或后10个)。
    • 哈希(hashes):由域(fields)和值之间关系组成的映射。域和值都是字符串。这和Ruby或Python的哈希非常相似。
    • 位数组(位图bitmaps):可以通过特殊命令,像处理位图一样地处理字符串:设置和清除某一位,统计被置1的位数,找到第一个被设置或没有被设置的位等。
    • HyperLogLogs:这是一种概率数据结构,用于估算集的势。不要被吓到了,没那么难。本文将在下文中HyperLogLog章节介绍。

    遇到问题的时候,理解数据结构是怎么工作的以及怎么被使用的并不是那么微不足道的事情。因此,这篇文档是一个关于Redis数据类型和它们常用模式的速成教材。
    这里所有的例子,我们都使用redis客户端(redis-cli)。相对于redis服务器来说,这是一个简单方便的命令行控制台。

    redis的键

    redis的键是二进制安全【1】的,也说是说,你可以使用任意的二进制序列作为键,比如字符串”foo”或一个JPEG文件的内容。
    空串也是一个有效的键。
    一些关于键的其它规则:

    • 太长的键不推荐。例如长度为1024字节的键并不好,不管是从内存角度,还是从查询键的角度。因为从数据集中查询键需要多次的键匹配步骤。即使手边的任务就是要判断一个很大的值是否存在,采用某种手段对它做hash是个好主意,尤其是从内存和带宽的角度去考虑。
    • 太短的键通常也不推荐。如果你把键“user:1000:followers”写成“u1000flw”可能会有点问题。因为前者可读性更好,而只需要多花费一点点的空间。短的键显然占的花费的空间会小一点,因此你需要找到平衡点。
    • 尽量坚持模式。例如”object-type:id”是推荐的,就像”user:1000”。点和短线常用于多个单词的场景,比如”comment:1234:reply.to”或”comment:1234:reply-to”。
    • 键的大小不能超过512MB。

    Redis中的字符串

    Redis中的字符串类型是可以与键关联的最简单的类型。它中Memcached中唯一的数据类型,也是Redis新手最常用的类型。
    由于Redis的键都是字符串,那么把使用字符串为值,也就是字符串到字符串的映射。字符串数据类型可以用于许多场景,比如缓存HTML片段或页面。
    让我们用redis客户端尝试一些字符串类型的使用吧(本文所有的例子都在redis客户端执行)。

    > set mykey somevalue
    OK
    > get mykey
    "somevalue"

    正如你所看到的,GETSET命令用于设置或获取一个字符串值。需要注意的是,如果键已经存在,SET会覆盖它的值,即使与这个键相关联的不是字符串类型的值。SET相当于赋值。
    值可以是任意类型的字符串(包含二进制数据),你也可以使用一个jpeg图像。值在大小不能大于512MB。
    SET命令配上一些额外的参数,可以实现一些有趣的功能。例如,我可以要求如果键已经存在,SET就会失败,或者相反,键已经存在时SET才会成功。

    > set mykey newval nx
    (nil)
    > set mykey newval xx
    OK

    虽然字符串是最基础的数据类型,你仍可以对它执行一些有趣的操作,比如原子性的自增:

    > set counter 100
    OK
    > incr counter
    (integer) 101
    > incr counter
    (integer) 102
    > incrby counter 50
    (integer) 152

    INCR命令把字符串解析成一个整数,然后+1,把得到的结果作为一个新值存进去。还有其它相似的命令:INCRBY, DECR, DECRBY。从命令的实现原理上讲,这几个命令是相同的,只是有一点细微的差别。
    为什么说INCR是原子性的呢?因为即使是多个客户端对同一个键使用INCR命令,也不会形成竞争条件。举个例子,像这样的情况是不会发生的:客户端1读取到键是10,客户端2也读到键值是10,它们同时对它执行自增命令,最终得到的值是11。实际上,最终的得到的值是12,因为当一个客户端对键值做读-自增-写的过程中,其它的客户是不能同时执行这个过程的。
    有许多用于操作字符串的命令,例如GETSET命令,它给键设置一个新值,并返回旧值。比如你有一个系统,每当有一个新的访问者登陆你的网站时,使用INCR对一个键值自增。你可能想要统计每个小时的信息,却又不希望丢失每次自增操作。你可以使用GETSET命令,设置一个新值“0”,同时读取旧值。
    redis支持通过一条命令同时设置或读取多个键,这对于减少延时很有用。这就是MSET命令和MGET命令:

    > mset a 10 b 20 c 30
    OK
    > mget a b c
    1) "10"
    2) "20"
    3) "30"

    使用MGET时,redis返回包含多个值的数组。

    更改或查询键空间

    【2】
    有些命令并没有指定特定的类型,但在与键空间的交互有非常有用,因此可以用于任意类型的键。
    举个例子,EXISTS命令返回1或者0,用于表示某个给定的键在数据库中是否存在。DEL命令删除键以及它对应的值而不管是什么值。

    > set mykey hello
    OK
    > exists mykey
    (integer) 1
    > del mykey
    (integer) 1
    > exists mykey
    (integer) 0

    DEL返回1还是0取决于键是(键存在)否(键不存在)被删除掉了。
    有许多键空间相关的命令,但以上这两个命令和TYPE命令是最基本的。TYPE命令的作用是返回这个键的值的类型。

    > set mykey x
    OK
    > type mykey
    string
    > del mykey
    (integer) 1
    > type mykey
    none

    键的生命周期

    在介绍更多更复杂的数据结构之间,我们先讨论另一个与值类型无关的特性,那就是redis的期限(redis expires)。最基本的,你可以给键设置一个超时时间,就是这个键的生存周期。当生存周期过去了,键会被自动销毁,就好像被用户执行过DEL一样。
    一些关于redis期限的快速信息:

    • 生存周期可以设置的时间单位从秒级到毫秒级。
    • 生存周期的时间精度都是1毫秒。
    • 关于生存周期的数据有多份且存在硬盘上,基于Redis服务器停止了,时间仍在流逝,这意味着redis存储的是key到期的时间。

    设置生存周期是件琐碎的事情:

    > set key some-value
    OK
    > expire key 5
    (integer) 1
    > get key (immediately)
    "some-value"
    > get key (after some time)
    (nil)

    键在两次调用之间消失了,这是因为第二次调用的延迟了超过5秒的时间。在上面的例子中,我们使用EXPIRE命令设置生命周期(它也可以用于为一个已经设置过生命周期的键重新设置生命周期,PERSIST命令可以用于移除键的命令周期,使它能够长期存在)。我们还可以使用redis命令在创建键的同时设置生命周期。比如使用带参数的SET命令:

    > set key 100 ex 10
    OK
    > ttl key
    (integer) 9

    上面这个例子中创建了一个键,它的值是字符串100,生命周期是10秒。后面的TTL命令用于查看键的剩余时间。
    如果要以毫秒为单位设置或查询键的生命周期,请查询PEXPIRE命令和PTTL命令,以及SET命令的参数列表。

    redis中的列表(lists)

    要解释列表数据类型,最好先从一点理论开始。因为列表这个术语常被信息技术人员错误地使用。例如“python 列表”,并不像它的命令所提示的(链表),而是数组(实际上与Ruby中的数组是同一个数据类型)。
    从广义上讲,列表只是元素的有序序列:10,20,1,2,3是一个列表。但是用数组实现的列表和用链表实现的列表,它们的属性有很大的不同。
    redis的列表都是用链表的方式实现的。也就是说,即使列表中有数百万个元素,增加一个新元素到列表头部或尾部操作的执行时间是常数时间。使用LPUSH命令把一个新元素增加到一个拥有10个元素的列表的头部,或是增加到一个拥有一千万个元素的列表的头部,其速度是一样的。
    缺点是什么呢?通过索引访问一个元素的操作,在数组实现的列表中非常快(常数时间),但在链表实现的列表中不是那么快(与找到元素对应下标的速度成比例)。
    redis选择用链表实现列表,因为对于一个数据库来说,快速地向一个很大的列表新增元素是非常重要的。另一个使用链表的强大优势,你稍后将会看到,能够在常数时间内得到一个固定长度的redis列表。
    快速地读取很大一堆元素的中间元素也是重要的,这时可以使用另一种数据结构,称为有序集(sorted sets)。本文后面会讲到有序集。

    regis列表第一步

    LPUSH命令把一个新的元素加到列表的左边(头部),而RPUSH命令把一个新的元素加到列表的右边(尾部)。LRANGE命令从列表中提取某个范围内的元素

    > rpush mylist A
    (integer) 1
    > rpush mylist B
    (integer) 2
    > lpush mylist first
    (integer) 3
    > lrange mylist 0 -1
    1) "first"
    2) "A"
    3) "B"

    注意,LRANGE命令需要输入两个下标,即范围的第一个元素下标和最后一个元素下标。两个下标都可以是负的,意思是从尾部开始数:因此-1是最后一个元素,-2是倒数第二个元素,等。
    正如你所见,RPUSH把元素加到列表右边,LPUSH把元素加到列表左边。所有命令的参数都是可变的,即你可以随意地把多个增加元素入列表的命令放到一次调用中:

    > rpush mylist 1 2 3 4 5 "foo bar"
    (integer) 9
    > lrange mylist 0 -1
    1) "first"
    2) "A"
    3) "B"
    4) "1"
    5) "2"
    6) "3"
    7) "4"
    8) "5"
    9) "foo bar"

    Redis中定义了一个重要的操作就是删除元素。删除命令可以同时从列表中检索和删除元素。你可以从左边或者右边删除元素,和从两边增加元素的方法类似:

    > rpush mylist a b c
    (integer) 3
    > rpop mylist
    "c"
    > rpop mylist
    "b"
    > rpop mylist
    "a"

    我们增加和删除的三个元素,因此最后列表是空的,没有元素可以删除。如果我们尝试继续删除元素,会得到这样的结果:

    > rpop mylist
    (nil)

    redis返回空值说明列表中没有元素了。

    列表的常见用例

    列表可以用于完成多种任务,以下是两个非常有代表性的用例:

    • 记住用户发布到社交网络的最新更新。
    • 使用消费者-生产者模型进行进程间通信,生产生把表项(items)放进列表中,消费者(通常是工作者)消费这些items并执行一些行为。redis针对这种用例有一些特殊的列表命令,既可靠又高效。

    例如非常有名的Ruby库resquesidekip,在底层都使用了Redis列表来实现后台作业。
    著名的社交网络Twitter使用Redis列表来获取用户发布的最新的消息。
    为了一步一步地描述一个常见用例,假设要在你的主页上展示社交网络上最新分享的照片并且加速访问。

    • 每当一个用户发布了一张新的照片,我们使用LPUSH命令把它的ID加入到列表中。
    • 当用户访问这个主页,我们使用LRANGE 0 9获取最新加入的10个表项。

    限制列表

    很多情况下我们只想要使用列表来存储最新的几条表项,例如社交网络更新、日志或者其它。
    Redis允许我们使用列表作为一个固定集合,使用LTRIM命令,只记录最新的N条记录,而丢弃所有更早的记录。
    LTRIM命令和LRANGE命令相似,但不像LRANGE一样显示特定范围的元素,而是用这个范围内的值重新设置列表。所有范围外的元素都被删除了。
    用个例子来说明这一点:

    > rpush mylist 1 2 3 4 5
    (integer) 5
    > ltrim mylist 0 2
    OK
    > lrange mylist 0 -1
    1) "1"
    2) "2"
    3) "3"

    上面的LTRIM命令告诉Redis只取得列表中下标为0到2的元素,其它的都要丢弃。这就是一种简单有用的模式成为了可能:列表增加(push)元素操作+列表提取(trim)元素操作=增加一个元素同时删除一个元素使得列表元素总数有限:

    LPUSH mylist <some element>
    LTRIM mylist 0 999

    上面的操作结合增加一个元素但只是存在1000个最新的元素在列表中。通过LRANGE你可以获取最新的表项而不需要记住旧的数据。
    注意:由于理论上LRANGE是O(N)命令,读取从头开始或从尾开始的小范围数据是常数时间的操作。

    列表中是阻塞型操作

    列表的一些特性使它适合现实队列(queues),也通常作为进程间通信系统的一个基础组件:阻塞式操作。
    假设你通过一个进程把元素增加到列表中,使用另一个进程对这些元素做些实际的操作。这是通常的生产者/消费者基础,你可以用下面这种简单的方法实现:

    • 生产者调用LPUSH,把元素加入列表
    • 消费者调用RPOP,把元素从列表中取出或处理

    有没有可能出现这种情况,列表是空的,没有什么东西可以处理,因此RPOP返回NULL。这种情况下,消费者不得不等一会再尝试RPOP。这就叫轮询。这并不是一个好方法,因为它有以下缺点:

    1. 要求redis和客户端执行没有意义的命令(当列表为空是所有的请求都不会执行实际工作,只是返回NULL)
    2. 工作者在收到NULL之后加入一个延时,让它等待一些时间。如果让延时小一点,在两次调用RPOP之间的等待时间会比较短,这成为第一个问题的放大-调用Redis更加没有意义

    因此Redis实现了命令BRPOPBLPOP,它是RPOPLPOP的带阻塞功能的版本:当列表为空时,它们会等到一个新的元素加入到列表时,或者用户定义的等待时间到了时,才会返回。
    这是BRPOP调用的一个例子,我们可以在工作者进程使用它:

    > brpop tasks 5
    1) "tasks"
    2) "do_something"

    它的意思是:等待列表中的元素,如果5秒还没有可用的元素。
    注意,如果使用0作为超时时间,将会永远等待,你也可以定义多个列表而不只是一个,这样就会同时等待多个列表,当任意一个列表收到一个元素时就会收到通知。
    一些关于BRPOP需要注意的事情:

    1. 客户端是按顺序被服务的:第一个等待某个列表的客户端,当列表被另一个客户端增加一个元素时,它会第一个处理。
    2. 返回值与RPOP的不同:只得到两个元素的包含键名的数组,因为BRPOP和BLPOP因为等待多个列表而阻塞。
    3. 如果时间超时了,就会返回NULL

    还有更多你应该知道的关于列表和阻塞操作的东西。我们建议你阅读以下材料:

    • 可以使用RPOPLPUSH创建更安全的队列或旋转队列。
    • 这个命令有一个阻塞参数,即BRPOPLPUSH

    自动创建和移除键

    到目前为止我们的例子还没有涉及到这些情景,在增加一个元素之间创建一个空的列表,或者当一个列表没有元素时把它移除。redis有责任删除变为空的列表,或当我们试图增加元素时创建空列表。例如LPUSH
    这不仅适用于列表,它可以应用于所有包含多个元素的Redis数据结构-集、有序集和哈希。
    基本上讲,我们把它的行为总结为三个规则:

    1. 当我们把一个元素增加到一个集合类数据类型时,如果这个键不存在,在增加前会创建一个空的集合类数据类型。
    2. 我们从一个集合类数据类型中移除一个元素时,如果值保持为空,键就会被自动删除
    3. 调用一个只读命令例如LLEN(返回列表的长度),或者一个移除元素的写命令但键为空,结果不会改变。[3]

    规则1举例:

    > del mylist
    (integer) 1
    > lpush mylist 1 2 3
    (integer) 3

    然而,我们不能对一个已经存在的键执行与它类型不同的操作:

    > set foo bar
    OK
    > lpush foo 1 2 3
    (error) WRONGTYPE Operation against a key holding the wrong kind of value
    > type foo
    string

    规则2举例:

    > lpush mylist 1 2 3
    (integer) 3
    > exists mylist
    (integer) 1
    > lpop mylist
    "3"
    > lpop mylist
    "2"
    > lpop mylist
    "1"
    > exists mylist
    (integer) 0

    当所有元素被取出,这个键就不存在了。
    规则3举例:

    > del mylist
    (integer) 0
    > llen mylist
    (integer) 0
    > lpop mylist
    (nil)

    redis中的哈希(hashed)

    redis的哈希和我们所认识的“哈希”非常相似,是域-值对。

    > hmset user:1000 username antirez birthyear 1977 verified 1
    OK
    > hget user:1000 username
    "antirez"
    > hget user:1000 birthyear
    "1977"
    > hgetall user:1000
    1) "username"
    2) "antirez"
    3) "birthyear"
    4) "1977"
    5) "verified"
    6) "1"

    hash表示对象(object)非常方便。实际上,可以放入一个hash的域的数量没有限制(不考虑可用内存),因此你可以在你的应用中用许多不同的方式使用哈希。
    HMSET命令为hash设置多个域,而HGET获取某一个域。HMGETHGET相似,但它返回由值组成的数组。

    > hmget user:1000 username birthyear no-such-field
    1) "antirez"
    2) "1977"
    3) (nil)

    还有一些命令可以对单个的域执行操作,例如HINCRBY

    > hincrby user:1000 birthyear 10
    (integer) 1987
    > hincrby user:1000 birthyear 10
    (integer) 1997

    你可以查看这篇文档《hash命令全列》
    把小的哈希(少量的元素,较小的值)用特殊的编码方式存放在内存中并不是什么难事,因此它们的空间效率非常高。

    redis的集(sets)

    Redis的集是字符串无序的集合。SADD向集中增加一些元素。对于集合还有很多其它的操作,例如测试某个给定的元素是否存在,多个集合之间求交集、合集或者差集,等。

    > sadd myset 1 2 3
    (integer) 3
    > smembers myset
    1. 3
    2. 1
    3. 2

    在这个例子中,我向myset中增加了三个元素,并让redis返回所有的元素。正如你所看到的,它们是无序的。每次调用,redis都可能以任何顺序返回元素,因此在这里,用户不能对元素的顺序有要求。
    redis提供测试成员的命令。这个给定的元素是否存在?

    > sismember myset 3
    (integer) 1
    > sismember myset 30
    (integer) 0

    “3”是这个集中的一员,而“30”不是。
    集善于表现对象之间的关系。例如我们可以很容易使用集实现标签(tags)。处理这个问题的一个简单的模型就是把所有要打标签的对象设置一个集。集包含相关对象的标签的ID。
    假设我们想要为新闻加标签。ID为1000的新闻被打上1,2,5和77这几个标签,我们可以用一个集将这些标签ID与新闻关联起来:

    > sadd news:1000:tags 1 2 5 77
    (integer) 4

    然而有时我会想要相反的关系:列表中的所有新闻都被打上一个给定的标签:

    > sadd tag:1:news 1000
    (integer) 1
    > sadd tag:2:news 1000
    (integer) 1
    > sadd tag:5:news 1000
    (integer) 1
    > sadd tag:77:news 1000
    (integer) 1

    要获取一个对象的所有标签是很麻烦的。

    > smembers news:1000:tags
    1. 5
    2. 1
    3. 77
    4. 2

    注意:在这个例子中我们假设你还有另一个数据结构,例如redis的哈希,用于标签ID到标签名的映射。
    如果使用正确的redis命令,可以通过并不繁琐却简单的方式去实现。例如我们可能想到同时拥有1,2,10和27标签的所有对象。我们可以使用SINTER命令执行不同集之间的求交运算。我们可以这么用:

    > sinter tag:1:news tag:2:news tag:10:news tag:27:news
    ... results here ...

    求交集运算不是唯一可以执行的操作,你还可以执行求并集运算、求差集运算、提取任意一个元素等。
    提取一个元素的命令是SOP,它对于模拟某些问题很方便。例如要实现一个基于网页的扑克牌游戏,你可能会把你的牌(deck)做成一个集。假设我们使用一个字符前缀来表示C(梅花)、D(方块)、H(红心)、S(黑桃):

    >  sadd deck C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 CJ CQ CK
       D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 DJ DQ DK H1 H2 H3
       H4 H5 H6 H7 H8 H9 H10 HJ HQ HK S1 S2 S3 S4 S5 S6
       S7 S8 S9 S10 SJ SQ SK
       (integer) 52

    现在我们给每个玩家提供5张牌。SPOP命令移除一个随机的元素,并把它返回给客户端,因此在这个用例中是最好的操作。
    然后如果我们直接对deck调用它,下一轮游戏我们需要把再次填写所有的牌,这还不够理想。因此在开始之前,先把集中存储的deck键做一个备份到game中。使用SUNIONSTORE来实现,把结果存到另一个集中。这个命令通常是对多个集做求并集运行的。对一个集求并集运算就是它自己,因此可以用于复制:

    > sunionstore game:1:deck deck
    (integer) 52

    现在我已经准备好为第一个玩家发五张牌了。

    > spop game:1:deck
    "C6"
    > spop game:1:deck
    "CQ"
    > spop game:1:deck
    "D1"
    > spop game:1:deck
    "CJ"
    > spop game:1:deck
    "SJ"

    一对J,不太好。。。
    现在是时候介绍集中元素个数的命令了。在集理论中,元素个数常被为集的势,因此这个命令是SCARD

    > scard game:1:deck
    (integer) 47

    计算公式:52-5=47
    如果你只是想得到一个随机的元素但不把它从集中删除,SRANDMEMBER命令适合这个任务。它还可以提供返回重复元素或非重要元素的功能。

    Redis的有序集

    有序集像一种将集和哈希混合的数据类型。像集一样,有序集由唯一的不重复的字符串元素组成。因此某种意义上说,有序集也是一个集。
    集中的元素是无序的,而有序集中的元素都基于一个相关联的浮点值排序。这个浮点值称为分数(score)(每个元素都映射到一个值,因此和哈希相似)。
    此外,有序集中的元素是按顺序取的(它们不是按照要求排序的,排序是这个数据结构用于表现有序集的一个特性【4】)。它们按照下面的规则排序:

    • 假设A和B是分值不同的两个元素,如果A的分数>B的分数,则A>B
    • 假设A和B的分值相同,如果字符串A的字典序大于字符串B的字典序,则A>B。A和B两个字符串不可能相同,因为有序集的元素是唯一的。

    我们从一个简单的例子开始,向有序集增加一些黑客的名字,将它们的出生年份作为“分数”。

    > zadd hackers 1940 "Alan Kay"
    (integer) 1
    > zadd hackers 1957 "Sophie Wilson"
    (integer 1)
    > zadd hackers 1953 "Richard Stallman"
    (integer) 1
    > zadd hackers 1949 "Anita Borg"
    (integer) 1
    > zadd hackers 1965 "Yukihiro Matsumoto"
    (integer) 1
    > zadd hackers 1914 "Hedy Lamarr"
    (integer) 1
    > zadd hackers 1916 "Claude Shannon"
    (integer) 1
    > zadd hackers 1969 "Linus Torvalds"
    (integer) 1
    > zadd hackers 1912 "Alan Turing"
    (integer) 1

    正如你所见,ZADDSADD相似,但是需要一个额外的参数(位置在要加的元素之前),这就是分数。ZADD也是参数可变的,你可以随意地定义多个“分数-值”对,虽然上面的例子没有这么写。
    要求有序集中的黑客名单按他们的出生年份排序是没有意义的,因为它们已经是这样的了。
    实现细节:有序集是基于一个双端口数据结构实现的,包含一个跳跃表和一个哈希表。因此增加一个元素的执行时间是O(log(N))。这很好,当我们请求有序的元素时不需要其它的工作,它们已经是排序的了:

    > zrange hackers 0 -1
    1) "Alan Turing"
    2) "Hedy Lamarr"
    3) "Claude Shannon"
    4) "Alan Kay"
    5) "Anita Borg"
    6) "Richard Stallman"
    7) "Sophie Wilson"
    8) "Yukihiro Matsumoto"
    9) "Linus Torvalds"

    注意:0和-1的意思是从下标为0的元素开始到最后一个元素(这里的-1和LRANGE命令中的-1一样)。
    如果想要反向排序,从最年轻到最老呢?使用ZREVERANGE代替ZRANGE

    > zrevrange hackers 0 -1
    1) "Linus Torvalds"
    2) "Yukihiro Matsumoto"
    3) "Sophie Wilson"
    4) "Richard Stallman"
    5) "Anita Borg"
    6) "Alan Kay"
    7) "Claude Shannon"
    8) "Hedy Lamarr"
    9) "Alan Turing"

    也可以同时返回分数,使用WITHSCORES参数:

    > zrange hackers 0 -1 withscores
    1) "Alan Turing"
    2) "1912"
    3) "Hedy Lamarr"
    4) "1914"
    5) "Claude Shannon"
    6) "1916"
    7) "Alan Kay"
    8) "1940"
    9) "Anita Borg"
    10) "1949"
    11) "Richard Stallman"
    12) "1953"
    13) "Sophie Wilson"
    14) "1957"
    15) "Yukihiro Matsumoto"
    16) "1965"
    17) "Linus Torvalds"
    18) "1969"

    基于范围的操作

    有序集的功能强大远不止这些。它还可以基于范围操作。我们要取得所有出生年份早于(包括)1950年的人,就使用ZRANGEBYSCORE命令来实现:

    > zrangebyscore hackers -inf 1950
    1) "Alan Turing"
    2) "Hedy Lamarr"
    3) "Claude Shannon"
    4) "Alan Kay"
    5) "Anita Borg"

    我们请求Redis返回所有分数在无限到1950(两边都是闭区间)之间的元素。
    也可以移除某个范围内的元素。我们要从有序集中移除所有出生年份在1940和1960之间的黑客:

    > zremrangebyscore hackers 1940 1960
    (integer) 4

    ZREMRANGEBYSCORE命令的名字也许不是很好,但是真的很有用,它返回被移除的元素的个数。
    另一个为有序集元素定义的非常有用的操作是获取排名(get-rank)操作。可以询问一个元素在它的有序集中的位置。

    > zrank hackers "Anita Borg"
    (integer) 4

    ZREVRANK命令也可以获取排名,不过元素是逆序排序的。

    字典序的分数

    最近的Redis 2.8版本引入了一个新特性,假设有序集中所有元素的分数相同(使用C语言的memcmp函数来比较元素,这样保证每个redis实例都会返回相同的结果)的情况下,允许按照字典序获得范围。【5】
    针对字典序范围操作的主要命令是ZRANGEBYLEXZREVRANGEBYLEXZREMRANGEBYLEXZLEXCOUNT
    举个例子,我们再次把所有著名黑客加入到列表中,但这一次所有元素的分数都是0:

    > zadd hackers 0 "Alan Kay" 0 "Sophie Wilson" 0 "Richard Stallman" 0
      "Anita Borg" 0 "Yukihiro Matsumoto" 0 "Hedy Lamarr" 0 "Claude Shannon"
      0 "Linus Torvalds" 0 "Alan Turing"

    基于有序集的排序规则,它们是字典序排序的:

    > zrange hackers 0 -1
    1) "Alan Kay"
    2) "Alan Turing"
    3) "Anita Borg"
    4) "Claude Shannon"
    5) "Hedy Lamarr"
    6) "Linus Torvalds"
    7) "Richard Stallman"
    8) "Sophie Wilson"
    9) "Yukihiro Matsumoto"

    我们可以使用ZRANGEBYLEX命令请求字典序的范围:

    > zrangebylex hackers [B [P
    1) "Claude Shannon"
    2) "Hedy Lamarr"
    3) "Linus Torvalds"

    范围是开区间还是闭区间都可以(由第一个字符决定),字符串正无穷和负无穷分别通过+和-来定义。更多信息请查看文档。
    这个特性很重要,它使得我们使用有序集作为一个通常索引。举个例子,如果你想要使用一个128位的无符号整数来为元素索引,你所要做的只是把元素加入到一个有序集并设置一个相同的分数(比如0)以及一个由128位数值组成的8字节前缀。由于数值是大端的,字典序的顺序(原始字节序)实际上是数字序的,你可以在128位空间请求范围,以前缀降序返回元素的值。
    如果你想查看这个特性更严谨的演示,请查看 Redis autocomplete demo.

    更新分数:排行榜

    这是在切换到下一个话题之前最后一个关于有序集的点。有序集的分数可以随时被更新。只需要对一个在有序集中已经存在的元素执行ZADD就可以在O(log(N))更新它的分数(和位置)。同样的,当会经常更新时使用有序集非常合适。
    这个特性的一个通常用例是排行榜。典型的应用是Facebook的一个游戏,你可以使用户基于它们的高分排序,增加获取排名的操作,在排行榜上显示前N个用户及用户排名(例:你是第4932好的分数)

    位图

    位图其实不是一个真正的数据类型,只是在这种字符串类型上有一系列基于位的操作。由于字符串是二进制安全的,最大长度是512MB,因此可以设置多达2^32种不同的位串。
    位操作分为两类,一种是针对某一个位的常数时间操作,如果设置某个位为1或0,或获取某个位的值。另一种是对所有位的操作,例如计算一个给定范围内被设置为1的位的个数(如人数统计)。
    位图一个最大的优势就是存储信息时非常少空间。例如一个系统里面每个用户用一个不同的递增的用户ID表示,可以记录40亿用户的某个信息(这个用户是否想要接收邮件)只需要512M的内存。
    通过SETBIT命令和GETBIT命令设置或获取位:

    > setbit key 10 1
    (integer) 1
    > getbit key 10
    (integer) 1
    > getbit key 11
    (integer) 0

    SETBIT命令把第一个参数作为位的序号,第二个参数作为这个位要设置的值,只能是1或0。如果地址位大于当前字符串的长度,这个命令会自动扩充字符串。
    GETBIT只返回位于某个位置的值。超过长度的位(地址位大于字符串的长度)将必然得到0。
    这三个命令是对所有位的操作:

    1. BITOP:执行不同字符串之间的位操作。包括AND、OR、XOR和NOT。
    2. BITCOUNT:执行统计操作,返回位集中1的个数
    3. BITPOS:找到第一个被设置为0或1的位置

    BITPOSBITCOUNT都可以接受位的地址范围作为参数,这样就不对对整个字符串做操作。下面是一个关于BITCOUNT的简单例子:

    > setbit key 0 1
    (integer) 0
    > setbit key 100 1
    (integer) 0
    > bitcount key
    (integer) 2

    位图的通常用法:

    • 各种实时分析
    • 存储要求空间时间高效的与对象ID关联的二进制信息。

    假如你想知道你的网页用户中每天访问最长的时间【6】,你从开始记录天数,你把你的网页公开化的第一天开始,计数为0,然后每当有用户用户网页,使用SETBIT设置一位。位的下标可以简单的认为是当前系统时间,减去第一天得到偏移,然后除以3600*24。
    使用这种方式,对于每一个用户,你有一个包含每天访问信息的字符串来表示。使用BITCOUNT命令可以得到某个用户访问网页的天数。而使用多个BITOPs调用,可能简单地获取和分析位图,就很容易地计算出longest streak。
    为了共享数据或避免对一个很大的键操作,bitmap可以分裂成多个键。要把一个位图分裂成多个键而不是全部设置到一个键里面去,一个比较麻烦的方法就是让每个键存储M位,键名为键的数量/M,第N个位在这个键里的地址是数的位置%M。

    HyperLogLogs

    HyperLogLogs是一个概率性的数据结构,用于计算特别的东西(技术上常用于估算一个集的势)。通过计算一个特别的表项需要使用相对于要计算的表项本身来说很大的内存,因为需要记住你已经见过的元素,以免重复计算。然后有一系列算法可以按精度使用内存:在redis的实现中,你最终得到一个标准错误的估计测量结果的可能性少于1%【7】。这个算法的神奇之处在于你再大需要相对于要计算的表项本身来说很大的内存空间,可能是只使用一个常数数量的空间。最坏情况下12K字节,如果元素少的话,这个空间会更小。
    Redis中的HLL,从技术上讲,它是一个完全不同的数据结构,但像字符串一样编码,因此你可以使用GET来串行化一个HLL,使用SET并行到服务器。
    从概念上讲,HLL的接口使用集来完成相同的工作。你会使用SADD把每一个观测值写入集中,使用SCARD来查询集中的元素个数。因为SADD不会重复添加一个已存在的元素,因此集中的元素是唯一的。
    但是你不能把一个表项真正地添加入一个HLL,因为数据结构只包含并不真正存在的元素的状态,API是一样的:

    • 每当你看见一个新的元素,使用PFADD计数增加
    • 每当你想要恢复当前的近似值,使用PFCOUNT。【8】
    > pfadd hll a b c d
    (integer) 1
    > pfcount hll
    (integer) 4

    使用这种数据结构的一个例子统计在一个调整中用户每天执行的请求数。
    Redis还可以对HLL执行求并集操作,请查询完整文件获取更多信息。

    其它显著的特性

    关于redis的接口,还有其它一些重要的信息不能放在这个文档中,但是非常值得引起你的注意:

    • 可以递增地迭代键空间
    • 可以在服务器端运行LUA脚本获取潜在因素和带宽
    • redis还是一个发布-订阅型服务器

    更多

    这篇教程不可能很完整,只是覆盖了一些基础的API。读《命令参数》获取更多信息。
    感谢阅读本文,祝你redis之旅愉快。

    参考文献:
    【1】什么是二进制安全?
    答:http://www.cnblogs.com/lovevivi/p/3159132.html
    【2】什么是键空间?
    【3】这句话看不懂,原文如下
    Calling a read-only command such as LLEN (which returns the length of the list), or a write command removing elements, with an empty key, always produces the same result as if the key is holding an empty aggregate type of the type the command expects to find.
    【4】原文
    so they are not ordered on request, order is a peculiarity of the data structure used to represent sorted sets。
    【5】原文
    With recent versions of Redis 2.8, a new feature was introduced that allows getting ranges lexicographically, assuming elements in a sorted set are all inserted with the same identical score (elements are compared with the C memcmp function, so it is guaranteed that there is no collation, and every Redis instance will reply with the same output).
    【6】原文
    For example imagine you want to know the longest streak of daily visits of your web site users.
    【7】原文
    you end with an estimated measure with a standard error, in the case of the Redis implementation, which is less than 1%
    【8】 Every time you want to retrieve the current approximation of the unique elements added with PFADD so far, you use thePFCOUNT.

    展开全文
  • web服务器之mongoose:数据结构

    千次阅读 2016-06-13 18:22:40
    Mongoose中有几个数据结构扮演着重要的角色,它们分别是: struct mg_context:保存Mongoose的上下文,几乎每个函数都有mg_context参数 struct mg_connection:保存HTPP连接信息 struct mg_request_info:保存...

    Mongoose中有几个数据结构扮演着重要的角色,它们分别是:

    struct mg_context:保存Mongoose的上下文,几乎每个函数都有mg_context参数

    struct mg_connection:保存HTPP连接信息

    struct mg_request_info:保存HTTP请求的信息,这个结构体传递给URL处理函数

     

    我之所以现在这里介绍它,因为之后的分析工作中要用到它们,如果在读完本文后还不能很好的理解,请将问题带到后续文章中或代码分析中去,你会找到答案的。下面分别介绍它们。

    本文的主要内容如下:

    1、mg_context详解

    2、mg_connection详解

    3、mg_request_info详解

    4、其他数据结构

    5、总结

     

    1、mg_context详解

     

    mg_context结构体——表示Mongoose的上下文,也称为一个实例句柄。它的成员如下:

    1. struct mg_context {
    2.     int        stop_flag;    /* Should we stop event loop    */
    3.     SSL_CTX        *ssl_ctx;    /* SSL context            */
    4.  
    5.     FILE        *access_log;    /* Opened access log        */
    6.     FILE        *error_log;    /* Opened error log        */
    7.  
    8.     struct socket    listeners[MAX_LISTENING_SOCKETS];
    9.     int        num_listeners;
    10.  
    11.     struct callback    callbacks[MAX_CALLBACKS];
    12.     int        num_callbacks;
    13.  
    14.     char        *options[NUM_OPTIONS];    /* Configured opions    */
    15.     pthread_mutex_t    opt_mutex[NUM_OPTIONS];    /* Option protector    */
    16.  
    17.     int        max_threads;    /* Maximum number of threads    */
    18.     int        num_threads;    /* Number of threads        */
    19.     int        num_idle;    /* Number of idle threads    */
    20.     pthread_mutex_t    thr_mutex;    /* Protects (max|num)_threads    */
    21.     pthread_cond_t    thr_cond;
    22.     pthread_mutex_t    bind_mutex;    /* Protects bind operations    */
    23.  
    24.     struct socket    queue[20];    /* Accepted sockets        */
    25.     int        sq_head;    /* Head of the socket queue    */
    26.     int        sq_tail;    /* Tail of the socket queue    */
    27.     pthread_cond_t    empty_cond;    /* Socket queue empty condvar    */
    28.     pthread_cond_t    full_cond;    /* Socket queue full condvar    */
    29.  
    30.     mg_spcb_t    ssl_password_callback;
    31.     mg_callback_t    log_callback;
    32. };

    这个结构体在mg_start()中创建和初始化,其它函数大部分都会用它。因此mg_start()应该首先被调用。它非常重要,几乎所有的函数都要用到它。

     

    1)、stop_flag表示是否应该停止的标记,它有三个可能的值0、1、2。 stop_flag=0表示 不应该停止,这是初始值;stop_flag=1表示停止,在mg_stop()函数中的一开始设置stop_flag=1,这会触发mg_fini(),且在mg_stop()中会一直等待mg_fini执行完成;stop_flag=2用于通知mg_stop(),mg_fini已经执行完成,stop_flag=2在mg_fini函数中的末尾设置。

     

    2)、ssl_ctx是结构体ssl_ctx_st的实例,它来自OpenSSL开源项目,作者把它放到这里的原因是使其独立于OpenSSL的源码安装,这样只有系统上面安装有SSL库,mongoose+SSL就能编译通过。

     

    3)、access_log、error_log很明显是指向访问日志文件、错误日志文件。

     

    4)、listeners数组存储mongoose建立的多个web server,每个web server都是listeners数组中的一个元素。例如,一个服务器可以分别在端口8080、8888建立web server,这样8080端口的那个server是listerns数组中的一个元素,8888端口的那个server也是listeners数组中的一个元素。换句话说,listeners数组表示web server的socket地址。num_listeners表示listeners数组的元素个数。

     

    5)、callbacks是结构体callback的数组,而callback本身是一个结构体,包含几个回调句柄。num_callbacks是callbacks数组元素的个数。

     

    6)、options数组,是用于存储配置选项的,例如端口号、工作目录等等。opt_mutext对配置进行操作的互斥变量。

     

    7)、max_threads表示允许的最大线程数量、num_threads表示当前的线程数量、num_idle表示空闲的线程数量。之所以会有空闲进程,是因为当创建一个线程处理连接请求之后,它会保持一段时间空闲而不是直接销毁。如果这里再用新的连接到来或等待队列中有需要处理的连接,空闲进程会被分配去处理。

     

    8)、thr_mutex、thr_cond、bind_mutex是用于互斥信号量和条件变量。

     

    9)、queue[20]队列数组存储client的连接请求,每个元素都是client的socket。sq_head、sq_tail分别是队列头、尾用于操作队列queue。empty_cond、full_cond分别表示队列是否为空、满的条件变量。

     

    10)、ssl_password_callback和log_callback都是函数指针,分别指向SSL密码处理函数、log处理函数。他们原型是:

    1. /*
    2.  * Register SSL password handler.
    3.  * This is needed only if SSL certificate asks for a password. Instead of
    4.  * prompting for a password on a console a specified function will be called.
    5.  */
    6. typedef int (*mg_spcb_t)(char *buf, int num, int w, void *key);
    7.  
    8. /*
    9.  * User-defined callback function prototype for URI handling, error handling,
    10.  * or logging server messages.
    11.  */
    12. typedef void (*mg_callback_t)(struct mg_connection *,
    13.         const struct mg_request_info *info, void *user_data);

    是上面讲了那么多感觉挺乱的,下面用张图片来形象表示一下:

        

                                       图1 mg_context结构体

    2、mg_connection详解

     

    故名思意,这个结构体用户保存client的连接信息。它的成员如下:

    1. /*
    2.  * Client connection.
    3.  */
    4. struct mg_connection {
    5.     struct mg_request_info    request_info;
    6.     struct mg_context *ctx;        /* Mongoose context we belong to*/
    7.     SSL        *ssl;        /* SSL descriptor        */
    8.     struct socket    client;        /* Connected client        */
    9.     time_t        birth_time;    /* Time connection was accepted    */
    10.     bool_t        free_post_data;    /* post_data was malloc-ed    */
    11.     bool_t        embedded_auth;    /* Used for authorization    */
    12.     uint64_t    num_bytes_sent;    /* Total bytes sent to client    */
    13. };

    上面的字段意思都很明显这里就不一一阐述了。可以看出, 每个连接都保存了一个Mongoose上下文(mg_context * ctx),这个很重要,对连接请求进行处理时都会用到。这里也可以看出mg_context相当于一个实例句柄。

     

    结构体mg_request_info用于保存每个请求的信息,例如,当打开http://www.google.com的时候,会发出一个请求信息,包括请求的方法是POST还是GET等、uri即http://www.google.com、http版本、还有一些http头信息等等。关于结构体mg_request_info的详细信息参见下一小节。

    mg_connection的图像表示如下:

                                     图2  mg_connection结构体的成员

    3、mg_request_info详解

     

    这个结构体保存每次client发送请求,即是一个HTTP请求报文信息。而我们知道HTTP的请求报文信息的格式如下:

        

     

                          图3 HTTP请求的格式

     

    根据这个信息,可以更好地理解mg_request_info。mg_request_info结构定义如下:

    1. /*
    2.  * This structure contains full information about the HTTP request.
    3.  * It is passed to the user-specified callback function as a parameter.
    4.  */
    5. struct mg_request_info {
    6.     char    *request_method;    /* "GET", "POST", etc    */
    7.     char    *uri;            /* Normalized URI    */
    8.     char    *query_string;        /* \- terminated    */
    9.     char    *post_data;        /* POST data buffer    */
    10.     char    *remote_user;        /* Authenticated user    */
    11.     long    remote_ip;        /* Client's IP address    */
    12.     int    remote_port;        /* Client's port    */
    13.     int    post_data_len;        /* POST buffer length    */
    14.     int    http_version_major;
    15.     int    http_version_minor;
    16.     int    status_code;        /* HTTP status code    */
    17.     int    num_headers;        /* Number of headers    */
    18.     struct mg_header {
    19.         char    *name;        /* HTTP header name    */
    20.         char    *value;        /* HTTP header value    */
    21.     } http_headers[64];        /* Maximum 64 headers    */
    22. };

    从字段都能够故名思意,这里就不再阐述了。

     

    4、其他数据结构 

     

    除了上面3个主要的数据结构,还有其它一些数据也默默地贡献着自己的一份力量。作为一个整体,少了它们Mongoose也只能沦为废物。下面我就列举几个:

    1. /*
    2.  * Structure used by mg_stat() function. Uses 64 bit file length.
    3.  */
    4. struct mgstat {
    5.     bool_t        is_directory;    /* Directory marker        */
    6.     uint64_t    size;        /* File size            */
    7.     time_t        mtime;        /* Modification time        */
    8. };
    9.  
    10. struct mg_option {
    11.     const char    *name;
    12.     const char    *description;
    13.     const char    *default_value;
    14.     int        index;
    15.     bool_t (*setter)(struct mg_context *, const char *);
    16. };
    17. /*
    18.  * Structure used to describe listening socket, or socket which was
    19.  * accept()-ed by the master thread and queued for future handling
    20.  * by the worker thread.
    21.  */
    22. struct socket {
    23.     SOCKET        sock;        /* Listening socket        */
    24.     struct usa    lsa;        /* Local socket address        */
    25.     struct usa    rsa;        /* Remote socket address    */
    26.     bool_t        is_ssl;        /* Is socket SSL-ed        */
    27. };
    28. /*
    29.  * Unified socket address. For IPv6 support, add IPv6 address structure
    30.  * in the union u.
    31.  */
    32. struct usa {
    33.     socklen_t len;
    34.     union {
    35.         struct sockaddr    sa;
    36.         struct sockaddr_in sin;
    37.     } u;
    38. };
    39.  
    40. /*
    41.  * Specifies a string (chunk of memory).
    42.  * Used to traverse comma separated lists of options.
    43.  */
    44. struct vec {
    45.     const char    *ptr;
    46.     size_t        len;
    47. };
    48. /*
    49.  * Dynamically loaded SSL functionality
    50.  */
    51. struct ssl_func {
    52.     const char    *name;        /* SSL function name    */
    53.     void        (*ptr)(void);    /* Function pointer    */
    54. };

    5、总结

     

    至此,我们介绍了Mongoose中使用的一些数据结构,搞清楚这些数据结构对整个项目的理解非常重要。它们遍布在项目的每个角落(虽然项目比较小)

    展开全文
  • dwr以何种数据结构将javabean发送到服务器端和如何返回?列如有一个这样的javaBean:public class Person { private String name; private String pass;public String getName() { return name;}public void set...
  • Redis 的数据结构

    2015-07-09 10:20:19
    一、Redis数据库的优势Redis是一个先进的Key-Value键值存储数据库,通常作为数据结构服务器。 支持strings, hashes, lists, sets, sorted sets, bitmaps 和hyperloglogs二、Redis数据结构1,string - 字符串Redis的...
  • Redis数据结构:位图

    2018-10-07 18:30:20
    位图(也称为位数组,位向量等)是紧凑存储位的数组数据结构。它可以用来实现一个简单的集数据结构。位数组可以有效地利用...Redis是一种内存数据结构服务器,它为位操作操作提供支持。但是,Redis中的位图没有特...
  • 服务器开发—谈谈游戏数据结构

    千次阅读 2012-11-04 13:10:42
    数据结构主要有两大类,一类是数据库的表,就像excel表一样,直观并且很好管理;二类是内存数据表,永远只key=>value形式,所以在设置数据库表时,一定要考虑加 载到内存是怎么样,并且二者即能转换又能快速查找 ...
  • udhcp源码剖析(二)——DHCP服务器重要的数据结构
  • 我们在前台向后台请求数据时可能会希望能得到一个树结构的数据结构,方便我们前台获取和使用,也能使得数据结构清晰,一目了然,树结构一般情况在我遇到的项目中都是某个表的自关联,使用到子父节点的关系,我们一般...
  • 一、需求场景 和同学一块开发一个小APP,前端使用AppCan开发,后端使用SpringBoot,我主要负责后端接口的开发,因为异地吧,两个人都是男的,开发异地0..0。...然后就用本地库开发同步本地库数据和...
  • Redis内部数据结构详解(1)——dict 2016-05-31如果你使用过Redis,一定会像我一样对它的内部实现产生兴趣。...Redis本质上是一个数据结构服务器(data structures server),以高效的方式实现了...
  • Redis内部数据结构详解(1)

    千次阅读 2018-01-10 10:36:37
    Redis内部数据结构详解(1)——dict 如果你使用过Redis,一定会像我一样对它的内部实现产生兴趣。《Redis内部数据结构详解...Redis本质上是一个数据结构服务器(data structures server),以高效的方式实现了多种现
  • 1. 不同服务器之间的数据库中的表结构数据进行同步操作,测试类,可直接运行,部分不同类型库之间的转换,还未完全完善,可能存在字段类型转换失败,导致建表失败,同步数据支持百万千万的数据量 package ...
  • dtNavMesh是Detour中表达3D场景的数据结构。 作者给的注释为: /// A navigation mesh based on tiles of convex polygons. /// @ingroup detour class dtNavMesh { // ... (代码略)... } A navigation mesh...
  • Redis本质上是一个数据结构服务器(data structures server),以高效的方式实现了多种现成的数据结构,研究它的数据结构和基于其上的算法,对于我们自己提升局部算法的编程水平有很重要的参考意义。 当我们在本文...
  • Redis 5种数据结构使用及注意事项

    千次阅读 2017-03-14 17:40:39
    1优缺点 非常非常的快,有测评说比Memcached还快(当大家都是...丰富的数据结构,超越了一般的Key-Value数据库而被认为是一个数据结构服务器。组合各种结构,限制Redis用途的是你自己的想象力,作者自己捉刀写的用途入门
  • 如何把本地数据库中的数据包括结构,存储过程,触发器移动到服务器
  • 现有一份.txt文件格式的文件,里面是json数组格式的数据,这数据将近百万条,我需要将数据解析出来放到数据库中。现如果是将数据全部读出来 解析成List, 内存过大,落表的时间过长,不现实!菜鸟请求个解决方案 ...
  • redis并不是简单的key-value数据容器,不能将其理解为静态存储数据,它是动态交互的数据结构服务器,可以被用作缓存,高性能k-v数据库等。 它支持很多种类型的数据结构,不仅支持string类型的value,还支持很多种...
  • -ts -表空间名称,用于导出某个表空间下的所有数据 -tc -表创建者,导出某用户创建的所有数据 -sn -模式名,用于导出某个模式下的所有数据 -io - 导入模式,指定DB2的import工具可以运行的一种模式。有效的选项有: ...
  • 我现在写服务器端,一般总归要维护一个客户端socket列表。执行的操作一般有: 1.遍历列表检查心跳包,删除异常的socket 2.在列表中查找对应的客户端节点(socket),发送数据 3.客户端登录,添加相应的节点 4....
  • 3)然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上。如果超过232仍然找不到服务器,就会保存到第一台memcached服务器上。 11.描述一种hash table的实现方法 1) 除法散列法: p ,令 h...
  • InnoDB内存数据结构

    千次阅读 2020-02-29 11:13:10
    InnoDB内存相关的数据结构主要包含以下几种: Buffer Pool Change Buffer Adaptive Hash Index Log Buffer Buffer Pool Buffer Pool 是在主存的一片区域,主要用来缓存表和索引数据供InnoDB访问。Buffer Pool允许...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 29,925
精华内容 11,970
关键字:

数据结构服务器

数据结构 订阅