You've already forked mariadb-columnstore-engine
							
							
				mirror of
				https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
				synced 2025-10-30 07:25:34 +03:00 
			
		
		
		
	* feat(BRM,tools): couple utilities to watch/operate shared memory locks and extent map * feat(BRM,tools): merged two utilities and added some extra dbbuilder output in case of upgrade * fix(dbbuilder): extra output to log upgrade detection.
		
			
				
	
	
		
			332 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			332 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* Copyright (C) 2014 InfiniDB, 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., 51 Franklin Street, Fifth Floor, Boston,
 | |
|    MA 02110-1301, USA. */
 | |
| 
 | |
| /*****************************************************************************
 | |
|  * $Id$
 | |
|  *
 | |
|  ****************************************************************************/
 | |
| 
 | |
| #include <exception>
 | |
| #include <boost/scoped_ptr.hpp>
 | |
| 
 | |
| #include "configcpp.h"
 | |
| #include "IDBDataFile.h"
 | |
| #include "IDBPolicy.h"
 | |
| 
 | |
| #define BRMTBLLOCKSVR_DLLEXPORT
 | |
| #include "tablelockserver.h"
 | |
| #undef BRMTBLLOCKSVR_DLLEXPORT
 | |
| 
 | |
| using namespace std;
 | |
| using namespace boost;
 | |
| using namespace idbdatafile;
 | |
| 
 | |
| namespace BRM
 | |
