Drizzled Public API Documentation

locks.cc
00001 /* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2010 Brian Aker
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 #include <config.h>
00022 #include <plugin/user_locks/module.h>
00023 
00024 #include <boost/thread/locks.hpp>
00025 
00026 #include <string>
00027 
00028 namespace user_locks {
00029 
00030 bool Locks::lock(drizzled::session_id_t id_arg, const user_locks::Key &arg, int64_t wait_for)
00031 {
00032   boost::unique_lock<boost::mutex> scope(mutex);
00033   boost::system_time timeout= boost::get_system_time() + boost::posix_time::seconds(wait_for);
00034   
00035   LockMap::iterator iter;
00036   while ((iter= lock_map.find(arg)) != lock_map.end())
00037   {
00038     if (id_arg == iter->second->id)
00039     {
00040       // We own the lock, so we just exit.
00041       return true;
00042     }
00043     try {
00044       if (wait_for)
00045       {
00046         bool success= release_cond.timed_wait(scope, timeout);
00047 
00048         if (not success)
00049           return false;
00050       }
00051       else
00052       {
00053         release_cond.wait(scope);
00054       }
00055     }
00056     catch(boost::thread_interrupted const& error)
00057     {
00058       // Currently nothing is done here.
00059       throw error;
00060     }
00061   }
00062 
00063   if (iter == lock_map.end())
00064   {
00065     create_cond.notify_all();
00066     return lock_map.insert(std::make_pair(arg, new Lock(id_arg))).second;
00067   }
00068 
00069   return false;
00070 }
00071 
00072 // Currently we just let timeouts occur, and the caller will need to know
00073 // what it is looking for/whether to go back into this.
00074 void Locks::waitCreate(int64_t wait_for)
00075 {
00076   boost::unique_lock<boost::mutex> scope(mutex);
00077   boost::system_time timeout= boost::get_system_time() + boost::posix_time::seconds(wait_for);
00078   bool timed_out;
00079 
00080   try {
00081     timed_out= create_cond.timed_wait(scope, timeout);
00082   }
00083   catch(boost::thread_interrupted const& error)
00084   {
00085     // Currently nothing is done here.
00086     throw error;
00087   }
00088 }
00089 
00090 bool Locks::lock(drizzled::session_id_t id_arg, const user_locks::Keys &arg)
00091 {
00092   boost::unique_lock<boost::mutex> scope(mutex);
00093   user_locks::Keys created;
00094   bool error= false;
00095 
00096   for (user_locks::Keys::const_iterator iter= arg.begin(); iter != arg.end(); iter++)
00097   {
00098     LockMap::iterator record= lock_map.find(*iter);
00099 
00100     if (record != lock_map.end()) // Found, so check ownership of the lock
00101     {
00102       if (id_arg != (*record).second->id)
00103       {
00104         // So it turns out the locks exist, and we can't grab them all
00105         error= true;
00106         break;
00107       }
00108     }
00109     else
00110     {
00111       lock_map.insert(std::make_pair(*iter, new Lock(id_arg)));
00112       created.insert(*iter);
00113     }
00114   }
00115 
00116   if (error)
00117   {
00118     for (user_locks::Keys::const_iterator iter= created.begin(); iter != created.end(); iter++)
00119     {
00120       lock_map.erase(*iter);
00121     }
00122 
00123     return false;
00124   }
00125 
00126   create_cond.notify_all();
00127 
00128   return true;
00129 }
00130 
00131 bool Locks::isUsed(const user_locks::Key &arg, drizzled::session_id_t &id_arg)
00132 {
00133   boost::unique_lock<boost::mutex> scope(mutex);
00134   
00135   LockMap::iterator iter= lock_map.find(arg);
00136   
00137   if ( iter == lock_map.end())
00138     return false;
00139 
00140   id_arg= iter->second->id;
00141 
00142   return true;
00143 }
00144 
00145 bool Locks::isFree(const user_locks::Key &arg)
00146 {
00147   boost::unique_lock<boost::mutex> scope(mutex);
00148 
00149   LockMap::iterator iter= lock_map.find(arg);
00150   
00151   return iter != lock_map.end();
00152 }
00153 
00154 void Locks::Copy(LockMap &lock_map_arg)
00155 {
00156   boost::unique_lock<boost::mutex> scope(mutex);
00157   lock_map_arg= lock_map;
00158 }
00159 
00160 locks::return_t Locks::release(const user_locks::Key &arg, drizzled::session_id_t &id_arg, bool and_wait)
00161 {
00162   size_t elements= 0;
00163   boost::unique_lock<boost::mutex> scope(mutex);
00164   LockMap::iterator iter= lock_map.find(arg);
00165 
00166   // Nothing is found
00167   if ( iter == lock_map.end())
00168     return locks::NOT_FOUND;
00169 
00170   if (iter->second->id == id_arg)
00171   {
00172     elements= lock_map.erase(arg);
00173     assert(elements); // If we can't find what we just found, then we are broken
00174 
00175     if (elements)
00176     {
00177       release_cond.notify_one();
00178 
00179       if (and_wait)
00180       {
00181         bool found= false;
00182         while (not found)
00183         {
00184           assert(boost::this_thread::interruption_enabled());
00185           try {
00186             create_cond.wait(scope);
00187           }
00188           catch(boost::thread_interrupted const& error)
00189           {
00190             // Currently nothing is done here.
00191             throw error;
00192           }
00193           iter= lock_map.find(arg);
00194 
00195           if (iter != lock_map.end())
00196             found= true;
00197         }
00198       }
00199 
00200       return locks::SUCCESS;
00201     }
00202   }
00203 
00204   return locks::NOT_OWNED_BY;
00205 }
00206 
00207 } /* namespace user_locks */