From: Kern Sibbald Date: Tue, 26 Jun 2007 14:43:32 +0000 (+0000) Subject: Move main SD locking code into lock.c (new file). X-Git-Tag: Release-7.0.0~6068 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=8710c6fb94ede9761c96906027e0b6ebec52b6b7;p=bacula%2Fbacula Move main SD locking code into lock.c (new file). git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@5100 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/kernstodo b/bacula/kernstodo index 068b7019bc..3fd1513432 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -58,6 +58,9 @@ Professional Needs: http://www.microsoft.com/technet/itshowcase/content/exchbkup.mspx Priority: +- Performance: multiple spool files for a single job. +- Performance: despool attributes when despooling data (problem + multiplexing Dir connection). - Make restore use the in-use volume reservation algorithm. - Look at mincore: http://insights.oetiker.ch/linux/fadvise.html - Unicode input http://en.wikipedia.org/wiki/Byte_Order_Mark diff --git a/bacula/src/stored/Makefile.in b/bacula/src/stored/Makefile.in index 490cb26483..9c7a8eafd0 100644 --- a/bacula/src/stored/Makefile.in +++ b/bacula/src/stored/Makefile.in @@ -25,40 +25,40 @@ SDOBJS = stored.o ansi_label.o \ askdir.o authenticate.o \ block.o butil.o dev.o \ device.o dircmd.o dvd.o ebcdic.o fd_cmds.o job.o \ - label.o locks.o mac.o match_bsr.o mount.o parse_bsr.o \ + label.o lock.o mac.o match_bsr.o mount.o parse_bsr.o \ pythonsd.o read.o read_record.o record.o \ reserve.o scan.o \ spool.o status.o stored_conf.o wait.o # btape TAPEOBJS = btape.o block.o butil.o dev.o device.o label.o \ - locks.o ansi_label.o dvd.o ebcdic.o \ + lock.o ansi_label.o dvd.o ebcdic.o \ autochanger.o acquire.o mount.o record.o read_record.o \ reserve.o \ stored_conf.o match_bsr.o parse_bsr.o scan.o spool.o wait.o # bls BLSOBJS = bls.o block.o butil.o device.o dev.o label.o match_bsr.o \ - ansi_label.o dvd.o ebcdic.o locks.o \ + ansi_label.o dvd.o ebcdic.o lock.o \ autochanger.o acquire.o mount.o parse_bsr.o record.o \ read_record.o reserve.o scan.o stored_conf.o spool.o wait.o # bextract BEXTOBJS = bextract.o block.o device.o dev.o label.o record.o \ - ansi_label.o dvd.o ebcdic.o locks.o \ + ansi_label.o dvd.o ebcdic.o lock.o \ autochanger.o acquire.o mount.o match_bsr.o parse_bsr.o butil.o \ pythonsd.o read_record.o reserve.o \ scan.o stored_conf.o spool.o wait.o # bscan SCNOBJS = bscan.o block.o device.o dev.o label.o \ - ansi_label.o dvd.o ebcdic.o locks.o \ + ansi_label.o dvd.o ebcdic.o lock.o \ autochanger.o acquire.o mount.o record.o match_bsr.o parse_bsr.o \ butil.o read_record.o scan.o reserve.o stored_conf.o spool.o wait.o # bcopy COPYOBJS = bcopy.o block.o device.o dev.o label.o \ - ansi_label.o dvd.o ebcdic.o locks.o \ + ansi_label.o dvd.o ebcdic.o lock.o \ autochanger.o acquire.o mount.o record.o match_bsr.o parse_bsr.o \ butil.o read_record.o reserve.o \ scan.o stored_conf.o spool.o wait.o diff --git a/bacula/src/stored/lock.c b/bacula/src/stored/lock.c new file mode 100644 index 0000000000..c57559dbf4 --- /dev/null +++ b/bacula/src/stored/lock.c @@ -0,0 +1,236 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2000-2007 Free Software Foundation Europe e.V. + + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation and included + in the file 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., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of John Walker. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ +/* + * Collection of Bacula Storage daemon locking software + * + * Kern Sibbald, 2000-2007. June 2007 + * + * Version $Id$ + */ + +#include "bacula.h" /* pull in global headers */ +#include "stored.h" /* pull in Storage Deamon headers */ + +#ifdef SD_DEBUG_LOCK +const int dbglvl = 0; +#else +const int dbglvl = 500; +#endif + + +void DEVICE::block(int why) +{ + r_dlock(); /* need recursive lock to block */ + block_device(this, why); + r_dunlock(); +} + +void DEVICE::unblock(bool locked) +{ + if (!locked) { + dlock(); + } + unblock_device(this); + dunlock(); +} + + +#ifdef SD_DEBUG_LOCK +void DEVICE::_dlock(const char *file, int line) +{ + Dmsg4(sd_dbglvl, "dlock from %s:%d precnt=%d JobId=%u\n", file, line, + m_count, get_jobid_from_tid()); + /* Note, this *really* should be protected by a mutex, but + * since it is only debug code we don't worry too much. + */ + if (m_count > 0 && pthread_equal(m_pid, pthread_self())) { + Dmsg5(sd_dbglvl, "Possible DEADLOCK!! lock held by JobId=%u from %s:%d m_count=%d JobId=%u\n", + get_jobid_from_tid(m_pid), + file, line, m_count, get_jobid_from_tid()); + } + P(m_mutex); + m_pid = pthread_self(); + m_count++; +} + +void DEVICE::_dunlock(const char *file, int line) +{ + m_count--; + Dmsg4(sd_dbglvl+1, "dunlock from %s:%d postcnt=%d JobId=%u\n", file, line, + m_count, get_jobid_from_tid()); + V(m_mutex); +} + +void DEVICE::_r_dunlock(const char *file, int line) +{ + this->_dunlock(file, line); +} + +#endif + + +/* + * This is a recursive lock that checks if the device is blocked. + * + * When blocked is set, all threads EXCEPT thread with id no_wait_id + * must wait. The no_wait_id thread is out obtaining a new volume + * and preparing the label. + */ +#ifdef SD_DEBUG_LOCK +void DEVICE::_r_dlock(const char *file, int line) +#else +void DEVICE::r_dlock() +#endif +{ + int stat; +#ifdef SD_DEBUG_LOCK + Dmsg4(sd_dbglvl+1, "r_dlock blked=%s from %s:%d JobId=%u\n", this->print_blocked(), + file, line, get_jobid_from_tid()); +#else + Dmsg1(sd_dbglvl, "reclock blked=%s\n", this->print_blocked()); +#endif + this->dlock(); + if (this->blocked() && !pthread_equal(this->no_wait_id, pthread_self())) { + this->num_waiting++; /* indicate that I am waiting */ + while (this->blocked()) { + Dmsg3(sd_dbglvl, "r_dlock blked=%s no_wait=%p me=%p\n", this->print_blocked(), + this->no_wait_id, pthread_self()); + if ((stat = pthread_cond_wait(&this->wait, &m_mutex)) != 0) { + berrno be; + this->dunlock(); + Emsg1(M_ABORT, 0, _("pthread_cond_wait failure. ERR=%s\n"), + be.bstrerror(stat)); + } + } + this->num_waiting--; /* no longer waiting */ + } +} + +/* + * Block all other threads from using the device + * Device must already be locked. After this call, + * the device is blocked to any thread calling dev->r_lock(), + * but the device is not locked (i.e. no P on device). Also, + * the current thread can do slip through the dev->r_lock() + * calls without blocking. + */ +void _block_device(const char *file, int line, DEVICE *dev, int state) +{ + ASSERT(dev->blocked() == BST_NOT_BLOCKED); + dev->set_blocked(state); /* make other threads wait */ + dev->no_wait_id = pthread_self(); /* allow us to continue */ + Dmsg3(sd_dbglvl, "set blocked=%s from %s:%d\n", dev->print_blocked(), file, line); +} + +/* + * Unblock the device, and wake up anyone who went to sleep. + * Enter: device locked + * Exit: device locked + */ +void _unblock_device(const char *file, int line, DEVICE *dev) +{ + Dmsg3(sd_dbglvl, "unblock %s from %s:%d\n", dev->print_blocked(), file, line); + ASSERT(dev->blocked()); + dev->set_blocked(BST_NOT_BLOCKED); + dev->no_wait_id = 0; + if (dev->num_waiting > 0) { + pthread_cond_broadcast(&dev->wait); /* wake them up */ + } +} + +/* + * Enter with device locked and blocked + * Exit with device unlocked and blocked by us. + */ +void _steal_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold, int state) +{ + + Dmsg3(sd_dbglvl, "steal lock. old=%s from %s:%d\n", dev->print_blocked(), + file, line); + hold->dev_blocked = dev->blocked(); + hold->dev_prev_blocked = dev->dev_prev_blocked; + hold->no_wait_id = dev->no_wait_id; + dev->set_blocked(state); + Dmsg1(sd_dbglvl, "steal lock. new=%s\n", dev->print_blocked()); + dev->no_wait_id = pthread_self(); + dev->dunlock(); +} + +/* + * Enter with device blocked by us but not locked + * Exit with device locked, and blocked by previous owner + */ +void _give_back_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold) +{ + Dmsg3(sd_dbglvl, "return lock. old=%s from %s:%d\n", + dev->print_blocked(), file, line); + dev->dlock(); + dev->set_blocked(hold->dev_blocked); + dev->dev_prev_blocked = hold->dev_prev_blocked; + dev->no_wait_id = hold->no_wait_id; + Dmsg1(sd_dbglvl, "return lock. new=%s\n", dev->print_blocked()); + if (dev->num_waiting > 0) { + pthread_cond_broadcast(&dev->wait); /* wake them up */ + } +} + +const char *DEVICE::print_blocked() const +{ + switch (m_blocked) { + case BST_NOT_BLOCKED: + return "BST_NOT_BLOCKED"; + case BST_UNMOUNTED: + return "BST_UNMOUNTED"; + case BST_WAITING_FOR_SYSOP: + return "BST_WAITING_FOR_SYSOP"; + case BST_DOING_ACQUIRE: + return "BST_DOING_ACQUIRE"; + case BST_WRITING_LABEL: + return "BST_WRITING_LABEL"; + case BST_UNMOUNTED_WAITING_FOR_SYSOP: + return "BST_UNMOUNTED_WAITING_FOR_SYSOP"; + case BST_MOUNT: + return "BST_MOUNT"; + default: + return _("unknown blocked code"); + } +} + + +/* + * Check if the device is blocked or not + */ +bool is_device_unmounted(DEVICE *dev) +{ + bool stat; + int blocked = dev->blocked(); + stat = (blocked == BST_UNMOUNTED) || + (blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP); + return stat; +} + diff --git a/bacula/src/stored/locks.c b/bacula/src/stored/locks.c deleted file mode 100644 index c57559dbf4..0000000000 --- a/bacula/src/stored/locks.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - Bacula® - The Network Backup Solution - - Copyright (C) 2000-2007 Free Software Foundation Europe e.V. - - The main author of Bacula is Kern Sibbald, with contributions from - many others, a complete list can be found in the file AUTHORS. - This program is Free Software; you can redistribute it and/or - modify it under the terms of version two of the GNU General Public - License as published by the Free Software Foundation and included - in the file 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., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. - - Bacula® is a registered trademark of John Walker. - The licensor of Bacula is the Free Software Foundation Europe - (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, - Switzerland, email:ftf@fsfeurope.org. -*/ -/* - * Collection of Bacula Storage daemon locking software - * - * Kern Sibbald, 2000-2007. June 2007 - * - * Version $Id$ - */ - -#include "bacula.h" /* pull in global headers */ -#include "stored.h" /* pull in Storage Deamon headers */ - -#ifdef SD_DEBUG_LOCK -const int dbglvl = 0; -#else -const int dbglvl = 500; -#endif - - -void DEVICE::block(int why) -{ - r_dlock(); /* need recursive lock to block */ - block_device(this, why); - r_dunlock(); -} - -void DEVICE::unblock(bool locked) -{ - if (!locked) { - dlock(); - } - unblock_device(this); - dunlock(); -} - - -#ifdef SD_DEBUG_LOCK -void DEVICE::_dlock(const char *file, int line) -{ - Dmsg4(sd_dbglvl, "dlock from %s:%d precnt=%d JobId=%u\n", file, line, - m_count, get_jobid_from_tid()); - /* Note, this *really* should be protected by a mutex, but - * since it is only debug code we don't worry too much. - */ - if (m_count > 0 && pthread_equal(m_pid, pthread_self())) { - Dmsg5(sd_dbglvl, "Possible DEADLOCK!! lock held by JobId=%u from %s:%d m_count=%d JobId=%u\n", - get_jobid_from_tid(m_pid), - file, line, m_count, get_jobid_from_tid()); - } - P(m_mutex); - m_pid = pthread_self(); - m_count++; -} - -void DEVICE::_dunlock(const char *file, int line) -{ - m_count--; - Dmsg4(sd_dbglvl+1, "dunlock from %s:%d postcnt=%d JobId=%u\n", file, line, - m_count, get_jobid_from_tid()); - V(m_mutex); -} - -void DEVICE::_r_dunlock(const char *file, int line) -{ - this->_dunlock(file, line); -} - -#endif - - -/* - * This is a recursive lock that checks if the device is blocked. - * - * When blocked is set, all threads EXCEPT thread with id no_wait_id - * must wait. The no_wait_id thread is out obtaining a new volume - * and preparing the label. - */ -#ifdef SD_DEBUG_LOCK -void DEVICE::_r_dlock(const char *file, int line) -#else -void DEVICE::r_dlock() -#endif -{ - int stat; -#ifdef SD_DEBUG_LOCK - Dmsg4(sd_dbglvl+1, "r_dlock blked=%s from %s:%d JobId=%u\n", this->print_blocked(), - file, line, get_jobid_from_tid()); -#else - Dmsg1(sd_dbglvl, "reclock blked=%s\n", this->print_blocked()); -#endif - this->dlock(); - if (this->blocked() && !pthread_equal(this->no_wait_id, pthread_self())) { - this->num_waiting++; /* indicate that I am waiting */ - while (this->blocked()) { - Dmsg3(sd_dbglvl, "r_dlock blked=%s no_wait=%p me=%p\n", this->print_blocked(), - this->no_wait_id, pthread_self()); - if ((stat = pthread_cond_wait(&this->wait, &m_mutex)) != 0) { - berrno be; - this->dunlock(); - Emsg1(M_ABORT, 0, _("pthread_cond_wait failure. ERR=%s\n"), - be.bstrerror(stat)); - } - } - this->num_waiting--; /* no longer waiting */ - } -} - -/* - * Block all other threads from using the device - * Device must already be locked. After this call, - * the device is blocked to any thread calling dev->r_lock(), - * but the device is not locked (i.e. no P on device). Also, - * the current thread can do slip through the dev->r_lock() - * calls without blocking. - */ -void _block_device(const char *file, int line, DEVICE *dev, int state) -{ - ASSERT(dev->blocked() == BST_NOT_BLOCKED); - dev->set_blocked(state); /* make other threads wait */ - dev->no_wait_id = pthread_self(); /* allow us to continue */ - Dmsg3(sd_dbglvl, "set blocked=%s from %s:%d\n", dev->print_blocked(), file, line); -} - -/* - * Unblock the device, and wake up anyone who went to sleep. - * Enter: device locked - * Exit: device locked - */ -void _unblock_device(const char *file, int line, DEVICE *dev) -{ - Dmsg3(sd_dbglvl, "unblock %s from %s:%d\n", dev->print_blocked(), file, line); - ASSERT(dev->blocked()); - dev->set_blocked(BST_NOT_BLOCKED); - dev->no_wait_id = 0; - if (dev->num_waiting > 0) { - pthread_cond_broadcast(&dev->wait); /* wake them up */ - } -} - -/* - * Enter with device locked and blocked - * Exit with device unlocked and blocked by us. - */ -void _steal_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold, int state) -{ - - Dmsg3(sd_dbglvl, "steal lock. old=%s from %s:%d\n", dev->print_blocked(), - file, line); - hold->dev_blocked = dev->blocked(); - hold->dev_prev_blocked = dev->dev_prev_blocked; - hold->no_wait_id = dev->no_wait_id; - dev->set_blocked(state); - Dmsg1(sd_dbglvl, "steal lock. new=%s\n", dev->print_blocked()); - dev->no_wait_id = pthread_self(); - dev->dunlock(); -} - -/* - * Enter with device blocked by us but not locked - * Exit with device locked, and blocked by previous owner - */ -void _give_back_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold) -{ - Dmsg3(sd_dbglvl, "return lock. old=%s from %s:%d\n", - dev->print_blocked(), file, line); - dev->dlock(); - dev->set_blocked(hold->dev_blocked); - dev->dev_prev_blocked = hold->dev_prev_blocked; - dev->no_wait_id = hold->no_wait_id; - Dmsg1(sd_dbglvl, "return lock. new=%s\n", dev->print_blocked()); - if (dev->num_waiting > 0) { - pthread_cond_broadcast(&dev->wait); /* wake them up */ - } -} - -const char *DEVICE::print_blocked() const -{ - switch (m_blocked) { - case BST_NOT_BLOCKED: - return "BST_NOT_BLOCKED"; - case BST_UNMOUNTED: - return "BST_UNMOUNTED"; - case BST_WAITING_FOR_SYSOP: - return "BST_WAITING_FOR_SYSOP"; - case BST_DOING_ACQUIRE: - return "BST_DOING_ACQUIRE"; - case BST_WRITING_LABEL: - return "BST_WRITING_LABEL"; - case BST_UNMOUNTED_WAITING_FOR_SYSOP: - return "BST_UNMOUNTED_WAITING_FOR_SYSOP"; - case BST_MOUNT: - return "BST_MOUNT"; - default: - return _("unknown blocked code"); - } -} - - -/* - * Check if the device is blocked or not - */ -bool is_device_unmounted(DEVICE *dev) -{ - bool stat; - int blocked = dev->blocked(); - stat = (blocked == BST_UNMOUNTED) || - (blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP); - return stat; -} - diff --git a/bacula/src/version.h b/bacula/src/version.h index 2bce5f5292..4a72952153 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -3,7 +3,7 @@ */ #undef VERSION -#define VERSION "2.1.22" +#define VERSION "2.1.23" #define BDATE "26 June 2007" #define LSMDATE "26Jun07" diff --git a/bacula/technotes-2.1 b/bacula/technotes-2.1 index 93230e409c..8da5e9fe6b 100644 --- a/bacula/technotes-2.1 +++ b/bacula/technotes-2.1 @@ -2,6 +2,9 @@ General: +26Jun07 +kes Move main SD locking code into lock.c (new file). + Release 2.1.22 beta 26Jun07 kes Dirk committed the qwt library code for drawing graphs in bat.