国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

MySQL 深潛 - 一文詳解 MySQL Data Dictionary

數據庫 MySQL
在 MySQL 8.0 之前,Server 層和存儲引擎(比如 InnoDB)會各自保留一份元數據(schema name, table definition 等),不僅在信息存儲上有著重復冗余,而且可能存在兩者之間存儲的元數據不同步的現象。

 [[419615]]

一 背景

在 MySQL 8.0 之前,Server 層和存儲引擎(比如 InnoDB)會各自保留一份元數據(schema name, table definition 等),不僅在信息存儲上有著重復冗余,而且可能存在兩者之間存儲的元數據不同步的現象。不同存儲引擎之間(比如 InnoDB 和 MyISAM)有著不同的元數據存儲形式和位置(.FRM, .PAR, .OPT, .TRN and .TRG files),造成了元數據無法統一管理。此外,將元數據存放在不支持事務的表和文件中,使得 DDL 變更不會是原子的,crash recovery 也會成為一個問題。

為了解決上述問題,MySQL 在 8.0 中引入了 data dictionary 來進行 Server 層和不同引擎間統一的元數據管理,這些元數據都存儲在 InnoDB 引擎的表中,自然的支持原子性,且 Server 層和引擎層共享一份元數據,不再存在不同步的問題。

二 整體架構

典表的讀寫操作,包含開表(open table)、構造主鍵、主鍵查找等過程。client 和底層存儲之間通過兩級緩存來加速對元數據對象的內存訪問,兩級緩存都是基于 hash map 實現的,一層緩存是 local 的,由每個 client(每個線程對應一個 client)獨享;二級緩存是 share 的,為所有線程共享的全局緩存。下面我將對 data dictionary 的數據結構和實現架構做重點介紹,也會分享一個支持原子的 DDL 在 data dictionary 層面的實現過程。

三 metadata 在內存和引擎層面的表示

data dictionary (簡稱DD)中的數據結構是完全按照多態、接口/實現的形式來組織的,接口通過純虛類來實現(比如表示一個表的 Table),其實現類(Table_impl)為接口類的名字加 _impl 后綴。下面以 Table_impl 為例介紹一個表的元數據對象在 DD cache 中的表示。

1 Table_impl

