精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Redis的跳躍表確定不了解下嗎?

存儲 存儲軟件 Redis
hello,大家好,前面幾周我們一起看了Redis底層數據結構,如動態字符串SDS,雙向鏈表Adlist,字典Dict,如果有對Redis常見的類型或底層數據結構不明白的請看上面傳送門。

[[332515]]

本文轉載自微信公眾號「 學習Java的小姐姐」,作者學習Java的小姐姐0618。轉載本文請聯系學習Java的小姐姐公眾號。

前言

hello,大家好,前面幾周我們一起看了Redis底層數據結構,如動態字符串SDS,雙向鏈表Adlist,字典Dict,如果有對Redis常見的類型或底層數據結構不明白的請看上面傳送門。

 

今天我們來看下ZSET的底層架構,如果不知道ZSET是什么的,可以看上面傳送門第一篇。簡單來說,ZSET是Redis提供的根據數據和分數來判斷其排名的數據結構。最常見的就是微信運動的排名,每個用戶對應自己的步數,每天晚上可以給出用戶的排名。

有小伙伴可能會想,如果是實現排名的話,各種排序方法都可以實現的,沒必要引入Redis的ZSET結構啊?

當然,如果是采用排序方法的話,是可以實現相同功能的,但是代碼里面需要硬編碼,會添加工作量,還會提供代碼的Bug哦,哈哈哈。而且Redis的底層是C實現的,直接操作內存,速度也會比Java方法實現提升。

綜上,使用Redis的ZSET結構,好處多多。那話不多說,開始把。在正式開始之前,我們需要引入下跳躍表的概念,其是ZSET結構的底層實現。以下可能有點枯燥,我盡量說的簡單點哈。(一定要看哦,這寫的太累了哈)

 

什么是跳躍表?

對于數據量大的鏈表結構,插入和刪除比較快,但是查詢速度卻很慢。那是因為無法直接獲取某個節點,需要從頭節點開始,借助某個節點的next指針來獲取下一節點。即使數據是有序排放的,想要查詢某個數據,只能從頭到尾遍歷變量,查詢效率會很低,時間復雜度為O(n)。

如果我們需要快速查詢鏈表有啥辦法呢?有同學說用數組存放,但是如果不改數據結構呢?

我們可以先想想在有序數組結構中有二分法,每次將范圍都縮小一半,這樣查詢速度提升了很多,那么在鏈表中能不能也使用這種思想。

這就到了今天講的主角——跳躍表。(一點也生硬的引出概念😊)

 

步驟一 新建有序單項鏈表

先看下圖有序單向鏈表,存放了1,2,3,4,5,6,7這7個元素。

 

步驟二 抽取二級索引節點

我們可以在鏈表中抽取部分節點,下圖抽取了1,3,5,7四個節點,也就是每兩個節點提取了一個節點到上級,抽取出來的叫做索引。

注意不是每次都能抽取到這么完美,這其實就跟拋硬幣一樣,每個硬幣的正反兩面的概率是一樣的,都是1/2。當數據量小的時候,正反的概率可能差別較大。但是隨著數據量的加大,正反的概率越來越接近于1/2。類比過來是一個意思,每個節點的機會都是一樣的,要么停留原級,要么提取到上級,概率都是1/2。但是隨著節點數量的增加,抽取的節點越來越接近與1/2。

 

步驟三 抽取三級索引節點

我們可以在鏈表中抽取部分節點,下圖抽取了1,5兩個節點,也就是每兩個節點提取了一個節點到上級,抽取出來的叫做索引。

 

步驟四 類二分法查詢

我們假設要查找值為6的節點,先從三級索引開始,找到值為1的節點,發現比5小,根據值為1節點的next指針,找到值為5的節點,5后面沒有其他的三級索引啦。

于是順著往下找,到了二級索引,根據值為5的節點的next指針找到值為7的節點,發現比6小,說明要找到的節點6在此范圍內。

再接著到了一級索引位置,根據值為5的節點next指針指向值為6的節點,發現是想要查詢的數據,所以查詢過程結束。

