PageRenderTime 58ms CodeModel.GetById 19ms app.highlight 31ms RepoModel.GetById 2ms app.codeStats 0ms

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