Slide 1

Slide 1 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 "50630'1045(3&42- $0/$633&/$:$0/530- Luka Huang@COSCUP 2019

Slide 2

Slide 2 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 8IZUIJTUPQJD

Slide 3

Slide 3 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 ref:

Slide 4

Slide 4 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 .7$$ 5VQMF )05 7BDVVN 1BHF

Slide 5

Slide 5 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 "50630'1045(3&42- $0/$633&/$:$0/530-

Slide 6

Slide 6 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 • ACID and Isolation levels • How MVCC works in PostgresQL • How tuples changed during CRUD • How snapshot isolation works • How MVCC works in MySQL • MySQL vs PosgreSQL 0VUMJOF

Slide 7

Slide 7 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 Concurrency Control and ACID

Slide 8

Slide 8 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019

Slide 9

Slide 9 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 • Atomicity • Consistency • Isolation • Durability "$*%

Slide 10

Slide 10 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 • Atomicity • A transaction is inseperable – ”all or nothing” • Consistency • Isolation • Durability "$*%

Slide 11

Slide 11 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 • Atomicity • Consistency • A transaction shall bring the database from one consistent state to another consistent state, even if its not necessarily consistent during the transaction. • Isolation • Durability "$*%

Slide 12

Slide 12 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 • Atomicity • Consistency • Isolation • Transactions are not affected by changes done by concurrent transactions • Durability "$*%

Slide 13

Slide 13 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 • Atomicity • Consistency • Isolation • Durability • When a transaction is COMMITED, the changes are permanent, even after a crash "$*%

Slide 14

Slide 14 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019

Slide 15

Slide 15 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 $PODVSSFODZ$POUSPM5FDIOJRVFT

Slide 16

Slide 16 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 $PODVSSFODZ$POUSPM5FDIOJRVFT • Locking e.g. 2PL (Two-Phase Locking) • Optimistic Concurrency Control • MVCC (Multi-version Concurrency Control)

Slide 17

Slide 17 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 $PODVSSFODZ$POUSPM5FDIOJRVFT • Locking e.g. 2PL (Two-Phase Locking) • Optimistic Concurrency Control • MVCC (Multi-version Concurrency Control)

Slide 18

Slide 18 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 $PODVSSFODZ$POUSPM5FDIOJRVFT • Locking e.g. 2PL (Two-Phase Locking) • Optimistic Concurrency Control • MVCC (Multi-version Concurrency Control)

Slide 19

Slide 19 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 • Locking e.g. 2PL (Two-Phase Locking) • Optimistic Concurrency Control • MVCC (Multi-version Concurrency Control) $PODVSSFODZ$POUSPM5FDIOJRVFT

Slide 20

Slide 20 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 4OBQTIPU*TPMBUJPO 4*

Slide 21

Slide 21 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 • A type of MVCC • PostgreSQL • every writing operation create a new version of data • retain old version of data. • use visibility check rules to decide which data to show • MySQL、Oracle • Implement by rollback segments 4* 4OBQTIPU*TPMBUJPO

Slide 22

Slide 22 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 Isolation levels

Slide 23

Slide 23 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 -PSFNJQTVN ref: https://www.microsoft.com/en-us/research/wp-content/uploads/

Slide 24

Slide 24 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 ref: https://www.microsoft.com/en-us/research/wp-content/uploads/

Slide 25

Slide 25 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 • P1 (Dirty Read) • P2 (Non-repeatable or Fuzzy Read) • P3 (Phantom Read) QIFOPNFOBPG*TPMBUJPO

Slide 26

Slide 26 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 1 %JSUZ3FBE ref: https://medium.com/getamis/database-transaction-isolation-

Slide 27

Slide 27 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 1 /POSFQFBUBCMF3FBE ref: https://medium.com/getamis/database-transaction-isolation-

Slide 28

Slide 28 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 1 1IBOUPN3FBE ref: https://medium.com/getamis/database-transaction-isolation-

Slide 29

Slide 29 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 • Read Uncommitted • Read Committed • Repeatable Read • Serializable *TPMBUJPO-FWFMT