根據上面的查詢過程(下圖的藍色連線),我們發現其采用的核心思想是二分法,不斷縮小查詢范圍,如果在上層索引找到區間,則順延深入到下一層找到真正的數據。

 

總結

從上面的整個過程中可以看出,數據量小的時候,這種拿空間換時間,消耗內存方法的并不是最優解。所以Redis的zset結構在數據量小的時候采用壓縮表(這邊先放著哈,下下篇說,立個flag),數據量大的時候采用跳躍表。

像這種鏈表加多級索引的結構,就是跳躍表。這名字起的形象,過程是跳躍著來查詢的。旋轉跳躍,我閉著眼,bgm響起來。

 

Redis中跳躍表圖解

下圖簡單來說是對跳躍表的改進和再封裝,首先引入了表頭的概念,這與雙向鏈表,字典結構一樣,都是對數據的封裝,因為他們都是采用的指針,而指針必然導致在計算長度,獲取最后節點的數據問題上會產生查詢太慢的性能問題,所以封裝表頭是為了在這些問題上提升速度,浪費的只是添加,刪除等操作的時間,與此對比,是可以忽略的。

其次是引入管理所有節點的層數數組,我們可以看到有32層,即32個數組,這和后面的數據節點結構是一樣的。引入它是為了便于直接根據此數組的層數定位到每個元素。

再其次是數據節點的每個level都有層級和span(也就是下圖箭頭指針上的數字,其是為了方便統計兩個節點相距多少長度)。

最后就是數據節點的后退指針backward,引入目的是Level數組只有前指針,即只能指向下一個節點地址,而后退指針是為了能往回找節點。

 

上圖主要分為3大塊:(這邊大致看下就行,下面將對各模塊進行代碼詳細解釋)

表頭

主要包括四個屬性,分別是頭指針header,尾指針tail,節點長度length,所有節點的最大level。

header:指向跳躍表的表頭節點,通過這個指針地址可以直接找到表頭,時間復雜度為O(1)。

tail:指向跳躍表的表尾節點,通過這個指針可以直接找到表尾,時間復雜度為O(1)。

length:記錄跳躍表的長度,即不包含表頭節點,整個跳躍表中有多少個元素。

level:記錄當前跳躍表內,所有節點層數最大的level(排除表頭節點)。

管理所有節點層數level的數組

其對象值為空,level數組為32層,目的是為了管理真正的數據節點。關于具體的level有哪些屬性放在數據節點來說。

數據節點

主要包括四個屬性對象值obj,分數score,后退指針backward和level數組。每個數據的Level數組有多少層,是隨機產生的,這跟上面說過的跳躍表是一樣的。

成員對象obj:真正的實際數據,每個節點的數據都是唯一的,但是節點的分數可能相同。兩個相同分數的節點是按照成員對象在字典中的大小進行排序的,成員對象較小的節點會排在前面,成員對象較大的節點會排在后面。

分數score:各個節點中的數字是節點所保存的分數,在跳躍表中,節點按各自所保存的分數從小到大排列。

后退指針backward:用于從表尾向表頭遍歷,每個節點只有一個后退指針,即每次只能后退一步。

層級level:節點中用1,2,3等字樣標記節點的各個層,L1代表第一層,L2代表第二層,L3代表第三層,并以此類推。

跳躍表的定義

表頭結構zskiplist

  1. typedef struct zskiplist { 
  2.     //表頭的頭指針header和尾指針tail 
  3.     struct zskiplistNode *header, *tail; 
  4.     //一共有多少個節點length 
  5.     unsigned long length; 
  6.     // 所有節點最大的層級level 
  7.    int level
  8. } zskiplist; 

具體數據節點zskiplistNode

  1. //跳表的具體節點 
  2. typedef struct zskiplistNode { 
  3.     sds ele; //具體的數據,對應張三 
  4.     double score;//分數,對應70 
  5.     struct zskiplistNode *backward;//后退指針backward 
  6.      //層級數組    struct zskiplistLevel { 
  7.         struct zskiplistNode *forward;//前進指針forward 
  8.         unsigned int span;//跨度span 
  9.     } level[]; 
  10. } zskiplistNode; 

跳躍表的實現(源碼分析)