Table_impl 類中包含一個表相關的元數據屬性定義,比如下列最基本引擎類型、comment、分區類型、分區表達式等。

  1. class Table_impl : public Abstract_table_impl, virtual public Table {  // Fields.  Object_id m_se_private_id;  String_type m_engine;  String_type m_comment;  // - Partitioning related fields.  enum_partition_type m_partition_type;  String_type m_partition_expression;  String_type m_partition_expression_utf8;  enum_default_partitioning m_default_partitioning;  // References to tightly-coupled objects.  Index_collection m_indexes;  Foreign_key_collection m_foreign_keys;  Foreign_key_parent_collection m_foreign_key_parents;  Partition_collection m_partitions;  Partition_leaf_vector m_leaf_partitions;  Trigger_collection m_triggers;  Check_constraint_collection m_check_constraints;}; 

Table_impl 也是代碼實現中 client 最常訪問的內存結構,開發者想要增加新的屬性,直接在這個類中添加和初始化即可,但是僅僅如此不會自動將該屬性持久化到存儲引擎中。除了上述簡單屬性之外,還包括與一個表相關的復雜屬性,比如列信息、索引信息、分區信息等,這些復雜屬性都是存在其他的 DD 表中,在內存 cache 中也都會集成到 Table_impl 對象里。

從 Abstract_table_impl 繼承來的 Collection m_columns 就表示表的所有列集合,集合中的每一個對象 Column_impl 表示該列的元信息,包括數值類型、是否為 NULL、是否自增、默認值等。同時也包含指向 Abstract_table_impl 的指針,將該列與其對應的表聯系起來。

  1. class Column_impl : public Entity_object_impl, public Column {  // Fields.  enum_column_types m_type;  bool m_is_nullable;  bool m_is_zerofill;  bool m_is_unsigned;  bool m_is_auto_increment;  bool m_is_virtual;  bool m_default_value_null;  String_type m_default_value;  // References to tightly-coupled objects.  Abstract_table_impl *m_table;}; 

此外 Table_impl 中也包含所有分區的元信息集合 Collection m_partitions,存放每個分區的 id、引擎、選項、范圍值、父子分區等。

  1. class Partition_impl : public Entity_object_impl, public Partition {  // Fields.  Object_id m_parent_partition_id;  uint m_number;  Object_id m_se_private_id;  String_type m_description_utf8;  String_type m_engine;  String_type m_comment;  Properties_impl m_options;  Properties_impl m_se_private_data;  // References to tightly-coupled objects.  Table_impl *m_table;  const Partition *m_parent;  Partition_values m_values;  Partition_indexes m_indexes;  Table::Partition_collection m_sub_partitions;}; 

因此獲取到一個表的 Table_impl,我們就可以獲取到與這個表相關聯的所有元信息。

2 Table_impl 是如何持久化存儲和訪問的

DD cache 中的元信息都是在 DD tables 中讀取和存儲的,每個表存放一類元信息的基本屬性字段,比如 tables、columns、indexes等,他們之間通過主外鍵關聯連接起來,組成 Table_impl 的全部元信息。DD tables 存放在 mysql 的表空間中,在 release 版本對用戶隱藏,只能通過 INFORMATION SCHEMA 的部分視圖查看;在 debug 版本可通過設置 SET debug='+d,skip_dd_table_access_check' 直接訪問查看。比如:

  1. root@localhost:test 8.0.18-debug> SHOW CREATE TABLE mysql.tables\G*************************< strong> 1. row < /strong>*************************       Table: tablesCreate TableCREATE TABLE `tables` (  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,  `schema_id` bigint(20) unsigned NOT NULL,  `namevarchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,  `type` enum('BASE TABLE','VIEW','SYSTEM VIEW'COLLATE utf8_bin NOT NULL,  `engine` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,  `mysql_version_id` int(10) unsigned NOT NULL,  `row_format` enum('Fixed','Dynamic','Compressed','Redundant','Compact','Paged'COLLATE utf8_bin DEFAULT NULL,  `collation_id` bigint(20) unsigned DEFAULT NULL,  `comment` varchar(2048) COLLATE utf8_bin NOT NULL,  `hidden` enum('Visible','System','SE','DDL'COLLATE utf8_bin NOT NULL,  `options` mediumtext COLLATE utf8_bin,  `se_private_data` mediumtext COLLATE utf8_bin,  `se_private_id` bigint(20) unsigned DEFAULT NULL,  `tablespace_id` bigint(20) unsigned DEFAULT NULL,  `partition_type` enum('HASH','KEY_51','KEY_55','LINEAR_HASH','LINEAR_KEY_51','LINEAR_KEY_55','RANGE','LIST','RANGE_COLUMNS','LIST_COLUMNS','AUTO','AUTO_LINEAR'COLLATE utf8_bin DEFAULT NULL,  `partition_expression` varchar(2048) COLLATE utf8_bin DEFAULT NULL,  `partition_expression_utf8` varchar(2048) COLLATE utf8_bin DEFAULT NULL,  `default_partitioning` enum('NO','YES','NUMBER'COLLATE utf8_bin DEFAULT NULL,  `subpartition_type` enum('HASH','KEY_51','KEY_55','LINEAR_HASH','LINEAR_KEY_51','LINEAR_KEY_55'COLLATE utf8_bin DEFAULT NULL,  `subpartition_expression` varchar(2048) COLLATE utf8_bin DEFAULT NULL,  `subpartition_expression_utf8` varchar(2048) COLLATE utf8_bin DEFAULT NULL,  `default_subpartitioning` enum('NO','YES','NUMBER'COLLATE utf8_bin DEFAULT NULL,  `created` timestamp NOT NULL,  `last_altered` timestamp NOT NULL,  `view_definition` longblob,  `view_definition_utf8` longtext COLLATE utf8_bin,  `view_check_option` enum('NONE','LOCAL','CASCADED'COLLATE utf8_bin DEFAULT NULL,  `view_is_updatable` enum('NO','YES'COLLATE utf8_bin DEFAULT NULL,  `view_algorithm` enum('UNDEFINED','TEMPTABLE','MERGE'COLLATE utf8_bin DEFAULT NULL,  `view_security_type` enum('DEFAULT','INVOKER','DEFINER'COLLATE utf8_bin DEFAULT NULL,  `view_definer` varchar(288) COLLATE utf8_bin DEFAULT NULL,  `view_client_collation_id` bigint(20) unsigned DEFAULT NULL,  `view_connection_collation_id` bigint(20) unsigned DEFAULT NULL,  `view_column_names` longtext COLLATE utf8_bin,  `last_checked_for_upgrade_version_id` int(10) unsigned NOT NULL,  PRIMARY KEY (`id`),  UNIQUE KEY `schema_id` (`schema_id`,`name`),  UNIQUE KEY `engine` (`engine`,`se_private_id`),  KEY `engine_2` (`engine`),  KEY `collation_id` (`collation_id`),  KEY `tablespace_id` (`tablespace_id`),  KEY `type` (`type`),  KEY `view_client_collation_id` (`view_client_collation_id`),  KEY `view_connection_collation_id` (`view_connection_collation_id`),  CONSTRAINT `tables_ibfk_1` FOREIGN KEY (`schema_id`) REFERENCES `schemata` (`id`),  CONSTRAINT `tables_ibfk_2` FOREIGN KEY (`collation_id`) REFERENCES `collations` (`id`),  CONSTRAINT `tables_ibfk_3` FOREIGN KEY (`tablespace_id`) REFERENCES `tablespaces` (`id`),  CONSTRAINT `tables_ibfk_4` FOREIGN KEY (`view_client_collation_id`) REFERENCES `collations` (`id`),  CONSTRAINT `tables_ibfk_5` FOREIGN KEY (`view_connection_collation_id`) REFERENCES `collations` (`id`)) /*!50100 TABLESPACE `mysql` */ ENGINE=InnoDB AUTO_INCREMENT=549 DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0 ROW_FORMAT=DYNAMIC1 row in set (0.00 sec) 

通過以上 mysql.tables 的表定義可以獲得存儲引擎中實際存儲的元信息字段。DD tables 包括 tables、schemata、columns、column_type_elements、indexes、index_column_usage、foreign_keys、foreign_key_column_usage、table_partitions、table_partition_values、index_partitions、triggers、check_constraints、view_table_usage、view_routine_usage 等。

Storage_adapter 是訪問持久存儲引擎的處理類,包括 get() / drop() / store() 等接口。當初次獲取一個表的元信息時,會調用 Storage_adapter::get() 接口,處理過程如下:

  1. Storage_adapter::get()  // 根據訪問對象類型,將依賴的 DD tables 加入到 open table list 中  |--Open_dictionary_tables_ctx::register_tables< T>()     |--Table_impl::register_tables()  |--Open_dictionary_tables_ctx::open_tables() // 調用 Server 層接口打開所有表  |--Raw_table::find_record() // 直接調用 handler 接口根據傳入的 key(比如表名)查找記錄    |--handler::ha_index_read_idx_map() // index read  // 從讀取到的 record 中解析出對應屬性,調用 field[field_no]->val_xx() 函數  |--Table_impl::restore_attributes()    // 通過調用 restore_children() 函數從與該對象關聯的其他 DD 表中根據主外鍵讀取完整的元數據定義    |--Table_impl::restore_children()   |--返回完整的 DD cache 對象 

上述在獲取列和屬性的對應關系時,根據的是 Tables 對象的枚舉類型下標,按順序包含了該類型 DD 表中的所有列,與上述表定義是一一對應的。因此如果我們需要新增 DD 表中存儲的列時,也需要往下面枚舉類型定義中加入對應的列,并且在 Table_impl::restore_attributes() / Table_impl::store_attributes() 函數中添加對新增列的讀取和存儲操作。

  1. class Tables : public Entity_object_table_impl {  enum enum_fields {    FIELD_ID,    FIELD_SCHEMA_ID,    FIELD_NAME,    FIELD_TYPE,    FIELD_ENGINE,    FIELD_MYSQL_VERSION_ID,    FIELD_ROW_FORMAT,    FIELD_COLLATION_ID,    FIELD_COMMENT,    FIELD_HIDDEN,    FIELD_OPTIONS,    FIELD_SE_PRIVATE_DATA,    FIELD_SE_PRIVATE_ID,    FIELD_TABLESPACE_ID,    FIELD_PARTITION_TYPE,    FIELD_PARTITION_EXPRESSION,    FIELD_PARTITION_EXPRESSION_UTF8,    FIELD_DEFAULT_PARTITIONING,    FIELD_SUBPARTITION_TYPE,    FIELD_SUBPARTITION_EXPRESSION,    FIELD_SUBPARTITION_EXPRESSION_UTF8,    FIELD_DEFAULT_SUBPARTITIONING,    FIELD_CREATED,    FIELD_LAST_ALTERED,    FIELD_VIEW_DEFINITION,    FIELD_VIEW_DEFINITION_UTF8,    FIELD_VIEW_CHECK_OPTION,    FIELD_VIEW_IS_UPDATABLE,    FIELD_VIEW_ALGORITHM,    FIELD_VIEW_SECURITY_TYPE,    FIELD_VIEW_DEFINER,    FIELD_VIEW_CLIENT_COLLATION_ID,    FIELD_VIEW_CONNECTION_COLLATION_ID,    FIELD_VIEW_COLUMN_NAMES,    FIELD_LAST_CHECKED_FOR_UPGRADE_VERSION_ID,    NUMBER_OF_FIELDS  // Always keep this entry at the end of the enum  };}; 

四 多級緩存

為了避免每次對元數據對象的訪問都需要去持久存儲中讀取多個表的數據,使生成的元數據內存對象能夠復用,data dictionary 實現了兩級緩存的架構,第一級是 client local 獨享的,核心數據結構為 Local_multi_map,用于加速在當前線程中對于相同對象的重復訪問,同時在當前線程涉及對 DD 對象的修改(DDL)時管理 committed、uncommitted、dropped 幾種狀態的對象。第二級就是比較常見的多線程共享的緩存,核心數據結構為 Shared_multi_map,包含著所有線程都可以訪問到其中的對象,所以會做并發控制的處理。

兩級緩存的底層實現很統一,都是基于 hash map 的,目前的實現是 std::map。Local_multi_map 和 Shared_multi_map都是派生于 Multi_map_base。

之所以叫 Multi_map_base,是因為其中包含了多個 hash map,適合用戶根據不同類型的 key 來獲取緩存對象,比如 id、name、DD cache 本身等。Element_map 就是對 std::map 的一個封裝,key 為前述幾種類型之一,value 為 DD cache 對象指針的一個封裝 Cache_element,封裝了對象本身和引用計數。

Multi_map_base 對象實現了豐富的 m_map() 模板函數,可以很方便的根據 key 的類型不同選擇到對應的 hash map。

Shared_multi_map 與 Local_multi_map 的不同在于,Shared_multi_map 還引入了一組 latch 與 condition variable 用于并發訪問中的線程同步與 cache miss 的處理。同時對 Cache_element 對象做了內存管理和復用的相關能力。

1 局部緩存

一級緩存位于每個 Dictionary_client (每個 client 與線程 THD 一一對應)內部,由不同狀態(committed、uncommitted、dropped)的 Object_registry 組成。每個 Object_registry 由不同元數據類型的 Local_multi_map 組成,用于管理不同類型的對象(比如表、schema、字符集、統計數據、Event 等)緩存。

其中 committed 狀態的 registry 就是我們訪問數據庫中已經存在的對象時,將其 DD cache object 存放在局部緩存中的位置。uncommitted 和 dropped 狀態的存在,主要用于當前連接執行的是一條 DDL 語句,在執行過程中會將要 drop 的舊表對應的 DD object 存放在 dropped 的 registry 中,將還未提交的新表定義對應的 DD object 存放在 uncommitted 的 registry 中,用于執行狀態的區分。

2 共享緩存

共享緩存是 Server 全局唯一的,使用單例 Shared_dictionary_cache 來實現。與上述局部緩存中 Object_registry 相似,Shared_dictionary_cache 也需要包含針對各種類型對象的緩存。與 Multi_map_base 實現根據 key 類型自動選取對應 hash map 的模版函數相似,Object_registry 和 Shared_dictionary_cache 也都實現了根據訪問對象的類型選擇對應緩存的 m_map() 函數,能夠很大程度上簡化函數調用。

與局部緩存可以無鎖訪問 hash map 不同,共享緩存在獲取 / 釋放 DD cache object 時都需要加鎖來完成引用計數的調整和防止訪問過程中被 destroy 掉。

3 緩存獲取過程

用戶通過 client 調用元數據對象獲取函數,傳入元數據的 name 字符串,然后構建出對應的 name key,通過 key 去緩存中獲取元數據對象。獲取的整體過程就是一級局部緩存 -> 二級共享緩存 -> 存儲引擎。

  1. // Get a dictionary object.template < typename K, typename T>bool Dictionary_client::acquire(const K &key, const T **object,                                bool *local_committed,                                bool *local_uncommitted) {  // Lookup in registry of uncommitted objects  T *uncommitted_object = nullptr;  bool dropped = false;  acquire_uncommitted(key, &uncommitted_object, &dropped);  ...  // Lookup in the registry of committed objects.  Cache_element< T> *element = NULL;  m_registry_committed.get(key, &element);  ...  // Get the object from the shared cache.  if (Shared_dictionary_cache::instance()->get(m_thd, key, &element)) {    DBUG_ASSERT(m_thd->is_system_thread() || m_thd->killed ||                m_thd->is_error());    return true;  }} 

在一級局部緩存中獲取時,會優先去 uncommitted 和 dropped 的 registry 獲取,因為這兩者是最新的修改,同時判斷獲取對象是否已經被 dropped。之后再會去 committed 的 registry 獲取,如果獲取到就直接返回,反之則去二級共享緩存中嘗試獲取。

Cache miss

共享緩存的獲取過程在 Shared_multi_map::get() 中實現。就是加鎖后直接的 hash map 查找,如果存在則給引用計數遞增后返回;如果不存在,就會進入到 cache miss 的處理過程,調用上面介紹的存儲引擎的接口 Storage_adapter::get() 從 DD tables 中讀取,創建出來后依次加入共享緩存和局部緩存 committed registry 中。

由于開表訪問 DD tables,構建 DD cache object 的過程相對耗時,不會一直給 Shared_multi_map 加鎖,因此需要對并發訪問的 client 做并發控制。DD 的實現方法是第一個訪問的 client 會將 cache miss 的 key 加入到 Shared_multi_map的 m_missed 集合中,這個集合包含著現在所有正在讀取元數據的對象 key 值。之后訪問的 client 看到目標 key 值在 m_missed 集合中就會進入等待。

當第一個 client 獲取到完整的 DD cache object,加入到共享緩存之后,移除 m_missed 集合中對應的 key,并通過廣播的方式通知之前等待的線程重新在共享緩存中獲取。

五 Auto_releaser

Auto_releaser 是一個 RAII 類,基本上在使用 client 訪問 DD cache 前都會做一個封裝,保證在整個 Auto_releaser 對象存在的作用域內,所獲取到的 DD cache 對象都會在局部緩存中存在不釋放。Auto_releaser 包含需要 release 的對象 registry,通過 auto_release() 函數收集著當前 client 從共享緩存中獲取到的 DD cache 對象,在超出其作用域進行析構時自動 release 對象,從局部緩存 committed 的 registry 中移除對象,并且在共享緩存中的引用計數遞減。

在嵌套函數調用過程中,可能在每一層都會有自己的 Auto_releaser,他們之間通過一個簡單的鏈表指針連接起來。在函數返回時將本層需要 release 的對象 release 掉,需要返回給上層使用的 DD cache 對象交給上層的 Auto_releaser 來負責。通過 transfer_release() 可以在不同層次的 Auto_releaser 對象間轉移需要 release 的對象,可以靈活的指定不再需要 DD cache 對象的層次。

六 應用舉例:inplace DDL 過程中對 DD 的操作

在 MySQL inplace DDL 執行過程中,會獲取當前表定義的 DD cache 對象,然后根據實際的 DDL 操作內容構造出新對應的 DD 對象。然后依次調用 client 的接口完成對當前表定義的刪除和新表定義的存儲。

  1. {      if (thd->dd_client()->drop(table_def)) goto cleanup2;  table_def = nullptr;  DEBUG_SYNC_C("alter_table_after_dd_client_drop");  // Reset check constraint's mode.  reset_check_constraints_alter_mode(altered_table_def);  if ((db_type->flags & HTON_SUPPORTS_ATOMIC_DDL)) {    /*      For engines supporting atomic DDL we have delayed storing new      table definition in the data-dictionary so far in order to avoid      conflicts between old and new definitions on foreign key names.      Since the old table definition is gone we can safely store new      definition now.    */    if (thd->dd_client()->store(altered_table_def)) goto cleanup2;  }}.../*  If the SE failed to commit the transaction, we must rollback the  modified dictionary objects to make sure the DD cache, the DD  tables and the state in the SE stay in sync.*/if (res)  thd->dd_client()->rollback_modified_objects();else  thd->dd_client()->commit_modified_objects(); 

在 drop() 過程中,會將當前表定義的 DD cache 對象對應的數據從存儲引擎中刪除,然后從共享緩存中移除(這要求當前對象的引用計數僅為1,即只有當前線程使用),之后加入到 dropped 局部緩存中。

在 store() 過程中,會將新的表定義寫入存儲引擎,并且將對應的 DD cache 對象加入 uncommitted 緩存中。

在事務提交或者回滾后,client 將局部緩存中的 dropped 和 uncommitted registry 清除。由于 InnoDB 引擎支持事務,持久存儲層面的數據會通過存儲引擎的接口提交或回滾,不需要 client 額外操作。

在這個過程中,由于 MDL(metadata lock) 的存在,不會有其他的線程嘗試訪問正在變更對象的 DD object,所以可以安全的對 Shared_dictionary_cache 進行操作。當 DDL 操作結束(提交或回滾),釋放 EXCLUSIVE 鎖之后,新的線程就可以重新從存儲引擎上加載新的表定義。

七 總結

MySQL data dictionary 解決了背景所述舊架構中的諸多問題,使元數據的訪問更加安全,存儲和管理成本更低。架構實現非常的精巧,通過大量的模版類實現使得代碼能夠最大程度上被復用。多層緩存的實現也能顯著提升訪問效率。通過 client 簡潔的接口,讓 Server 層和存儲層能在任何地方方便的訪問元數據。

參考

[1] MySQL8.0DataDictionary:BackgroundandMotivation
http://mysqlserverteam.com/mysql-8-0-data-dictionary-background-and-motivation/

[2] MySQL 8.0: Data Dictionary Architecture and Design
http://mysqlserverteam.com/mysql-8-0-data-dictionary-architecture-and-design/

[3] Source code mysql / mysql-server 8.0.18
https://github.com/mysql/mysql-server/tree/mysql-8.0.18

責任編輯:梁菲 來源: 阿里云云棲號
相關推薦

2021-08-25 11:25:41

MySQLData Dictio數據庫

2021-09-28 10:59:53

MYSQLPerformance 內存管理

2022-11-06 21:14:02

數據驅動架構數據

2022-03-11 09:12:06

MySQLMDL

2020-03-18 14:00:47

MySQL分區數據庫

2021-03-04 00:09:31

MySQL體系架構

2020-10-20 13:50:47

MySQL數據庫

2021-10-19 10:10:51

MySQL事務隔離級別數據庫

2021-02-11 09:01:32

CSS開發 SDK

2020-06-23 08:41:47

JavaScript開發技術

2022-06-26 00:18:05

企業產品化變量

2025-03-28 11:47:38

2020-05-12 15:40:06

MySQ數據庫索引

2023-02-27 07:33:14

MySQL數據庫服務器

2023-03-27 17:58:34

MySQL加鎖間隙鎖

2019-02-25 08:58:16

Python深拷貝淺拷貝

2023-02-28 18:09:53

Javascript定時器

2023-02-23 19:32:03

DOMJavascript開發

2021-05-11 11:05:43

SAL子查詢

2022-08-05 08:22:10

eBPFHTTP項目
點贊
收藏

51CTO技術棧公眾號

日本人妻伦在线中文字幕| 亚洲黄色尤物视频| 日日骚久久av| 在线观看午夜看亚太视频| 午夜在线精品偷拍| 欧美日本高清视频| 青春草在线免费视频| 亚洲欧美电影一区二区| 欧美日韩一区在线视频| 99热国内精品永久免费观看| 欧美成人午夜免费视在线看片| 九色91在线| 色老综合老女人久久久| 久草免费在线播放| 国产日韩综合av| 欧美一级中文字幕| 香蕉成人久久| 444亚洲人体| 日韩美女精品| 欧美色倩网站大全免费| 日本福利片高清在线观看| 婷婷成人激情在线网| 激情六月丁香婷婷| 成人国产精品视频| 中国成人亚色综合网站| 久久一区二区三区四区五区 | 欧美一级爆毛片| 精品国产丝袜高跟鞋| 欧美日韩aaaaaa| caoporn97在线视频| 欧美成人精品二区三区99精品| 水莓100在线视频| 91精品国产综合久久小美女| www在线视频| 亚洲午夜女主播在线直播| 校园春色亚洲| 欧美精品久久久久久久久久| 国产高清久久| 色一情一乱一伦一区二区三区丨| 欧美一级二区| 99久久久无码国产精品6| 国产精品私人影院| 成人在线免费公开观看视频| 亚洲国产婷婷香蕉久久久久久| 久久亚洲国产精品尤物| 国产精品狼人色视频一区| 麻豆精品一区二区三区| 免费成人看片| 精品国产乱码久久久久久蜜臀| 欧美成人福利| 99视频在线| 国产日韩欧美在线一区| 日本国产一区二区三区| 国内成人精品2018免费看| 偷偷要色偷偷| 日韩在线播放av| 亚洲第一区色| 男女午夜刺激视频| 亚洲美女精品久久| 欧美午夜不卡| eeuss在线观看| 久久精品91久久久久久再现| 亚洲少妇在线| 美女毛片在线看| 中文字幕av亚洲精品一部二部| 一区二区三区鲁丝不卡| 久久99精品久久| 国产精品对白刺激| www.久久久久久久久| 黄av在线播放| 国产精品国模大尺度私拍| 亚洲精品老司机| 91夜夜蜜桃臀一区二区三区| 青春草国产视频| 日韩精品最新网址| 免播放器亚洲| 欧美激情免费| 97超级在线观看免费高清完整版电视剧| 国产农村妇女精品| 成人自拍视频网| 97久久国产亚洲精品超碰热| 欧美一区二区三区在线电影| 激情久久五月| 三级外国片在线观看视频| 成人写真视频福利网| 欧美性猛交xxxx黑人猛交| 水蜜桃久久夜色精品一区| 在线免费中文字幕| 国产欧美一区二区三区视频| 一色屋精品亚洲香蕉网站| 日韩伦理一区二区三区| 日韩午夜影院| 日本视频一区二区不卡| 日韩免费在线观看| 丁香亚洲综合激情啪啪综合| 试看120秒一区二区三区| 97蝌蚪自拍自窝| 国产精品九九久久久久久久| 午夜国产不卡在线观看视频| 亚洲高清久久| 日韩欧美精品电影| 亚州黄色一级| 欧美日韩一区二区三区在线视频| 亚洲精品国产拍免费91在线| 2024国产精品| 欧美军人男男激情gay| 黄色网页在线观看| 91国视频在线| 国产精品久久视频| 欧美日韩国产高清一区二区三区 | 国产精品白丝在线| 国产精品久久久久久久免费软件| 三上悠亚一区二区| 午夜影院在线| 欧美一区1区三区3区公司 | 日本h片久久| 在线成人动漫| 免费看黄在线看| 成人欧美在线观看| 精品在线欧美视频| 日本高清不卡在线观看| 成人av先锋影音| 一级毛片免费看| 国产精品又粗又长| 国产精品日韩高清| 91精品91久久久久久| 亚洲第一视频网| 欧美日韩国产在线| 久久久亚洲国产美女国产盗摄| 校园春色综合网| 成人羞羞动漫| 黑人久久a级毛片免费观看| 性欧美freesex顶级少妇| 色资源在线观看| www.大网伊人| av黄色免费| 国产精品97在线| 特级黄色录像片| 久久久久久久久久久一区 | 女人让男人操自己视频在线观看| 日本午夜在线| 日本免费视频| wwwwww.色| 茄子视频成人免费观看| 国产va亚洲va在线va| 亚洲天堂第一区| 日韩最新中文字幕| 日韩久久久久久久| 日韩免费一区二区三区| 你懂的网址一区二区三区| 精品久久蜜桃| 欧美日韩精品免费看| 日本亚洲自拍| 亚洲国产午夜伦理片大全在线观看网站| 精品欧美国产| 伊人久久av导航| 国产黄色激情视频| 岛国毛片在线播放| 蜜桃成人在线视频| 都市激情国产精品| 日本亚洲欧洲无免费码在线| jizz国产精品| 成人av二区| 日本午夜精品视频在线观看| 国产999精品久久久久久| 中文成人av在线| 亚洲超碰97人人做人人爱| 日韩视频一区二区| 欧美成人第一页| 亚洲xxx自由成熟| 欧美日韩福利在线| 亚洲中文字幕久久精品无码喷水| 中文字幕乱在线伦视频乱在线伦视频| 九色视频在线观看免费播放| 欧洲成人综合网| 国产伦精品一区二区三区在线播放| 欧美特黄一级大片| 国产成人亚洲精品青草天美| 亚洲一区二区欧美激情| 国产亚洲成av人片在线观看桃| 成人黄色片网站| 亚洲 中文字幕 日韩 无码| 毛片免费在线播放| 一本一道久久a久久| 国产精品视区| 亚洲一区二区在线免费观看视频| 亚洲精品视频免费| 狠狠色综合网站久久久久久久| 乱子伦视频在线看| 成人久久一区二区三区| 亚洲jizzjizz日本少妇| 午夜在线观看视频| 美女网站视频久久| 精品国产欧美一区二区三区成人| 国产理论在线播放| 国产日韩欧美| 日韩av电影院| 三上悠亚激情av一区二区三区| 天天色 色综合| 37pao成人国产永久免费视频|