mirror of
https://github.com/MariaDB/server.git
synced 2025-08-07 00:04:31 +03:00
post-review fixes
include/atomic/generic-msvc.h: prevent possible compiler warnings include/lf.h: comments, better definition for LF_HASH_OVERHEAD include/maria.h: define MARIA_CANNOT_ROLLBACK here include/my_pthread.h: avoid possible name clash include/waiting_threads.h: comments, const, move WT_RESOURCE to waiting_threads.c mysql-test/suite/maria/r/maria_notembedded.result: new test mysql-test/suite/maria/t/maria_notembedded.test: new test - 5-way deadlock mysys/lf_hash.c: better definition for LF_HASH_OVERHEAD mysys/my_static.c: comment mysys/my_thr_init.c: casts mysys/waiting_threads.c: comments, asserts, etc server-tools/instance-manager/parse.cc: fix my_init_dynamic_array() to follow new calling conventions sql/mysqld.cc: call wt_init after set_proper_floating_point_mode sql/sql_class.h: comment storage/maria/ha_maria.cc: move MARIA_CANNOT_ROLLBACK to a common header storage/maria/ma_commit.c: comment storage/maria/ma_write.c: comments, check for HA_ERR_FOUND_DUPP_KEY storage/maria/trnman.c: comments, assert storage/maria/trnman.h: comments storage/maria/unittest/trnman-t.c: be paranoid unittest/mysys/lf-t.c: comments unittest/mysys/waiting_threads-t.c: comments, safety, memory leak
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2008 MySQL AB
|
||||
/* Copyright (C) 2008 MySQL AB, 2008-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
|
||||
@@ -24,16 +24,18 @@
|
||||
C_MODE_START
|
||||
|
||||
typedef struct st_wt_resource_id WT_RESOURCE_ID;
|
||||
typedef struct st_wt_resource WT_RESOURCE;
|
||||
|
||||
typedef struct st_wt_resource_type {
|
||||
int (*compare)(void *a, void *b);
|
||||
const void *(*make_key)(WT_RESOURCE_ID *id, uint *len);
|
||||
my_bool (*compare)(const void *a, const void *b);
|
||||
const void *(*make_key)(const WT_RESOURCE_ID *id, uint *len); /* not used */
|
||||
} WT_RESOURCE_TYPE;
|
||||
|
||||
struct st_wt_resource_id {
|
||||
ulonglong value;
|
||||
WT_RESOURCE_TYPE *type;
|
||||
const WT_RESOURCE_TYPE *type;
|
||||
};
|
||||
/* the below differs from sizeof(WT_RESOURCE_ID) by the amount of padding */
|
||||
#define sizeof_WT_RESOURCE_ID (sizeof(ulonglong)+sizeof(void*))
|
||||
|
||||
#define WT_WAIT_STATS 24
|
||||
@@ -43,93 +45,17 @@ extern uint32 wt_wait_stats[WT_WAIT_STATS+1];
|
||||
extern uint32 wt_cycle_stats[2][WT_CYCLE_STATS+1];
|
||||
extern uint32 wt_success_stats;
|
||||
|
||||
/*
|
||||
'lock' protects 'owners', 'state', and 'waiter_count'
|
||||
'id' is read-only
|
||||
|
||||
a resource is picked up from a hash in a lock-free manner
|
||||
it's returned pinned, so it cannot be freed at once
|
||||
but it may be freed right after the pin is removed
|
||||
to free a resource it should be
|
||||
1. have no owners
|
||||
2. have no waiters
|
||||
|
||||
two ways to access a resource:
|
||||
1. find it in a hash
|
||||
- it's returned pinned.
|
||||
a) take a lock in exclusive mode
|
||||
b) check the state, it should be ACTIVE
|
||||
c) unpin
|
||||
2. by a direct reference
|
||||
- could only used if a resource cannot be freed
|
||||
e.g. accessing a resource by thd->waiting_for is safe,
|
||||
a resource cannot be freed as there's a thread waiting for it
|
||||
*/
|
||||
typedef struct st_wt_resource {
|
||||
WT_RESOURCE_ID id;
|
||||
uint waiter_count;
|
||||
enum { ACTIVE, FREE } state;
|
||||
#ifndef DBUG_OFF
|
||||
pthread_mutex_t *mutex;
|
||||
#endif
|
||||
/*
|
||||
before the 'lock' all elements are mutable, after (and including) -
|
||||
immutable in the sense that lf_hash_insert() won't memcpy() over them.
|
||||
See wt_init().
|
||||
*/
|
||||
#ifdef WT_RWLOCKS_USE_MUTEXES
|
||||
/*
|
||||
we need a special rwlock-like 'lock' to allow readers bypass
|
||||
waiting writers, otherwise readers can deadlock. For example:
|
||||
|
||||
A waits on resource x, owned by B, B waits on resource y, owned
|
||||
by A, we have a cycle (A->x->B->y->A)
|
||||
Both A and B start deadlock detection:
|
||||
|
||||
A locks x B locks y
|
||||
A goes deeper B goes deeper
|
||||
A locks y B locks x
|
||||
|
||||
with mutexes it would deadlock. With rwlocks it won't, as long
|
||||
as both A and B are taking read locks (and they do).
|
||||
But other threads may take write locks. Assume there's
|
||||
C who wants to start waiting on x, and D who wants to start
|
||||
waiting on y.
|
||||
|
||||
A read-locks x B read-locks y
|
||||
A goes deeper B goes deeper
|
||||
=> C write-locks x (to add a new edge) D write-locks y
|
||||
.. C is blocked D is blocked
|
||||
A read-locks y B read-locks x
|
||||
|
||||
Now, if a read lock can bypass a pending wrote lock request, we're fine.
|
||||
If it can not, we have a deadlock.
|
||||
|
||||
writer starvation is technically possible, but unlikely, because
|
||||
the contention is expected to be low.
|
||||
*/
|
||||
struct {
|
||||
pthread_cond_t cond;
|
||||
pthread_mutex_t mutex;
|
||||
uint readers: 16;
|
||||
uint pending_writers: 15;
|
||||
uint write_locked: 1;
|
||||
} lock;
|
||||
#else
|
||||
rw_lock_t lock;
|
||||
#endif
|
||||
pthread_cond_t cond;
|
||||
DYNAMIC_ARRAY owners;
|
||||
} WT_RESOURCE;
|
||||
|
||||
typedef struct st_wt_thd {
|
||||
/*
|
||||
XXX
|
||||
there's no protection (mutex) against concurrent access of
|
||||
the dynarray below. it is assumed that a caller will have it
|
||||
automatically (not to protect this array but to protect its
|
||||
own - caller's - data structures, and we'll get it for free.
|
||||
If not, we'll need to add a mutex
|
||||
there's no protection (mutex) against concurrent access of the
|
||||
dynarray below. it is assumed that a caller will have it anyway
|
||||
(not to protect this array but to protect its own - caller's -
|
||||
data structures), and we'll get it for free. A caller needs to
|
||||
ensure that a blocker won't release a resource before a blocked
|
||||
thread starts waiting, which is usually done with a mutex.
|
||||
|
||||
If the above assumption is wrong, we'll need to add a mutex here.
|
||||
*/
|
||||
DYNAMIC_ARRAY my_resources;
|
||||
/*
|
||||
@@ -141,8 +67,10 @@ typedef struct st_wt_thd {
|
||||
LF_PINS *pins;
|
||||
|
||||
/* pointers to values */
|
||||
ulong *timeout_short, *deadlock_search_depth_short;
|
||||
ulong *timeout_long, *deadlock_search_depth_long;
|
||||
const ulong *timeout_short;
|
||||
const ulong *deadlock_search_depth_short;
|
||||
const ulong *timeout_long;
|
||||
const ulong *deadlock_search_depth_long;
|
||||
|
||||
/*
|
||||
weight relates to the desirability of a transaction being killed if it's
|
||||
@@ -169,13 +97,13 @@ typedef struct st_wt_thd {
|
||||
*/
|
||||
ulong volatile weight;
|
||||
/*
|
||||
'killed' is indirectly protected by waiting_for->lock -
|
||||
a killed thread needs to clear its 'waiting_for', and thus needs a lock.
|
||||
'killed' is indirectly protected by waiting_for->lock because
|
||||
a killed thread needs to clear its 'waiting_for' and thus needs a lock.
|
||||
That is a thread needs an exclusive lock to read 'killed' reliably.
|
||||
But other threads may change 'killed' from 0 to 1, a shared
|
||||
lock is enough for that.
|
||||
*/
|
||||
my_bool volatile killed;
|
||||
my_bool killed;
|
||||
#ifndef DBUG_OFF
|
||||
const char *name;
|
||||
#endif
|
||||
@@ -189,13 +117,13 @@ typedef struct st_wt_thd {
|
||||
|
||||
void wt_init(void);
|
||||
void wt_end(void);
|
||||
void wt_thd_lazy_init(WT_THD *, ulong *, ulong *, ulong *, ulong *);
|
||||
void wt_thd_lazy_init(WT_THD *, const ulong *, const ulong *, const ulong *, const ulong *);
|
||||
void wt_thd_destroy(WT_THD *);
|
||||
int wt_thd_will_wait_for(WT_THD *, WT_THD *, WT_RESOURCE_ID *);
|
||||
int wt_thd_will_wait_for(WT_THD *, WT_THD *, const WT_RESOURCE_ID *);
|
||||
int wt_thd_cond_timedwait(WT_THD *, pthread_mutex_t *);
|
||||
void wt_thd_release(WT_THD *, WT_RESOURCE_ID *);
|
||||
void wt_thd_release(WT_THD *, const WT_RESOURCE_ID *);
|
||||
#define wt_thd_release_all(THD) wt_thd_release((THD), 0)
|
||||
int wt_resource_id_memcmp(void *, void *);
|
||||
int wt_resource_id_memcmp(const void *, const void *);
|
||||
|
||||
C_MODE_END
|
||||
|
||||
|
Reference in New Issue
Block a user