/NameNode/src/mdfs/namenode/sql/MySQLUpdater.java
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}