Slide 30

Slide 30 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 *TPMBUJPOMFWFMTWTSFBEQIFOPNFOB

Slide 31

Slide 31 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 3FBE$PNNJUUFE

Slide 32

Slide 32 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 3FQFBUBCMF3FBE'V[[Z3FBE

Slide 33

Slide 33 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 4FSJBMJ[BCMF

Slide 34

Slide 34 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 Table, Page and Tuple

Slide 35

Slide 35 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 5BCMF%BUB QBHF QBHF QBHF QBHF QBHF QBHF QBHF 5BCMFEBUBBOE1BHF 8kb

Slide 36

Slide 36 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 5BCMFEBUBBOE1BHF

Slide 37

Slide 37 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 5BCMFEBUBBOE1BHF

Slide 38

Slide 38 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 5BCMFEBUBBOE1BHF

Slide 39

Slide 39 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 • Sequential Scan • B-Tree Index scan "DDFTTNFUIPET

Slide 40

Slide 40 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 4FRVFOUJBM4DBO

Slide 41

Slide 41 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 #5SFF*OEFY4DBO ref: https://www.pgcon.org/2016/schedule/attachments/423_Btree

Slide 42

Slide 42 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 Concurrency Control

Slide 43

Slide 43 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 ref: 1PTUHSF42-4PVSDF$PEF

Slide 44

Slide 44 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 ref: 1PTUHSF42-4PVSDF$PEF

Slide 45

Slide 45 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 )FBQ5VQMF'JFMET src/include/access/htup_details.h

Slide 46

Slide 46 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 )FBQ5VQMF)FBEFS%BUB

Slide 47

Slide 47 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 1BHFBOE5VQMF

Slide 48

Slide 48 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 • t_xmin - 保存插入此 tuple 的 txid。 • t_xmax - 更新或刪除 tuple 的 txid。如果 沒更新、刪除的話就設為 0 • t_cid (command_id) - ⽬前執⾏了多少命 令。 • t_ctid - ⾃⼰所在的 tuple (tid)。 'JFMETJO)FBQ5VQMF

Slide 49

Slide 49 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 CREATE TABLE p_table (data text) ; INSERT INTO p_table ( data ) VALUES ( 'Jack' ) ; INSERT INTO p_table ( data ) VALUES ( 'Peter' ) ; INSERT INTO p_table ( data ) VALUES ( 'Luka' ) ; SELECT * FROM p_table; )FBQ5VQMF

Slide 50

