MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
pfs_lock.h
Go to the documentation of this file.
1 /* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software Foundation,
14  51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
15 
16 #ifndef PFS_LOCK_H
17 #define PFS_LOCK_H
18 
24 #include "pfs_atomic.h"
25 
36 #define PFS_LOCK_FREE 0x00
37 
44 #define PFS_LOCK_DIRTY 0x01
45 
51 #define PFS_LOCK_ALLOCATED 0x02
52 
53 #define VERSION_MASK 0xFFFFFFFC
54 #define STATE_MASK 0x00000003
55 #define VERSION_INC 4
56 
64 struct pfs_lock
65 {
82  volatile uint32 m_version_state;
83 
85  bool is_free(void)
86  {
87  uint32 copy= m_version_state; /* non volatile copy, and dirty read */
88  return ((copy & STATE_MASK) == PFS_LOCK_FREE);
89  }
90 
92  bool is_populated(void)
93  {
94  uint32 copy= m_version_state; /* non volatile copy, and dirty read */
95  return ((copy & STATE_MASK) == PFS_LOCK_ALLOCATED);
96  }
97 
104  bool free_to_dirty(void)
105  {
106  uint32 copy= m_version_state; /* non volatile copy, and dirty read */
107  uint32 old_val= (copy & VERSION_MASK) + PFS_LOCK_FREE;
108  uint32 new_val= (copy & VERSION_MASK) + PFS_LOCK_DIRTY;
109 
110  return (PFS_atomic::cas_u32(&m_version_state, &old_val, new_val));
111  }
112 
119  {
120  uint32 copy= PFS_atomic::load_u32(&m_version_state);
121  /* Make sure the record was ALLOCATED. */
122  DBUG_ASSERT((copy & STATE_MASK) == PFS_LOCK_ALLOCATED);
123  /* Keep the same version, set the DIRTY state */
124  uint32 new_val= (copy & VERSION_MASK) + PFS_LOCK_DIRTY;
125  /* We own the record, no need to use compare and swap. */
127  }
128 
135  {
136  uint32 copy= PFS_atomic::load_u32(&m_version_state);
137  /* Make sure the record was DIRTY. */
138  DBUG_ASSERT((copy & STATE_MASK) == PFS_LOCK_DIRTY);
139  /* Increment the version, set the ALLOCATED state */
140  uint32 new_val= (copy & VERSION_MASK) + VERSION_INC + PFS_LOCK_ALLOCATED;
142  }
143 
149  void set_allocated(void)
150  {
151  /* Do not set the version to 0, read the previous value. */
152  uint32 copy= PFS_atomic::load_u32(&m_version_state);
153  /* Increment the version, set the ALLOCATED state */
154  uint32 new_val= (copy & VERSION_MASK) + VERSION_INC + PFS_LOCK_ALLOCATED;
156  }
157 
162  void dirty_to_free(void)
163  {
164  uint32 copy= PFS_atomic::load_u32(&m_version_state);
165  /* Make sure the record was DIRTY. */
166  DBUG_ASSERT((copy & STATE_MASK) == PFS_LOCK_DIRTY);
167  /* Keep the same version, set the FREE state */
168  uint32 new_val= (copy & VERSION_MASK) + PFS_LOCK_FREE;
170  }
171 
176  void allocated_to_free(void)
177  {
178 #ifndef DBUG_OFF
179  extern volatile bool ready_to_exit;
180 #endif
181 
182  /*
183  If this record is not in the ALLOCATED state and the caller is trying
184  to free it, this is a bug: the caller is confused,
185  and potentially damaging data owned by another thread or object.
186  The correct assert to use here to guarantee data integrity is simply:
187  DBUG_ASSERT(m_state == PFS_LOCK_ALLOCATED);
188  Now, because of Bug#56666 (Race condition between the server main thread
189  and the kill server thread), this assert actually fails during shutdown,
190  and the failure is legitimate, on concurrent calls to mysql_*_destroy(),
191  when destroying the instrumentation of an object ... twice.
192  During shutdown this has no consequences for the performance schema,
193  so the assert is relaxed with the "|| ready_to_exit" condition as a work
194  around until Bug#56666 is fixed.
195  */
196  uint32 copy= PFS_atomic::load_u32(&m_version_state);
197  /* Make sure the record was ALLOCATED. */
198  DBUG_ASSERT(((copy & STATE_MASK) == PFS_LOCK_ALLOCATED) || ready_to_exit);
199  /* Keep the same version, set the FREE state */
200  uint32 new_val= (copy & VERSION_MASK) + PFS_LOCK_FREE;
202  }
203 
208  void begin_optimistic_lock(struct pfs_lock *copy)
209  {
211  }
212 
218  bool end_optimistic_lock(struct pfs_lock *copy)
219  {
220  /* Check there was valid data to look at. */
221  if ((copy->m_version_state & STATE_MASK) != PFS_LOCK_ALLOCATED)
222  return false;
223 
224  /* Check the version + state has not changed. */
226  return false;
227 
228  return true;
229  }
230 
231  uint32 get_version()
232  {
233  return (PFS_atomic::load_u32(&m_version_state) & VERSION_MASK);
234  }
235 };
236 
237 
239 #endif
240