/NameNode/src/mdfs/namenode/sql/MySQLUpdater.java

https://bitbucket.org/crholm/mdfs · Java · 342 lines · 219 code · 49 blank · 74 comment · 7 complexity · c5b0c68b4742cba3f77726074824b840 MD5 · raw file

  1. package mdfs.namenode.sql;
  2. import java.sql.Connection;
  3. import java.sql.SQLException;
  4. import java.util.concurrent.ConcurrentLinkedQueue;
  5. import java.util.concurrent.locks.ReentrantLock;
  6. import mdfs.namenode.repositories.DataNodeInfoRepositoryNode;
  7. import mdfs.namenode.repositories.MetaDataRepositoryNode;
  8. import mdfs.namenode.repositories.UserDataRepositoryNode;
  9. import mdfs.utils.Config;
  10. /**
  11. * This Class is a threaded Singelton that helps other classes to execute query that need no response.
  12. * It works in a way that a thread is intermittently executing querys to the MySQL database specified mdfs/config/config.cfg
  13. * The MySQL.update.rate in the config.cfg is the milliseconds that the thread sleeps before checking if any querys
  14. * are queued to be issued.
  15. * This enables other classes to just enqueue a query and not having to wait for a response from the SQL server.
  16. * MySQLUpdater works in a way that other classes can queue items even if MySQLUpdater is currently executing querys
  17. * from said queue. This helps MDFS performance since no other pars of the software have to wait on a SQL server.
  18. *
  19. * @author Rasmus Holm
  20. *
  21. */
  22. public class MySQLUpdater implements Runnable{
  23. private static MySQLUpdater instance = null;
  24. private Thread thread = null;
  25. private int updateRate = Config.getInt("MySQL.update.rate");
  26. private ConcurrentLinkedQueue<String> queue1 = new ConcurrentLinkedQueue<String>();
  27. private ConcurrentLinkedQueue<String> queue2 = new ConcurrentLinkedQueue<String>();
  28. private boolean queue1IsInUse = false;
  29. private MySQLDeleteInsertUpdate updater = new MySQLDeleteInsertUpdate();
  30. ReentrantLock lock = new ReentrantLock();
  31. private MySQLUpdater(){
  32. thread = new Thread(this);
  33. thread.start();
  34. }
  35. public static MySQLUpdater getInstance(){
  36. if(instance == null){
  37. instance = new MySQLUpdater();
  38. }
  39. return instance;
  40. }
  41. /*
  42. * By using 2 queues other classes can always enqueue querys without waiting for the updating
  43. * thread to be finished. This way other classes never have to wait for sql related performance issues
  44. */
  45. @Override
  46. public void run() {
  47. Connection connection = null;
  48. while(true){
  49. //Locks the queue 1 and all new query queued in queue2
  50. lock.lock();
  51. try{
  52. queue1IsInUse = true;
  53. }finally{
  54. lock.unlock();
  55. }
  56. // Executing updates from queue 1, if any
  57. if(!queue1.isEmpty()){
  58. connection = new MySQLConnector().getConnection();
  59. String query;
  60. while((query = queue1.poll()) != null){
  61. updater.update(connection, query);
  62. }
  63. try {
  64. connection.close();
  65. } catch (SQLException e) {
  66. e.printStackTrace();
  67. }
  68. }
  69. //Unlocks queue1 and and all new query queued in queue1 again
  70. lock.lock();
  71. try{
  72. queue1IsInUse = false;
  73. }finally{
  74. lock.unlock();
  75. }
  76. // // Executing updates from queue 2
  77. if(!queue2.isEmpty()){
  78. connection = new MySQLConnector().getConnection();
  79. String query;
  80. while((query = queue2.poll()) != null){
  81. updater.update(connection, query);
  82. }
  83. try {
  84. connection.close();
  85. } catch (SQLException e) {
  86. e.printStackTrace();
  87. }
  88. }
  89. //Sleeps a while to wait for new querys
  90. try {
  91. Thread.sleep(updateRate);
  92. } catch (InterruptedException e) {}
  93. }
  94. }
  95. /*
  96. * enqueus a new item in the queue for querys to be updated.
  97. * if queue1 is in use queue2 is used
  98. */
  99. private void enqueue(String query){
  100. lock.lock();
  101. try{
  102. if(queue1IsInUse){
  103. queue2.add(query);
  104. }else{
  105. queue1.add(query);
  106. }
  107. }finally{
  108. lock.unlock();
  109. }
  110. }
  111. /**
  112. * Forces the MySQLUpdater to execute querys enqueued
  113. */
  114. public void push(){
  115. thread.interrupt();
  116. }
  117. /**
  118. * Updates the node in permanent storage
  119. * @param node the MetaDataRepositoryNode that is to be updated in SQL
  120. */
  121. public void updateMetaData(MetaDataRepositoryNode node){
  122. lock.lock();
  123. try{
  124. enqueue(createMetaDataRowSQLStatement(node));
  125. }finally{
  126. lock.unlock();
  127. }
  128. }
  129. /**
  130. * Deletes a MetaDataRepositoryNode as stored in the MySQL database
  131. * @param filePath the logical MDFS path to the node that is to be deleted from the SQL
  132. */
  133. public void deleteMetaData(String filePath){
  134. lock.lock();
  135. try{
  136. enqueue(createMetaDataDeleteRowStatement(filePath));
  137. }finally{
  138. lock.unlock();
  139. }
  140. }
  141. /**
  142. * Deletes a MetaDataRepositoryNode as stored in the MySQL database
  143. * @param node The node that is to be deleted from SQL
  144. */
  145. public void deleteMetaData(MetaDataRepositoryNode node){
  146. deleteMetaData(node.getFilePath());
  147. }
  148. /**
  149. * Updates the node in permanent storage
  150. * @param node the node that is to be updated
  151. */
  152. public void updateUserData(UserDataRepositoryNode node){
  153. lock.lock();
  154. try{
  155. enqueue(createUserDataRowSQLStatement(node));
  156. }finally{
  157. lock.unlock();
  158. }
  159. }
  160. /**
  161. * Removes node from permanent storage
  162. * @param node the node that is to be removed
  163. */
  164. public void removeUserData(UserDataRepositoryNode node) {
  165. lock.lock();
  166. try{
  167. enqueue(createUserDataDeleteRowSQLStatement(node));
  168. }finally{
  169. lock.unlock();
  170. }
  171. // DELETE FROM `mdfs`.`user-data` WHERE `user-data`.`name` = \'test2\'
  172. }
  173. /**
  174. * Updates the node in permanent storage
  175. * @param node the node that is to be updated
  176. */
  177. public void updateDataNode(DataNodeInfoRepositoryNode node) {
  178. lock.lock();
  179. try{
  180. enqueue(createDataNodeRowSQLStatement(node));
  181. }finally{
  182. lock.unlock();
  183. }
  184. }
  185. /**
  186. * Updates the relation between a MetaDataRepositoryNode DataNodeInfoRepositoryNode in permanent storage
  187. * @param metaData The MetaDataRepositoryNode that has relation to DataNodeInfoRepositoryNode
  188. * @param dataNode The DataNodeInfoRepositoryNode that has relation to MetaDataRepositoryNode
  189. */
  190. public void updateMetaDataDataNodeRelation( MetaDataRepositoryNode metaData, DataNodeInfoRepositoryNode dataNode) {
  191. lock.lock();
  192. try{
  193. enqueue(createMetaDataDataNodeRelation(metaData, dataNode));
  194. }finally{
  195. lock.unlock();
  196. }
  197. }
  198. /*
  199. * Creates SQL statement executing update
  200. */
  201. private String createMetaDataDataNodeRelation(MetaDataRepositoryNode metaData, DataNodeInfoRepositoryNode dataNode) {
  202. return "INSERT INTO `" + Config.getString("MySQL.db") + "`.`" + Config.getString("MySQL.prefix") + "meta-data_data-node` " +
  203. "(`Meta_Data_filePath`, " +
  204. "`Data_Node_Name`) " +
  205. "VALUES (" +
  206. "'" + metaData.getFilePath() + "', " +
  207. "'" + dataNode.getName() + "'" +
  208. ");";
  209. }
  210. /*
  211. * Creates SQL statement executing update
  212. */
  213. private String createDataNodeRowSQLStatement(DataNodeInfoRepositoryNode node) {
  214. return "INSERT INTO `" + Config.getString("MySQL.db") + "`.`" + Config.getString("MySQL.prefix") + "data-node` (" +
  215. "`name`, " +
  216. "`address`, " +
  217. "`port`" +
  218. ") " +
  219. "VALUES (" +
  220. "'" + node.getName() + "', " +
  221. "'" + node.getAddress() + "', " +
  222. "'" + node.getPort() + "'" +
  223. ")" +
  224. "ON DUPLICATE KEY UPDATE" +
  225. "`name` = '" + node.getName() + "', " +
  226. "`address` = '" + node.getAddress() + "', " +
  227. "`port` = '" + node.getPort() + "' " +
  228. ";";
  229. }
  230. /*
  231. * Creates SQL statement executing delete
  232. */
  233. private String createMetaDataDeleteRowStatement(String filePath){
  234. return "DELETE FROM `" + Config.getString("MySQL.db") + "`.`" + Config.getString("MySQL.prefix") + "meta-data` " +
  235. "WHERE `meta-data`.`filePath` = '" + filePath + "';" ;
  236. }
  237. /*
  238. * Creates SQL statement executing update
  239. */
  240. private String createUserDataRowSQLStatement(UserDataRepositoryNode node){
  241. return "INSERT INTO `" + Config.getString("MySQL.db") + "`.`" + Config.getString("MySQL.prefix") + "user-data` (" +
  242. "`name`, " +
  243. "`pwdHash`" +
  244. ") " +
  245. "VALUES (" +
  246. "'" + node.getName() + "', '" + node.getPwdHash() + "')" +
  247. "ON DUPLICATE KEY UPDATE" +
  248. "`name` = '" + node.getName() + "', " +
  249. "`pwdHash` = '"+ node.getPwdHash() + "'" +
  250. ";";
  251. }
  252. private String createUserDataDeleteRowSQLStatement(UserDataRepositoryNode node){
  253. return "DELETE FROM `" + Config.getString("MySQL.db") + "`.`" + Config.getString("MySQL.prefix") + "user-data` " +
  254. "WHERE `user-data`.`name` = '" + node.getName() + "';";
  255. }
  256. /*
  257. * Creates SQL statement executing update
  258. */
  259. private String createMetaDataRowSQLStatement(MetaDataRepositoryNode node){
  260. return "INSERT INTO `" + Config.getString("MySQL.db") + "`.`" + Config.getString("MySQL.prefix") + "meta-data` (" +
  261. "`filePath`, " +
  262. "`size`, " +
  263. "`fileType`, " +
  264. "`storageName`, " +
  265. "`permission`, " +
  266. "`owner`, " +
  267. "`group`, " +
  268. "`created`, " +
  269. "`lastEdited` ) " +
  270. "values (" +
  271. "'" + node.getFilePath() + "', " +
  272. "'" + node.getSize() + "', " +
  273. "'" + node.getFileType() + "', " +
  274. "'" + node.getStorageName() + "', " +
  275. "'" + node.getPermission() + "', " +
  276. "'" + node.getOwner() + "', " +
  277. "'" + node.getGroup() + "', " +
  278. "'" + node.getCreated() + "', " +
  279. "'" + node.getLastEdited() + "'" +
  280. ")" +
  281. "ON DUPLICATE KEY UPDATE " +
  282. "`size` = '" + node.getSize() + "', " +
  283. "`fileType` = '" + node.getFileType() + "', " +
  284. "`storageName` = '" + node.getStorageName() + "', " +
  285. "`permission` = '" + node.getPermission() + "', " +
  286. "`owner` = '" + node.getOwner() + "', " +
  287. "`group` = '" + node.getGroup() + "', " +
  288. "`created` = '" + node.getCreated() + "', " +
  289. "`lastEdited` = '" + node.getLastEdited() + "' " +
  290. //"`lastTouched` = '" + node.getLastTouched() + "' " +
  291. ";";
  292. }
  293. }