Slide 50 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 (FUUVQMFJOGPSNBUJPO SELECT lp as tuple, t_xmin, t_xmax, t_ fi eld3 as t_cid, t_cti d FROM heap_page_items(get_raw_page(p_table', 0));

Slide 51

Slide 51 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 */4&35

Slide 52

Slide 52 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 INSERT INTO p_table ( data ) VALUES ( 'Apple' ) ; *OTFSU

Slide 53

Slide 53 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 BEGIN ; INSERT INTO p_table ( data ) VALUES ( 'Apple' ) ; SELECT txid_current() ; END ; *OTFSU

Slide 54

Slide 54 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 BEGIN ; INSERT INTO p_table ( data ) VALUES ( 'Apple' ) ; SELECT txid_current(); => txid: 62 7 END ; *OTFSU

Slide 55

Slide 55 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 61%"5&

Slide 56

Slide 56 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 #&'03&

Slide 57

Slide 57 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 6QEBUF UPDATE p_table SET data = ‘Cake';

Slide 58

Slide 58 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 6QEBUF UPDATE p_table SET data = ‘Cake';

Slide 59

Slide 59 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 UPDATE p_table SET data = 'Cheese'; 6QEBUFBHBJO

Slide 60

Slide 60 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 UPDATE p_table SET data = 'Cheese'; 6QEBUFBHBJO

Slide 61

Slide 61 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 %&-&5&

Slide 62

Slide 62 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 %FMFUF DELETE FROM p_table;

Slide 63

Slide 63 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 %FMFUF

Slide 64

Slide 64 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 53"/4"$5*0/4/"14)05

Slide 65

Slide 65 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 • Active Transaction ID • In progress or not started • It’s invisible • Inactive Transaction ID • committed or aborted • It’s visible if committed "DUJWF*OBDUJWF5SBOTBDUJPO*%

Slide 66

Slide 66 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 $VSSFOU4OBQTIPU xmin:xmax:xip_list

Slide 67

Slide 67 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 4OBQTIPU • xmin • if txid < xmin, transaction is inactive • xmax • if txid >= xmax transaction is active. • xip_list • transactions that transaction id in xip_list are active.

Slide 68

Slide 68 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 &YBNQMF ref: http://www.interdb.jp/pg/

Slide 69

Slide 69 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 &YBNQMF ref: http://www.interdb.jp/pg/

Slide 70

Slide 70 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 7*4*#*-*5:$)&$,

Slide 71

Slide 71 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 7*4*#*-*5:$)&$,36-&4

Slide 72

Slide 72 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019

Slide 73

Slide 73 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 • ABORTED • IN PROGRESS • COMMITTED U@YNJO

Slide 74

Slide 74 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 /* t_xmin status = ABORTED */ Rule 1: IF t_xmin status is 'ABORTED' THE N RETURN 'Invisible' END IF "#035&% ref: http://www.interdb.jp/pg/

Slide 75

Slide 75 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 /* t_xmin status = IN_PROGRESS */ IF t_xmin status is 'IN_PROGRESS' THE N IF t_xmin = current_txid THE N Rule 2: IF t_xmax = INVALID THE N RETURN 'Visible' Rule 3: ELSE /* this tuple has been deleted or updated by the current transaction itself. */ RETURN 'Invisible' END I F Rule 4: ELSE /* t_xmin ≠ current_txid */ RETURN 'Invisible' END I F END IF */@130(3&44 ref: http://www.interdb.jp/pg/

Slide 76

Slide 76 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 /* t_xmin status = COMMITTED */ IF t_xmin status is 'COMMITTED' THE N Rule 5: IF t_xmin is active in the obtained transaction snapshot THE N RETURN 'Invisible' Rule 6: ELSE IF t_xmax = INVALID OR status of t_xmax is 'ABORTED' THE N RETURN 'Visible' ELSE IF t_xmax status is 'IN_PROGRESS' THE N Rule 7: IF t_xmax = current_txid THE N RETURN 'Invisible' Rule 8: ELSE /* t_xmax ≠ current_txid */ RETURN 'Visible' END I F ELSE IF t_xmax status is 'COMMITTED' THE N Rule 9: IF t_xmax is active in the obtained transaction snapshot THE N RETURN 'Visible' Rule 10: ELS E RETURN 'Invisible' END I F $0..*55&% ref: http://www.interdb.jp/pg/

Slide 77

Slide 77 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 &YBNQMF ref: http://www.interdb.jp/pg/

Slide 78

Slide 78 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 • Rule6(Tuple_1) 㱺 Status(t_xmin:199) = COMMITTED ∧ t_xmax = INVALID 㱺 Visible 5 ref: http://www.interdb.jp/pg/ ref: http://www.interdb.jp/pg/

Slide 79

Slide 79 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 • Rule7(Tuple_1): Status(t_xmin:199) = COMMITTED ∧ Status(t_xmax:200) = IN_PROGRESS ∧ t_xmax:200 = current_txid:200 㱺 Invisible 5 ref: http://www.interdb.jp/pg/ ref: http://www.interdb.jp/pg/

Slide 80

Slide 80 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 • Rule2(Tuple_2): Status(t_xmin:200) = IN_PROGRESS ∧ t_xmin:200 = current_txid:200 ∧ t_xmax = INVAILD 㱺 Visible 5 ref: http://www.interdb.jp/pg/

Slide 81

Slide 81 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 )05 )&"10/-: 561-&4

Slide 82

Slide 82 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 8JUIPVU)05 ref: http://www.interdb.jp/pg/

Slide 83

Slide 83 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 8JUI)05 ref: http://www.interdb.jp/pg/

