startTrashEmptier(conf);
有這個麼東西,啓動TrashEmptier,empire翻譯成排空裝置,我擦,起名起得很牛逼啊、
private void startTrashEmptier(Configuration conf) throws IOException { this.emptier = new Thread(new Trash(conf).getEmptier(), "Trash Emptier"); this.emptier.setDaemon(true); this.emptier.start(); }看到了嗎,啓動一個後臺線程,名字叫Trash Emptier再搞這個事情。看看Emptier這個線程在搞啥呢...
private static class Emptier implements Runnable { private Configuration conf; private FileSystem fs; private long interval; public Emptier(Configuration conf) throws IOException { this.conf = conf; this.interval = conf.getLong("fs.trash.interval", 60) * MSECS_PER_MINUTE;//拿到清理間隔 this.fs = FileSystem.get(conf);//拿到hdfs的文件句柄。 } public void run() { if (interval == 0) return; //如果清理間隔爲0 ,還啓動個屁 // trash disabled long now = System.currentTimeMillis(); long end; while (true) { end = ceiling(now, interval);//定鬧鐘 try { // sleep for interval Thread.sleep(end - now); } catch (InterruptedException e) { return; // exit on interrupt } try { now = System.currentTimeMillis(); if (now >= end) { FileStatus[] homes = null; try { homes = fs.listStatus(HOMES); // 拿到hdfs上/user/下的所有文件的FileStatus } catch (IOException e) { LOG.warn("Trash can't list homes: "+e+" Sleeping."); continue; } if (homes == null) continue; for (FileStatus home : homes) { // dump each trash if (!home.isDir()) continue; try { Trash trash = new Trash(home.getPath(), conf); trash.expunge(); trash.checkpoint(); } catch (IOException e) { LOG.warn("Trash caught: "+e+". Skipping "+home.getPath()+"."); } } } } catch (Exception e) { LOG.warn("RuntimeException during Trash.Emptier.run() " + StringUtils.stringifyException(e)); } } } }看到上面,什麼叫expunge,什麼叫checkpoint?看看對每個用戶的trash做了什麼
public void expunge() throws IOException { FileStatus[] dirs = fs.listStatus(trash); // scan trash sub-directories,即拿到用戶trash目錄的FileStatus if( dirs == null){ return; } long now = System.currentTimeMillis(); for (int i = 0; i < dirs.length; i++) { Path path = dirs[i].getPath(); String dir = path.toUri().getPath(); String name = path.getName(); if (name.equals(CURRENT.getName())) // skip current continue;//CURRENT目錄不處理它,這個東西再哪被處理的,用戶刪數據都是rename到CURRENT裏啊。 long time; try { synchronized (CHECKPOINT) { time = CHECKPOINT.parse(name).getTime();//這是幹啥,我日,原來trash目錄下可以被清理的文件都以數字命令,確切說是以數字命令的目錄,起名規律1312250800,就是13年12月25日08時00分,哦,我擦所謂checkpoint就是把CURRENT目錄的文件轉換出來。 } } catch (ParseException e) { LOG.warn("Unexpected item in trash: "+dir+". Ignoring."); continue; } if ((now - interval) > time) {//比如清理間隔是1天,那麼根據目錄名看看這是不是1天前的目錄,是的話,搞它。 if (fs.delete(path, true)) {//這個delete就相當於客戶端執行了帶SkipTrash參數的rmr命令(遞歸刪哦!) LOG.info("Deleted trash checkpoint: "+dir); } else { LOG.warn("Couldn't delete checkpoint: "+dir+" Ignoring."); } } } }
好了,再看到底啥叫checkpoint?
public void checkpoint() throws IOException { if (!fs.exists(current)) // no trash, no checkpoint return; Path checkpoint; synchronized (CHECKPOINT) { checkpoint = new Path(trash, CHECKPOINT.format(new Date())); } if (fs.rename(current, checkpoint)) { LOG.info("Created trash checkpoint: "+checkpoint.toUri().getPath()); } else { throw new IOException("Failed to checkpoint trash: "+checkpoint); } }我日,很簡單啊,trash的checkpoint就是把current rename成一個以yyMMddHHmm格式的數字命名的目錄。
這樣的目錄每次執行trash清理的時候都會被清理掉,執行http://blog.csdn.net/tracymkgld/article/details/17552189這樣的6步刪除操作。
注意:TrashEmptier執行一次,先清理數字目錄,即checkpoint過的目錄,再checkpoint。假如每天清理一次,大概在早上2點,我3點刪掉的東西,要到後天的2點左右纔會被執行真正的清理。
也就是說Trash機制保證刪除指令和真正執行刪除操作中間至少有一個完整的週期間隔。