mirror of
https://github.com/MariaDB/server.git
synced 2025-01-20 14:02:32 +01:00
67a48e1a4c
Part V: performance schema implementation
173 lines
4.9 KiB
C
173 lines
4.9 KiB
C
/* 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
|
|
|