redis關于跳躍表的API都定義在t_zset.c文件中。

千萬不要看到源碼分析就跑開了,一定要看哦。

 

創建跳躍表

創建空的跳躍表,其實就是創建表頭和管理所有的節點的level數組。首先,定義一些變量,嘗試分配內存空間。其次是初始化表頭的level和length,分別賦值1和0。接著創建管理所有節點的Level的數組,是調用zslCreateNode函數,輸入參數為數組大小宏常量ZSKIPLIST_MAXLEVEL(32),分數為0,對象值為NULL。(此為跳躍表得以實現重點)。再接著就是為此數組每個元素的前指針forword和跨度span初始化。最后初始化尾指針并返回值。

可以參照下面的圖解和源碼:

  1. //創建一個空表頭的跳躍表 
  2. zskiplist *zslCreate(void) { 
  3.     int j; 
  4.     zskiplist *zsl; 
  5.     //嘗試分配內存空間 
  6.     zsl = zmalloc(sizeof(*zsl)); 
  7.     //初始化level和length 
  8.     zsl->level = 1; 
  9.     zsl->length = 0; 
  10.     //調用下面的方法zslCreateNode,傳入的參數有數組長度ZSKIPLIST_MAXLEVEL 32 
  11.     //分數0,對象值NuLL 
  12.     //這一步就是創建管理所有節點的數組 
  13.     //并且設置表頭的頭頭指針為此對象的地址 
  14.     zsl->header = zslCreateNode(ZSKIPLIST_MAXLEVEL,0,NULL); 
  15.     //為這32個數組賦值前指針forward和跨度span 
  16.     for (j = 0; j < ZSKIPLIST_MAXLEVEL; j++) { 
  17.         zsl->header->level[j].forward = NULL
  18.         zsl->header->level[j].span = 0; 
  19.     } 
  20.     //設置尾指針 
  21.     zsl->header->backward = NULL
  22.     zsl->tail = NULL
  23.     //返回對象 
  24.     return zsl; 
  1. zskiplistNode *zslCreateNode(int leveldouble score, sds ele) { 
  2.     zskiplistNode *zn = 
  3.         zmalloc(sizeof(*zn)+level*sizeof(struct zskiplistLevel)); 
  4.     zn->score = score; 
  5.     zn->ele = ele; 
  6.     return zn; 

插入節點

比如有下圖6個元素,需要插入值為趙六,分數為101的元素,我們大致想一想,大致的步驟包括找到要插入的位置,新建一個數據節點,然后調整與之相關的頭尾指針的level數組。那就看看redis咋做的,和我們想的一樣不一樣呢?

噔噔噔噔,答案揭曉。當然了大框架是相同的。

 

正文開始了:(先來圖片)

 

1.遍歷管理所有節點的level數組,從最大的level開始,即3,挨個對比值,如果有分數比他大的值或者分數相同,但是數據的值比他大,記錄到數組里面,同時記錄跨度。

這樣說太抽象了。拿上圖舉個例子,從表頭的level即3開始,首先到張三的L3,發現分數70,比目標分數101小跳過,根據其前指針找到趙六的L3,發現分數102,比目標分數101大,將趙六L3記錄在待更新數組update中,同時記錄跨度span為4。接著到下一層,張三的L2層,發現分數70比目標分數101小跳過,根據前指針找到王五的L2,發現分數90,比目標分數101小跳過,根據前指針找到趙六的L2,發現分數102比目標分數101大,將趙六的L2記錄到待更新數組update中,同時記錄跨度span為2。最后到下一層,張三的L1層,邏輯和剛才一樣的,也是記錄趙六的L1層和跨度span為1。

2.為新節點隨機生成層級數level(通過位運算),如果生成的level大于目前level最大值3,則將將大于部分挨個遍歷,并將跨度等信息記錄到上面update表中。

比如,新節點生成的level為5,目前level最大值為3,說明這個節點只會有一個,并且跨越了之前的所有節點,那么我們將從第四層和第五層都遍歷下,記錄到待更新數組update中。

3.準備工作都做好了,找到了該節點將插入到哪一位置,處于哪一層,每層對應的跨度是多少,下面就要新增數據節點了。把上兩步的信息都添加到新節點上,并且調整位置前后指針即可。

4.最后就是一些收尾工作,比如修改表頭的層級level,節點大小length和尾指針tail等屬性。

綜上,整個流程就已經結束了。可能看著有點復雜,可以對照下面代碼來。

  1. //插入節點,輸入參數為 
  2. //zsl:表頭 
  3. //score:插入元素的分數score 
  4. //ele:插入元素的具體數據ele 
  5. zskiplistNode *zslInsert(zskiplist *zsl, double score, sds ele) { 
  6.     //使用update數組記錄每層待插入元素的前一個元素 
  7.     zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x; 
  8.     //記錄前置節點與第一個節點之間的跨度,即元素在列表中的排名-1 
  9.     unsigned int rank[ZSKIPLIST_MAXLEVEL]; 
  10.     int i, level
  11.  
  12.     serverAssert(!isnan(score)); 
  13.     x = zsl->header; 
  14.     //從最大的level開始遍歷,從頂到底,找到每一層待插入的位置 
  15.     for (i = zsl->level-1; i >= 0; i--) { 
  16.         /* store rank that is crossed to reach the insert position */ 
  17.         rank[i] = i == (zsl->level-1) ? 0 : rank[i+1]; 
  18.     //直接找到第一個分數比該元素大的位置 
  19.     //或者分數與該元素相同但是對象的ASSICC碼比該元素大的位置 
  20.         while (x->level[i].forward && 
  21.                 (x->level[i].forward->score < score || 
  22.                     (x->level[i].forward->score == score && 
  23.                     sdscmp(x->level[i].forward->ele,ele) < 0))) 
  24.         { 
  25.             //將已走過元素的跨越元素進行計數,得到元素在列表中排名,或者是已搜尋的路徑長度 
  26.             rank[i] += x->level[i].span; 
  27.             x = x->level[i].forward
  28.         } 
  29.     //記錄待插入位置 
  30.         update[i] = x; 
  31.     } 
  32.      //隨機產生一個層數,在1到32之間,層數越高,生成的概率越低 
  33.     level = zslRandomLevel(); 
  34.     //如果產生的層數大于現有的最高層數,則超出層數都需要初始化 
  35.     if (level > zsl->level) { 
  36.         //開始循環 
  37.         for (i = zsl->level; i < level; i++) { 
  38.             rank[i] = 0; 
  39.             //該元素作為這些層的第一個節點,前節點就是header 
  40.             update[i] = zsl->header; 
  41.             //初始化后這些層每層有兩個元素,走一步就是跨越所有元素 
  42.             update[i]->level[i].span = zsl->length; 
  43.         } 
  44.         zsl->level = level
  45.     } 
  46.     //創建節點 
  47.     x = zslCreateNode(level,score,ele); 
  48.     for (i = 0; i < level; i++) { 
  49.         //將新節點插入到各層鏈表中 
  50.         x->level[i].forward = update[i]->level[i].forward
  51.         update[i]->level[i].forward = x; 
  52.  
  53.         // rank[0]是第0層的前置節點P1(也就是底層插入節點前面那個節點)與第一個節點的跨度 
  54.         // rank[i]是第i層的前置節點P2(這一層里在插入節點前面那個節點)與第一個節點的跨度 
  55.         // 插入節點X與后置節點Y的跨度f(X,Y)可由以下公式計算 
  56.         // 關鍵在于f(P1,0)-f(P2,0)+1等于新節點與P2的跨度,這是因為跨度呈扇形形向下延伸到最底層 
  57.         // 記錄節點各層跨越元素情況span, 由層與層之間的跨越元素總和rank相減而得 
  58.         x->level[i].span = update[i]->level[i].span - (rank[0] - rank[i]); 
  59.                // 插入位置前一個節點的span在原基礎上加1即可(新節點在rank[0]的后一個位置) 
  60.  
  61.  update[i]->level[i].span = (rank[0] - rank[i]) + 1; 
  62.     } 
  63.  
  64.     /* increment span for untouched levels */ 
  65.     for (i = level; i < zsl->level; i++) { 
  66.         update[i]->level[i].span++; 
  67.     } 
  68.     // 第0層是雙向鏈表, 便于redis常支持逆序類查找 
  69.     x->backward = (update[0] == zsl->header) ? NULL : update[0]; 
  70.     if (x->level[0].forward
  71.         x->level[0].forward->backward = x; 
  72.     else 
  73.         zsl->tail = x; 
  74.     zsl->length++; 
  75.     return x; 
  76.  
  77.  
  78.  
  79.  
  80.  
  81.  
  82.  
  83.  
  84. int zslRandomLevel(void) { 
  85.     int level = 1; 
  86.     while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF)) 
  87.         level += 1; 
  88.     return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL; 

獲取節點排名

擔心大家忘了這張圖,再粘貼一遍。如下圖,這部分邏輯比較簡單,就不寫了,具體參考代碼分析。

  1. //得到節點的排名 
  2. //輸入參數為表頭結構zsl,分數score,真正的數據ele 
  3. unsigned long zslGetRank(zskiplist *zsl, double score, sds ele) { 
  4.     zskiplistNode *x; 
  5.     unsigned long rank = 0; 
  6.     int i; 
  7.     //先獲取表頭的頭指針,即找到管理所有節點的level數組 
  8.     x = zsl->header; 
  9.      //從表頭的level,即最大值開始循環遍歷 
  10.     for (i = zsl->level-1; i >= 0; i--) { 
  11.         //如果找到分數小于目標分數的,排名加上其跨度 
  12.         //或者分數相同,但是具體數據小于目標數據的,排名也加上跨度 
  13.         while (x->level[i].forward && 
  14.             (x->level[i].forward->score < score || 
  15.                 (x->level[i].forward->score == score && 
  16.                 sdscmp(x->level[i].forward->ele,ele) <= 0))) { 
  17.             rank += x->level[i].span; 
  18.             x = x->level[i].forward
  19.         } 
  20.  
  21.         //確保在第i層找到分值相同,且對象相同時才會返回排位值 
  22.         if (x->ele && sdscmp(x->ele,ele) == 0) { 
  23.             return rank; 
  24.         } 
  25.     } 
  26.     return 0; 

結語

該篇主要講了Redis的ZSET數據類型的底層實現跳躍表,先從跳躍表是什么,引出跳躍表的概念和數據結構,剖析了其主要組成部分,進而通過多幅過程圖解釋了Redis是如何設計跳躍表的,最后結合源碼對跳躍表進行描述,如創建過程,添加節點過程,獲取某個節點排名過程,中間穿插例子和過程圖。

如果覺得寫得還行,麻煩給個贊👍,您的認可才是我寫作的動力!

如果覺得有說的不對的地方,歡迎評論指出。

 

好了,拜拜咯。

 

原文鏈接:https://mp.weixin.qq.com/s/EDGrGabrdorgKUdaw6OK5A

 

責任編輯:武曉燕 來源: 學習Java的小姐姐
相關推薦

2021-01-14 08:31:54

Web開發應用程序

2019-04-03 09:10:35

Rediskey-value數據庫

2021-08-29 20:11:12

Linux系統噪音

2011-03-29 15:44:41

對日軟件外包

2020-09-16 07:59:40

數組內存

2020-04-20 10:55:57

大數據人工智能技術

2020-11-30 06:27:35

Java泛型Object

2021-07-12 07:01:39

AST前端abstract sy

2019-11-21 15:08:13

DevOps云計算管理

2014-06-16 10:03:54

分組交換

2010-08-19 10:12:34

路由器標準

2023-02-12 21:54:32

架構AI元宇宙

2025-08-06 06:15:00

2013-11-11 10:07:43

靜態路由配置

2017-03-13 17:25:00

移動支付技術支撐易寶

2018-07-16 09:00:32

LinuxBash數組

2017-03-07 13:52:38

程序員調試片斷

2019-10-30 09:25:58

NginxApache 服務器

2025-08-28 06:05:00

2015-06-05 09:52:41

公有云風險成本
點贊
收藏

51CTO技術棧公眾號

久草免费在线色站| 国产日韩在线观看一区| 久久99高清| 欧日韩精品视频| 一区二区三区精品国产| 99热这里只有精品在线观看| 亚洲三级国产| 夜夜嗨av一区二区三区四区| 久久久九九九热| 超碰高清在线| 国产精品乱码人人做人人爱| 高清不卡一区二区三区| 中文字幕xxxx| 欧美精品日韩| 中文字幕视频一区二区在线有码 | 波多视频一区| 中文字幕欧美一区| 久久精品99| 国产精品一级二级| 香蕉国产精品偷在线观看不卡| 中文字幕日韩免费视频| 无码国产69精品久久久久网站 | 污污内射在线观看一区二区少妇| 在线国产成人影院| 亚洲一本大道在线| 黄频视频在线观看| 黄色软件在线| 成人白浆超碰人人人人| 成人欧美一区二区三区黑人孕妇| 日日骚av一区二区| 1024成人| 欧美另类在线观看| 国产无遮挡在线观看| 欧美网色网址| 精品福利av导航| 91aaa精品| 色综合天天色| 日韩欧美精品网站| 国产av麻豆mag剧集| 97超碰资源站在线观看| 中文字幕一区三区| 五月天婷亚洲天综合网鲁鲁鲁| 五月激情六月婷婷| 成人动漫在线一区| 国产精品swag| 国产免费黄色片| 久久国产剧场电影| 欧洲成人在线视频| 国产高潮久久久| 最新亚洲一区| 91精品国产91久久久久久吃药| 毛片a片免费观看| 欧美不卡在线| 久久av红桃一区二区小说| 美女网站视频色| 不卡在线一区二区| 一区二区三区视频在线| 97伦伦午夜电影理伦片| 亚欧日韩另类中文欧美| 日韩电影在线观看永久视频免费网站| 人妻激情偷乱频一区二区三区| 亚洲精品在线a| 欧美不卡视频一区| 午夜男人的天堂| 国产精品网站在线看| 337p日本欧洲亚洲大胆精品| 性农村xxxxx小树林| 精品丝袜久久| 亚洲精品一区在线观看香蕉| 久久中文字幕人妻| 国产影视一区| 精品国产一区二区三区久久久狼| 五月婷婷综合激情网| 2023国产精品久久久精品双| 欧美裸体xxxx极品少妇| 国产无码精品一区二区| 国产亚洲午夜| 国产精品久久不能| 国产成人三级在线播放| eeuss影院一区二区三区| 久久综合一区二区三区| a√资源在线| 亚洲麻豆国产自偷在线| 国产日韩欧美精品在线观看| www.51av欧美视频| 日本韩国一区二区三区视频| 日本黄大片一区二区三区| 国产精品毛片aⅴ一区二区三区| 日韩精品一区二区三区四区| av网页在线观看| 日韩久久久久| 久久久久国产视频| 无码人妻精品一区二区三区不卡 | 久久久久中文字幕亚洲精品| 台湾色综合娱乐中文网| 一区二区三区天堂av| 99精品久久久久| 亚洲黄色在线| 国产欧美精品日韩| 日本激情一区二区| 国产精品美女久久久久av爽李琼 | 亚洲综合不卡| 成人亲热视频网站| 四虎在线观看| 亚洲人成电影网站色mp4| 男人日女人逼逼| 青青在线精品| 日韩精品一二三四区| 夫妻性生活毛片| 国产欧美成人| 97超级碰碰| av在线三区| 五月婷婷另类国产| 日本中文字幕二区| 久久99国产精品视频| 欧美激情日韩图片| 亚洲一卡二卡在线| 久久综合99re88久久爱| 热久久最新地址| av免费在线一区| 精品亚洲一区二区三区在线观看 | 玖玖综合伊人| 亚洲综合视频在线观看| 亚洲美女性囗交| 亚洲激情77| 韩国精品美女www爽爽爽视频| 国产亚洲久一区二区| heyzo一本久久综合| 青青草综合视频| 日本免费一区二区三区等视频| 亚洲精品黄网在线观看| 久久免费视频6| 狠狠色狠狠色综合日日91app| 欧美极品一区二区| 国产盗摄精品一区二区酒店| 欧美一区二区在线免费观看| 大胸美女被爆操| 日韩精品亚洲专区| 欧美午夜视频在线| 成人爱爱网址| 亚洲理论在线a中文字幕| 国产乡下妇女做爰| 成人涩涩免费视频| 波多野结衣与黑人| 日本少妇精品亚洲第一区| 日韩中文字幕在线精品| 最近中文字幕在线视频| 国产日韩av一区| 茄子视频成人免费观看| 亚洲第一福利社区| 欧美专区在线播放| 四虎在线视频| 一本一道综合狠狠老| 亚洲熟妇一区二区三区| 老司机一区二区三区| 久久66热这里只有精品| 一级毛片久久久| 亚洲日本欧美日韩高观看| 免费黄色av片| 国产三级一区二区| xx欧美撒尿嘘撒尿xx| 99热在线成人| 亚洲999一在线观看www| 色爱综合区网| 亚洲国产一区二区三区四区 | 欧美日韩综合色| 黑人狂躁日本娇小| 国产一区二区三区精品视频| 国产一区二区三区在线免费| 97一区二区国产好的精华液| 91成人福利在线| 国产乱视频在线观看| 欧美色视频在线观看| 欧美日韩在线观看成人| 99视频国产精品| 日韩欧美xxxx| 日韩综合网站| 国产欧美一区二区白浆黑人| 黄色成年人视频在线观看| 欧美成人a视频| 日本黄色一级视频| 中文字幕亚洲视频| 妖精视频一区二区| 日韩不卡免费视频| 美女av免费观看| 久久99国产精品视频| 亚洲a中文字幕| а√天堂8资源在线| 亚洲人午夜色婷婷| 精品美女www爽爽爽视频| 精品久久久一区二区| 免费成人深夜天涯网站| 国产高清在线观看免费不卡| 国产免费毛卡片| 亚洲乱码电影| 蜜桃传媒一区二区| 日本在线一区二区三区| 热re99久久精品国产66热| 青青影院在线观看| 亚洲精品白浆高清久久久久久| 无码人妻精品一区二区| 亚洲一区二区五区| 天美传媒免费在线观看| 99久久免费精品| 嫩草视频免费在线观看| 性欧美暴力猛交另类hd| 亚洲av首页在线| 精品国产中文字幕第一页| 国产精品二区在线| 久久久国产精品网站| 97久久精品国产| 国产丝袜在线| 中文字幕在线观看亚洲| 视频三区在线观看| 精品美女一区二区三区| 一级做a爱片性色毛片| 五月天一区二区三区| 伊人在线视频观看| 国产欧美一区二区三区鸳鸯浴 | 国产一区视频免费观看| 欧美视频官网| 中文字幕黄色大片| 成人同人动漫免费观看| 免费av一区二区三区| 成人偷拍自拍| 亚洲一区二区三区乱码aⅴ| 最新欧美电影| 4388成人网| 免费看污久久久| 成人免费网址| 中文字幕日本精品| 巨骚激情综合| 亚洲欧美国产精品| 天天干在线观看| 精品久久一区二区三区| 国产三级伦理片| 久草精品在线观看| 无码人妻精品一区二区三区在线| 欧美fxxxxxx另类| 喜爱夜蒲2在线| 午夜国产精品视频| 97超碰在线视| 韩国一区二区三区在线观看| 日本一道在线观看| 欧美视频成人| 日本手机在线视频| 在线国产日韩| 免费看国产曰批40分钟| 日韩午夜电影| 国产中文字幕二区| 国产精品一国产精品k频道56| 福利视频一二区| 一区二区国产在线观看| 丰满爆乳一区二区三区| 国产日韩一区二区三区在线| 久久成人免费观看| 首页欧美精品中文字幕| 色多多视频在线播放| 日本成人在线视频网站| 亚洲美女性囗交| 国产精品白丝jk白祙喷水网站| 亚洲av无码久久精品色欲| 国产成人av电影在线播放| 亚洲成a人片在线www| www.亚洲人| 新91视频在线观看| 欧美国产一区二区| www.xxxx日本| 天天操天天干天天综合网| 免费观看成人毛片| 在线观看av一区| 99久久精品国产成人一区二区| 欧美tk丨vk视频| 欧洲毛片在线| 精品国产视频在线| 国产一线二线在线观看| 欧美中文在线字幕| 国产精品麻豆成人av电影艾秋| 亚洲a一级视频| 欧美理论电影在线精品| 四虎影视永久免费在线观看一区二区三区| 久久久影院免费| 国产一区二区三区小说| 久久久噜噜噜| 在线观看中文av| 99精品久久只有精品| 永久免费毛片在线观看| 亚洲欧美另类综合偷拍| 可以免费看的av毛片| 欧美日韩一级大片网址| 不卡av中文字幕| 亚洲人成电影网| av色综合久久天堂av色综合在| 97色在线观看免费视频| 国产福利亚洲| 国外成人在线视频网站| 久久精品高清| 久久综合色视频| 国产综合色视频| 野花社区视频在线观看| 亚洲视频一区二区在线| 中国一级特黄毛片| 欧美一区二区美女| 国产在线电影| 97视频人免费观看| 超碰国产精品一区二页| 久久亚洲高清| 国产精品magnet| 国产原创精品在线| 97久久超碰国产精品| 欧美黑人性猛交xxx| 在线观看亚洲专区| 色欲av永久无码精品无码蜜桃 | 欧美少妇一区二区| 人妻无码中文字幕免费视频蜜桃| 综合久久五月天| 黑人巨大精品| 国产精品theporn88| 亚洲综合中文| 久久这里只精品| 久久久久高清精品| 日本熟妇毛耸耸xxxxxx| 777午夜精品视频在线播放| 黑人与亚洲人色ⅹvideos| 91精品国产91久久久久福利| 婷婷视频一区二区三区| 91手机视频在线| 日本成人在线不卡视频| 亚洲AV无码国产成人久久| 亚洲不卡一区二区三区| 超碰在线播放97| 久久这里有精品| 欧美成人黄色| 亚洲人体一区| 人妖欧美一区二区| 欧美大波大乳巨大乳| 日韩欧美精品免费在线| 日韩一区av| 人人做人人澡人人爽欧美| 九九热hot精品视频在线播放| 真实国产乱子伦对白视频| 国产成人在线色| 欧美成人精品一区二区免费看片 | 国产99视频在线观看| 偷拍精品福利视频导航| 国产 福利 在线| 91丝袜呻吟高潮美腿白嫩在线观看| 国产一级久久久| 亚洲福利视频网站| 秋霞伦理一区| 欧美日韩日本网| 日欧美一区二区| 国产又粗又长又硬| 欧美另类z0zxhd电影| www在线视频| 高清视频一区| 在线亚洲自拍| 亚洲精品国产一区黑色丝袜| 在线视频综合导航| 岛国最新视频免费在线观看| 国产精品第一第二| 久久中文字幕av| 中文字幕乱妇无码av在线| 亚洲国产人成综合网站| 国产又爽又黄网站亚洲视频123| 538国产精品视频一区二区| 亚洲精品推荐| 日本a√在线观看| 亚洲天堂中文字幕| 欧美 日韩 国产 在线| 88国产精品欧美一区二区三区| 少妇精品久久久一区二区三区| www.xxx亚洲| 亚洲人123区| 国产香蕉在线观看| 日韩av电影在线免费播放| 欧美大片aaaa| 国产精品亚洲一区二区无码| 欧美日韩国内自拍| a√资源在线| 国产伦精品一区二区三区四区免费| 国产日韩亚洲| 二区三区四区视频| 亚洲国产成人精品久久| 中文.日本.精品| 久久久天堂国产精品| 26uuu色噜噜精品一区| 亚洲综合免费视频| 国内精品久久久久影院 日本资源| 一道在线中文一区二区三区| 91亚洲精品久久久蜜桃借种| 亚洲高清免费视频| av在线资源站| 精品伦理一区二区三区| 久久国产精品99久久人人澡| 日本一区二区网站| 日韩视频一区在线| 亚洲亚洲免费| 国产精品偷伦视频免费观看了| 欧洲一区二区三区免费视频|