summaryrefslogtreecommitdiff
path: root/storage/perfschema/pfs_lock.h
diff options
context:
space:
mode:
Diffstat (limited to 'storage/perfschema/pfs_lock.h')
-rw-r--r--storage/perfschema/pfs_lock.h173
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
+