Slide 84

Slide 84 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 )05JTOPUXPSL ref: http://www.interdb.jp/pg/

Slide 85

Slide 85 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 )05JTOPUXPSL ref: http://www.interdb.jp/pg/

Slide 86

Slide 86 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 MVCC in MySQ L

Slide 87

Slide 87 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 • Storage Engine - InnoDB only • Isolation level • READ COMMITTED • REPEATABLE READ .7$$JO.Z42-

Slide 88

Slide 88 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 • DB_TRX_ID • DB_ROLL_PTR .7$$JO.Z42-*OOP%# ref: https://zhuanlan.zhihu.com/p/40208895

Slide 89

Slide 89 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 • DB_TRX_ID • The last transaction that update this record • DB_ROLL_PTR .7$$JO.Z42-*OOP%# ref: https://zhuanlan.zhihu.com/p/40208895

Slide 90

Slide 90 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 • DB_TRX_ID • The last transaction that update this record • DB_ROLL_PTR • rollback segment (undo log) .7$$JO.Z42-*OOP%# ref: https://zhuanlan.zhihu.com/p/40208895

Slide 91

Slide 91 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 6OEP-PH • Automaticity • Copy data to another place before updating data . • The place is called undo log. ref: https://liuzhengyang.github.io/2017/04/18/innodb-mvcc/

Slide 92

Slide 92 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 3PMMCBDL4FHNFOU ref: http://leviathan.vip/2019/02/14/InnoDB%E7%9A%84%E4%BA%8B%E5%8A%A1%E5%88%86%E6%9E%90- undo slot rollback segment undo log tablespace

Slide 93

Slide 93 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 1. rseg_id - get rollback tablespace id 2. get data from undo log 4UFQTPG3PMM1PJOUFS /** Decodes a roll pointer. */ inline void trx_undo_decode_roll_ptr ( roll_ptr_t roll_ptr, /*!< in: roll pointer */ ibool *is_insert, /*!< out: TRUE if insert undo log */ ulint *rseg_id, /*!< out: rollback segment id */ page_no_t *page_no, /*!< out: page number */ ulint *offset) /*!< out: offset of the und o entry within page */ { ut_ad(roll_ptr < (1ULL << 56)) ; *offset = (ulint)roll_ptr & 0xFFFF ; roll_ptr >>= 16 ; *page_no = (ulint)roll_ptr & 0xFFFFFFFF ; roll_ptr >>= 32 ; *rseg_id = (ulint)roll_ptr & 0x7F ; roll_ptr >>= 7 ; *is_insert = (ibool)roll_ptr; /* TRUE==1 */ }

Slide 94

Slide 94 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 • Uncommited transacftions • If transactions is commited, system will remove transaction id from trx_sys list. USY@TZTUSBOTBDUJPOTMJTU ref: https://liuzhengyang.github.io/2017/04/18/innodb-mvcc/

Slide 95

Slide 95 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 • low_trx_id • up_trx_id • trx_ids 3FBEWJFX ref: https://liuzhengyang.github.io/2017/04/18/innodb-mvcc/

Slide 96

Slide 96 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 ref: https://liuzhengyang.github.io/2017/04/18/innodb-mvcc/ .7$$JO.Z42-

Slide 97

Slide 97 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 1PTUHSF42- WT 
 .Z42-

Slide 98

Slide 98 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 ref:

Slide 99

Slide 99 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019

Slide 100

Slide 100 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 ref:

Slide 101

Slide 101 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 ref:

Slide 102

Slide 102 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 ref:

Slide 103

Slide 103 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 ref:

Slide 104

Slide 104 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 ref:

Slide 105

Slide 105 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 ref:

Slide 106

Slide 106 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 ref:

Slide 107

Slide 107 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 $0/$-64*0/

Slide 108

Slide 108 text

A Tour of PostgreSQL Concurrency Control, Luka Huang@COSCUP 2019 5)"/,4'03-*45&/*/(