LetsCoding.cn

          天地之間有桿秤,拿秤砣砸老百姓。

          Lucene源碼分析筆記之[org.apache.lucene.store](一)

           Lock/LockFactory類系

          綜述:Lucene 的機(jī)制來實(shí)現(xiàn)同一文件夾的互斥訪問:當(dāng)有進(jìn)程訪問需要互斥訪問的文件夾時(shí),首先查看與之關(guān)聯(lián)的是否存在,若存在則拒絕訪問;若不存在,則先上,訪問之,最后解。不同的Lock子類,具體的實(shí)現(xiàn)方式并不一樣。

          1.Lock/LockFactory類系的層次圖



          2.
          部分代碼說明

          Lock

          Lock本身是一個(gè)抽象類,它提供了4個(gè)方法,但它僅實(shí)現(xiàn)了obtain(long)這一個(gè)方法,其他三個(gè)留給了它的子類去完成。4個(gè)方法的聲明羅列如下:

          public abstract Boolean obtain() throws IOException;
          public boolean obtain(long lockWaitTimeout) throws LockObtainFailedException;;
          public abstract void release() throws IOException;
          public abstract Boolean isLocked();

           

          Lock還提供了兩個(gè)靜態(tài)變量:long LOCK_POLL_INTERVAL(默認(rèn)值為1000ms)和final long LOCK_OBTAIN_WAIT_FOREVER(值為-1) ,前者為試圖獲取時(shí)的時(shí)間間隔值,后者為當(dāng)lockWaitTimeout設(shè)置為該值時(shí),obtain(long)將會(huì)無限期試圖獲取

          obtain(long)的功能為在給定的lockWaitTimeout時(shí)間內(nèi)試圖獲取,一旦獲取到,則返回;超過時(shí)間則會(huì)拋出異常。其代碼及注釋如下:

           1    public boolean obtain(long lockWaitTimeout)
           2            throws LockObtainFailedException, IOException {
           3        failureReason = null;
           4        // locked試圖獲取“鎖文件”。obtain()的功能是及時(shí)返回是否能取得“鎖文件”
           5        boolean locked = obtain();
           6        // 給定參數(shù)值為負(fù)并且不等于-1,則拋出參數(shù)值設(shè)置異常
           7        if (lockWaitTimeout < 0 && lockWaitTimeout != LOCK_OBTAIN_WAIT_FOREVER)
           8            throw new IllegalArgumentException(
           9                    "lockWaitTimeout should be LOCK_OBTAIN_WAIT_FOREVER or a non-negative number (got "
          10                            + lockWaitTimeout + ")");
          11        // 設(shè)置最大睡眠次數(shù)
          12        long maxSleepCount = lockWaitTimeout / LOCK_POLL_INTERVAL;
          13        long sleepCount = 0;    // 睡眠次數(shù)累加器
          14        // 循環(huán)直到取得“鎖文件”;或者時(shí)間到,則拋出異常
          15        while (!locked) {
          16            if (lockWaitTimeout != LOCK_OBTAIN_WAIT_FOREVER
          17                    && sleepCount++ >= maxSleepCount) {        // 參數(shù)lockWaitTimeout不為-1且累計(jì)睡眠次數(shù)大于maxSleepCount,拋出異常
          18                String reason = "Lock obtain timed out: " + this.toString();
          19                if (failureReason != null{
          20                    reason += "" + failureReason;
          21                }

          22                LockObtainFailedException e = new LockObtainFailedException(
          23                        reason);
          24                if (failureReason != null{
          25                    e.initCause(failureReason);
          26                }

          27                throw e;
          28            }

          29            try {
          30                // 睡眠LOCK_POLL_INTERVAL(默認(rèn)1000ms)時(shí)間
          31                Thread.sleep(LOCK_POLL_INTERVAL);
          32            }
           catch (InterruptedException e) {
          33                throw new IOException(e.toString());
          34            }

          35            // 再次試圖獲取“鎖文件”
          36            locked = obtain();
          37        }

          38        // 正常退出,
          39        return locked;
          40    }

           

          SimpleFSLock

          SimpleFSLock類中,是通過給需要訪問的文件夾另外建立一個(gè)文件的方式來實(shí)現(xiàn)的;查看某文件夾是否被上鎖,你需要做的僅僅是查看下與其相關(guān)的鎖文件是否存在;解鎖時(shí)只需刪除鎖文件就萬事OK了。下面是obtain()方法的代碼及注釋:

           1    public boolean obtain() throws IOException {
           2
           3        // Ensure that lockDir exists and is a directory:
           4        // 確保lockDir存在并且是文件夾類型
           5        if (!lockDir.exists()) {
           6            if (!lockDir.mkdirs())    // 如果lockDir不存在,則試圖為其建立新文件夾,建立失敗則拋出異常
           7                throw new IOException("Cannot create directory: "
           8                        + lockDir.getAbsolutePath());
           9        }
           else if (!lockDir.isDirectory()) {
          10            // 如果lockDir存在,但不是文件夾,拋出異常
          11            throw new IOException(
          12                    "Found regular file where directory expected: "
          13                            + lockDir.getAbsolutePath());
          14        }

          15        // createNewFile成功,返回true; 失敗,false;
          16        // 說明:建立成功,也就是說“鎖文件”不存在; 失敗,說明“鎖文件”已經(jīng)存在,也就是說該文件夾已被上鎖
          17        return lockFile.createNewFile();
          18    }

          NativeFSLock

          NativeFSLockSimpleFSLock有些不同,它的用的是鎖文件的鎖,說起來很是繞口,其實(shí)它只是給鎖文件上一把鎖:在查看某文件夾是否能被訪問時(shí),首先檢查與此文件夾關(guān)聯(lián)的鎖文件的鎖是否被占用,而不像SimpleFSLock僅僅查看與之相連的鎖文件是否存在。正因?yàn)槿绱耍鉀Q了如果JVM異常退出時(shí)遺留的鎖文件的問題:在SimpleFSLock中,只要鎖文件存在,就被人為該文件夾被鎖,而不能被任何其他進(jìn)程訪問。

          NativeFSLock額外定義了一個(gè)私有靜態(tài)變量:private static HashSet LOCK_HELD。它用來記錄鎖文件的標(biāo)準(zhǔn)路徑名(canonical path),當(dāng)某文件夾的鎖文件標(biāo)準(zhǔn)路徑名存在于LOCK_HELD中,且沒有被上鎖,就說明該文件夾可被訪問;否則拒絕訪問。在解鎖時(shí),需要從LOCK_HELD中刪除鎖文件的標(biāo)準(zhǔn)路徑名,刪除鎖文件

          NativeFSLock的代碼中包含了很多對(duì)于異常的處理,使得程序看起來很是費(fèi)解。

          obtain()的主要代碼及注釋如下:

            1    public synchronized boolean obtain() throws IOException {    // 該方法被設(shè)置為同步訪問
            2        //    isLocked()為true說明“鎖文件”已被上鎖,正在被使用中
            3        if (isLocked()) {
            4            // Our instance is already locked:
            5            return false;
            6        }

            7
            8        // Ensure that lockDir exists and is a directory.
            9        if (!lockDir.exists()) {
           10            if (!lockDir.mkdirs())
           11                throw new IOException("Cannot create directory: "
           12                        + lockDir.getAbsolutePath());
           13        }
           else if (!lockDir.isDirectory()) {
           14            throw new IOException(
           15                    "Found regular file where directory expected: "
           16                            + lockDir.getAbsolutePath());
           17        }

           18
           19        String canonicalPath = path.getCanonicalPath();
           20
           21        boolean markedHeld = false;    //標(biāo)記在LOCK_HELD中是否存在某“鎖文件”的路徑名
           22
           23        try {
           24
           25            // Make sure nobody else in-process has this lock held
           26            // already, and, mark it held if not:
           27
           28            synchronized (LOCK_HELD) {    // 設(shè)置LOCK_HELD的同步訪問
           29                if (LOCK_HELD.contains(canonicalPath)) {    // 如果標(biāo)準(zhǔn)路徑存在于LOCK_HELD中,說明該文件被上鎖或正在被上鎖,返回false
           30                    // Someone else in this JVM already has the lock:
           31                    return false;
           32                }
           else {
           33                    // This "reserves" the fact that we are the one
           34                    // thread trying to obtain this lock, so we own
           35                    // the only instance of a channel against this
           36                    // file:
           37                    LOCK_HELD.add(canonicalPath);    // 添加路徑名到LOCK_HELD中
           38                    markedHeld = true;    // 設(shè)置為true
           39                }

           40            }

           41
           42            try {
           43                //  建立“鎖文件”
           44                f = new RandomAccessFile(path, "rw");
           45            }
           catch (IOException e) {
           46                // On Windows, we can get intermittant "Access
           47                // Denied" here.  So, we treat this as failure to
           48                // acquire the lock, but, store the reason in case
           49                // there is in fact a real error case.
           50                failureReason = e;
           51                f = null;    // 建立失敗,則f= null
           52            }

           53
           54            if (f != null{
           55                try {
           56                    // 獲取“鎖文件”的通道
           57                    channel = f.getChannel();
           58                    try {
           59                        // 給“鎖文件”上鎖
           60                        lock = channel.tryLock();
           61                    }
           catch (IOException e) {
           62                        // At least on OS X, we will sometimes get an
           63                        // intermittant "Permission Denied" IOException,
           64                        // which seems to simply mean "you failed to get
           65                        // the lock".  But other IOExceptions could be
           66                        // "permanent" (eg, locking is not supported via
           67                        // the filesystem).  So, we record the failure
           68                        // reason here; the timeout obtain (usually the
           69                        // one calling us) will use this as "root cause"
           70                        // if it fails to get the lock.
           71                        failureReason = e;
           72                    }
           finally {        
           73                        if (lock == null{    // 如果沒有取得鎖,需關(guān)閉通道并設(shè)置其為null
           74                            try {
           75                                channel.close();    //關(guān)閉通道
           76                            }
           finally {
           77                                channel = null;    //設(shè)置為null
           78                            }

           79                        }

           80                    }

           81                }
           finally {
           82                    if (channel == null{ // 如果通道獲取失敗或者上鎖異常,關(guān)閉“鎖文件”
           83                        try {
           84                            f.close();    // 關(guān)閉“鎖文件”
           85                        }
           finally {
           86                            f = null;
           87                        }

           88                    }

           89                }

           90            }

           91
           92        }
           finally {
           93            // markedHeld為ture,但isLocked()為false,說明上鎖途中出現(xiàn)異常
           94            // 需刪除“鎖文件”的路徑名 
           95            if (markedHeld && !isLocked()) {
           96                synchronized (LOCK_HELD) {    // 注意同步訪問LOCK_HELD
           97                    if (LOCK_HELD.contains(canonicalPath)) {
           98                        LOCK_HELD.remove(canonicalPath);
           99                    }

          100                }

          101            }

          102        }

          103        // 經(jīng)過以上過程,若成功上鎖則isLock()為true;反之,false
          104        return isLocked();
          105    }

          posted on 2008-11-10 16:26 Rolandz 閱讀(2953) 評(píng)論(0)  編輯  收藏


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           

          導(dǎo)航

          統(tǒng)計(jì)

          留言簿(1)

          隨筆分類(12)

          隨筆檔案(19)

          積分與排名

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 沁源县| 平顶山市| 云安县| 杭锦后旗| 牡丹江市| 平原县| 深水埗区| 嘉义市| 深泽县| 南雄市| 弥勒县| 类乌齐县| 巴彦淖尔市| 龙山县| 赤壁市| 松溪县| 都昌县| 武平县| 东明县| 铜陵市| 综艺| 汉沽区| 陇南市| 南澳县| 沙河市| 姚安县| 长乐市| 古交市| 儋州市| 通榆县| 都匀市| 奉新县| 元阳县| 铁岭县| 万州区| 浪卡子县| 河曲县| 桐柏县| 新兴县| 东莞市| 永福县|