| {
 | |
| TableLockServer::TableLockServer(SessionManagerServer* sm) : sms(sm)
 | |
| {
 | |
|   boost::mutex::scoped_lock lk(mutex);
 | |
|   config::Config* config = config::Config::makeConfig();
 | |
| 
 | |
|   filename = config->getConfig("SystemConfig", "TableLockSaveFile");
 | |
| 
 | |
|   if (filename == "")
 | |
|     throw invalid_argument(
 | |
|         "TableLockServer: Need to define SystemConfig/TableLockSaveFile in config file");  // todo, replace
 | |
|                                                                                            // this
 | |
| 
 | |
|   load();
 | |
| }
 | |
| 
 | |
| TableLockServer::~TableLockServer()
 | |
| {
 | |
| }
 | |
| 
 | |
| // call with lock held
 | |
| void TableLockServer::save()
 | |
| {
 | |
|   lit_t it;
 | |
|   uint32_t count = locks.size();
 | |
| 
 | |
|   const char* filename_p = filename.c_str();
 | |
| 
 | |
|   scoped_ptr<IDBDataFile> out(
 | |
|       IDBDataFile::open(IDBPolicy::getType(filename_p, IDBPolicy::WRITEENG), filename_p, "wb", 0));
 | |
| 
 | |
|   if (!out)
 | |
|     throw runtime_error("TableLockServer::save():  could not open save file");
 | |
| 
 | |
|   uint32_t bufferSize = 4;
 | |
|   for (const auto& lock : locks)
 | |
|     bufferSize += lock.second.getInternalSize();
 | |
| 
 | |
|   std::unique_ptr<char[]> buffer(new char[bufferSize]);
 | |
|   uint32_t offset = 0;
 | |
|   std::memcpy(&buffer[offset], (char*)&count, 4);
 | |
|   offset += 4;
 | |
| 
 | |
|   for (it = locks.begin(); it != locks.end(); ++it)
 | |
|     it->second.serialize(buffer.get(), offset);
 | |
| 
 | |
|   uint32_t writtenSize = 0;
 | |
|   uint32_t sizeToWrite = bufferSize;
 | |
|   while (writtenSize != bufferSize)
 | |
|   {
 | |
|     uint32_t ret = out->write(&buffer[writtenSize], sizeToWrite);
 | |
|     if (!ret)
 | |
|       throw runtime_error("TableLockServer::save():  could not write to the file");
 | |
| 
 | |
|     writtenSize += ret;
 | |
|     sizeToWrite -= ret;
 | |
|   }
 | |
| }
 | |
| 
 | |
| // call with lock held
 | |
| void TableLockServer::load()
 | |
| {
 | |
|   uint32_t size;
 | |
|   uint32_t i = 0;
 | |
|   TableLockInfo tli;
 | |
| 
 | |
|   /* Need to standardize the file error handling */
 | |
|   const char* filename_p = filename.c_str();
 | |
|   scoped_ptr<IDBDataFile> in(
 | |
|       IDBDataFile::open(IDBPolicy::getType(filename_p, IDBPolicy::WRITEENG), filename_p, "rb", 0));
 | |
| 
 | |
|   if (!in)
 | |
|   {
 | |
|     ostringstream os;
 | |
|     os << "TableLockServer::load(): either this is the first cluster start or could not open the save file" << filename;
 | |
|     log(os.str(), logging::LOG_TYPE_DEBUG);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   try
 | |
|   {
 | |
|     in->read((char*)&size, 4);
 | |
| 
 | |
|     for (i = 0; i < size; i++)
 | |
|     {
 | |
|       tli.deserialize(in.get());
 | |
|       tli.id = sms->getUnique64();  // Need new #s...
 | |
| 
 | |
|       if (tli.id == 0)  // 0 is an error code
 | |
|         tli.id = sms->getUnique64();
 | |
| 
 | |
|       locks[tli.id] = tli;
 | |
|     }
 | |
|   }
 | |
|   catch (std::exception& e)
 | |
|   {
 | |
|     ostringstream os;
 | |
|     os << "TableLockServer::load(): could not load save file " << filename << " loaded " << i << "/" << size
 | |
|        << " entries\n";
 | |
|     log(os.str(), logging::LOG_TYPE_DEBUG);
 | |
|     throw;
 | |
|   }
 | |
| }
 | |
| 
 | |
| // throws on a failed save()
 | |
| uint64_t TableLockServer::lock(TableLockInfo* tli)
 | |
| {
 | |
|   set<uint32_t> dbroots;
 | |
|   lit_t it;
 | |
|   uint32_t i;
 | |
|   boost::mutex::scoped_lock lk(mutex);
 | |
| 
 | |
|   for (i = 0; i < tli->dbrootList.size(); i++)
 | |
|     dbroots.insert(tli->dbrootList[i]);
 | |
| 
 | |
|   for (it = locks.begin(); it != locks.end(); ++it)
 | |
|   {
 | |
|     if (it->second.overlaps(*tli, dbroots))
 | |
|     {
 | |
|       tli->ownerName = it->second.ownerName;
 | |
|       tli->ownerPID = it->second.ownerPID;
 | |
|       tli->ownerSessionID = it->second.ownerSessionID;
 | |
|       tli->ownerTxnID = it->second.ownerTxnID;
 | |
|       return false;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   tli->id = sms->getUnique64();
 | |
| 
 | |
|   if (tli->id == 0)  // 0 is an error code
 | |
|     tli->id = sms->getUnique64();
 | |
| 
 | |
|   locks[tli->id] = *tli;
 | |
| 
 | |
|   try
 | |
|   {
 | |
|     save();
 | |
|   }
 | |
|   catch (...)
 | |
|   {
 | |
|     locks.erase(tli->id);
 | |
|     throw;
 | |
|   }
 | |
| 
 | |
|   return tli->id;
 | |
| }
 | |
| 
 | |
| bool TableLockServer::unlock(uint64_t id)
 | |
| {
 | |
|   std::map<uint64_t, TableLockInfo>::iterator it;
 | |
|   TableLockInfo tli;
 | |
| 
 | |
|   boost::mutex::scoped_lock lk(mutex);
 | |
|   it = locks.find(id);
 | |
| 
 | |
|   if (it != locks.end())
 | |
|   {
 | |
|     tli = it->second;
 | |
|     locks.erase(it);
 | |
| 
 | |
|     try
 | |
|     {
 | |
|       save();
 | |
|     }
 | |
|     catch (...)
 | |
|     {
 | |
|       locks[tli.id] = tli;
 | |
|       throw;
 | |
|     }
 | |
| 
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| bool TableLockServer::changeState(uint64_t id, LockState state)
 | |
| {
 | |
|   lit_t it;
 | |
|   boost::mutex::scoped_lock lk(mutex);
 | |
|   LockState old;
 | |
| 
 | |
|   it = locks.find(id);
 | |
| 
 | |
|   if (it == locks.end())
 | |
|     return false;
 | |
| 
 | |
|   old = it->second.state;
 | |
|   it->second.state = state;
 | |
| 
 | |
|   try
 | |
|   {
 | |
|     save();
 | |
|   }
 | |
|   catch (...)
 | |
|   {
 | |
|     it->second.state = old;
 | |
|     throw;
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool TableLockServer::changeOwner(uint64_t id, const string& ownerName, uint32_t pid, int32_t session,
 | |
|                                   int32_t txnID)
 | |
| {
 | |
|   lit_t it;
 | |
|   boost::mutex::scoped_lock lk(mutex);
 | |
|   string oldName;
 | |
|   uint32_t oldPID;
 | |
|   int32_t oldSession;
 | |
|   int32_t oldTxnID;
 | |
| 
 | |
|   it = locks.find(id);
 | |
| 
 | |
|   if (it == locks.end())
 | |
|     return false;
 | |
| 
 | |
|   oldName = it->second.ownerName;
 | |
|   oldPID = it->second.ownerPID;
 | |
|   oldSession = it->second.ownerSessionID;
 | |
|   oldTxnID = it->second.ownerTxnID;
 | |
|   it->second.ownerName = ownerName;
 | |
|   it->second.ownerPID = pid;
 | |
|   it->second.ownerSessionID = session;
 | |
|   it->second.ownerTxnID = txnID;
 | |
| 
 | |
|   try
 | |
|   {
 | |
|     save();
 | |
|   }
 | |
|   catch (...)
 | |
|   {
 | |
|     it->second.ownerName = oldName;
 | |
|     it->second.ownerPID = oldPID;
 | |
|     it->second.ownerSessionID = oldSession;
 | |
|     it->second.ownerTxnID = oldTxnID;
 | |
|     throw;
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| vector<TableLockInfo> TableLockServer::getAllLocks() const
 | |
| {
 | |
|   vector<TableLockInfo> ret;
 | |
|   boost::mutex::scoped_lock lk(mutex);
 | |
|   constlit_t it;
 | |
| 
 | |
|   for (it = locks.begin(); it != locks.end(); ++it)
 | |
|     ret.push_back(it->second);
 | |
| 
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| void TableLockServer::releaseAllLocks()
 | |
| {
 | |
|   std::map<uint64_t, TableLockInfo> tmp;
 | |
| 
 | |
|   boost::mutex::scoped_lock lk(mutex);
 | |
|   tmp.swap(locks);
 | |
| 
 | |
|   try
 | |
|   {
 | |
|     save();
 | |
|   }
 | |
|   catch (...)
 | |
|   {
 | |
|     tmp.swap(locks);
 | |
|     throw;
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool TableLockServer::getLockInfo(uint64_t id, TableLockInfo* out) const
 | |
| {
 | |
|   constlit_t it;
 | |
|   boost::mutex::scoped_lock lk(mutex);
 | |
| 
 | |
|   it = locks.find(id);
 | |
| 
 | |
|   if (out == NULL)
 | |
|     return (it != locks.end());
 | |
| 
 | |
|   if (it != locks.end())
 | |
|   {
 | |
|     *out = it->second;
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| }  // namespace BRM
 |