diff options
Diffstat (limited to 'storage/perfschema/pfs_lock.h')
-rw-r--r-- | storage/perfschema/pfs_lock.h | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/storage/perfschema/pfs_lock.h b/storage/perfschema/pfs_lock.h new file mode 100644 index 00000000000..46d7d33617b --- /dev/null +++ b/storage/perfschema/pfs_lock.h @@ -0,0 +1,173 @@ +/* Copyright (C) 2009 Sun Microsystems, Inc + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef PFS_LOCK_H +#define PFS_LOCK_H + +/** + @file storage/perfschema/pfs_lock.h + Performance schema internal locks (declarations). +*/ + +#include "pfs_atomic.h" + +/** + @addtogroup Performance_schema_buffers + @{ +*/ + +/** + State of a free record. + Values of a free record should not be read by a reader. + Writers can concurrently attempt to allocate a free record. +*/ +#define PFS_LOCK_FREE 0 +/** + State of a dirty record. + Values of a dirty record should not be read by a reader, + as the record is currently being modified. + Only one writer, the writer which owns the record, should + modify the record content. +*/ +#define PFS_LOCK_DIRTY 1 +/** + State of an allocated record. + Values of an allocated record are safe to read by a reader. + A writer may modify some but not all properties of the record: + only modifying values that can never cause the reader to crash is allowed. +*/ +#define PFS_LOCK_ALLOCATED 2 + +/** + A 'lock' protecting performance schema internal buffers. + This lock is used to mark the state of a record. + Access to the record is not enforced here, + it's up to the readers and writers to look at the record state + before making an actual read or write operation. +*/ +struct pfs_lock +{ + /** + The record internal state. + @sa PFS_LOCK_FREE + @sa PFS_LOCK_DIRTY + @sa PFS_LOCK_ALLOCATED + */ + volatile int32 m_state; + /** + The record internal version number. + This version number is to transform the 'ABA' problem + (see http://en.wikipedia.org/wiki/ABA_problem) + into an 'A(n)BA(n + 1)' problem, where 'n' is the m_version number. + When the performance schema instrumentation deletes a record, + then create a different record reusing the same memory allocation, + the version number is incremented, so that a reader can detect that + the record was changed. Note that the version number is never + reset to zero when a new record is created. + */ + volatile uint32 m_version; + + /** Returns true if the record is free. */ + bool is_free(void) + { + /* This is a dirty read */ + return (m_state == PFS_LOCK_FREE); + } + + /** Returns true if the record contains values that can be read. */ + bool is_populated(void) + { + int32 copy= m_state; /* non volatile copy, and dirty read */ + return (copy == PFS_LOCK_ALLOCATED); + } + + /** + Execute a free to dirty transition. + This transition is safe to execute concurrently by multiple writers. + Only one writer will succeed to acquire the record. + @return true if the operation succeed + */ + bool free_to_dirty(void) + { + int32 old_state= PFS_LOCK_FREE; + int32 new_state= PFS_LOCK_DIRTY; + + return (PFS_atomic::cas_32(&m_state, &old_state, new_state)); + } + + /** + Execute a dirty to allocated transition. + This transition should be executed by the writer that owns the record, + after the record is in a state ready to be read. + */ + void dirty_to_allocated(void) + { + DBUG_ASSERT(m_state == PFS_LOCK_DIRTY); + PFS_atomic::add_u32(&m_version, 1); + PFS_atomic::store_32(&m_state, PFS_LOCK_ALLOCATED); + } + + /** + Execute a dirty to free transition. + This transition should be executed by the writer that owns the record. + */ + void dirty_to_free(void) + { + DBUG_ASSERT(m_state == PFS_LOCK_DIRTY); + PFS_atomic::store_32(&m_state, PFS_LOCK_FREE); + } + + /** + Execute an allocated to free transition. + This transition should be executed by the writer that owns the record. + */ + void allocated_to_free(void) + { + DBUG_ASSERT(m_state == PFS_LOCK_ALLOCATED); + PFS_atomic::store_32(&m_state, PFS_LOCK_FREE); + } + + /** + Start an optimistic read operation. + @sa end_optimist_lock. + */ + void begin_optimistic_lock(struct pfs_lock *copy) + { + copy->m_version= PFS_atomic::load_u32(&m_version); + copy->m_state= PFS_atomic::load_32(&m_state); + } + + /** + End an optimistic read operation. + @sa begin_optimist_lock. + @return true if the data read is safe to use. + */ + bool end_optimistic_lock(struct pfs_lock *copy) + { + /* + return true if: + - the version + state has not changed + - and there was valid data to look at + */ + return ((copy->m_version == PFS_atomic::load_u32(&m_version)) && + (copy->m_state == PFS_atomic::load_32(&m_state)) && + (copy->m_state == PFS_LOCK_ALLOCATED)); + } +}; + + +/** @} */ +#endif + |