Heritrix 3.1.0 소스 해석(5)

33296 단어 Heritrix
위의 Crawl Controller 대상에서 볼 수 있듯이 파충류 임무는 ToePool류를 통해 ToeThread의 스레드 탱크를 구축하는 것이다
우리는 채집 스레드 탱크와 관련된 종류를 이해하기 전에 Crawl Controller 종류를 알아야 한다. 왜냐하면 우리의 파충류 조작 명령은 최종적으로 Crawl Controller 대상을 호출하는 방법을 통해
Crawl Controller 클래스의 구성원과 방법은 모두 채집 작업과 직결된다. 예를 들어 컨트롤 센터와 같다.
// ApplicationContextAware implementation, for eventing

    AbstractApplicationContext appCtx;

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

        this.appCtx = (AbstractApplicationContext)applicationContext;

    }

    

    CrawlMetadata metadata;

    public CrawlMetadata getMetadata() {

        return metadata;

    }

    @Autowired

    public void setMetadata(CrawlMetadata provider) {

        this.metadata = provider;

    }

    

    protected ServerCache serverCache;

    public ServerCache getServerCache() {

        return this.serverCache;

    }

    @Autowired

    public void setServerCache(ServerCache serverCache) {

        this.serverCache = serverCache;

    }



    /**

     * The frontier to use for the crawl.

     */

    protected Frontier frontier;

    public Frontier getFrontier() {

        return this.frontier;

    }

    @Autowired

    public void setFrontier(Frontier frontier) {

        this.frontier = frontier;

    }



    /**

     * Scratch directory for temporary overflow-to-disk

     */

    protected ConfigPath scratchDir = 

        new ConfigPath("scratch subdirectory","scratch");

    public ConfigPath getScratchDir() {

        return scratchDir;

    }

    public void setScratchDir(ConfigPath scratchDir) {

        this.scratchDir = scratchDir;

    }



    /**

     * Statistics tracking modules.  Any number of specialized statistics 

     * trackers that monitor a crawl and write logs, reports and/or provide 

     * information to the user interface.

     */

    protected StatisticsTracker statisticsTracker;

    public StatisticsTracker getStatisticsTracker() {

        return this.statisticsTracker;

    }

    @Autowired

    public void setStatisticsTracker(StatisticsTracker statisticsTracker) {

        this.statisticsTracker = statisticsTracker;

    }



    protected SeedModule seeds;

    public SeedModule getSeeds() {

        return this.seeds;

    }

    @Autowired

    public void setSeeds(SeedModule seeds) {

        this.seeds = seeds;

    }

    

    /**

     * Fetch chain

     */

    protected FetchChain fetchChain;

    public FetchChain getFetchChain() {

        return this.fetchChain;

    }

    @Autowired

    public void setFetchChain(FetchChain fetchChain) {

        this.fetchChain = fetchChain;

    }

    

    /**

     * Disposition chain

     */

    protected DispositionChain dispositionChain;

    public DispositionChain getDispositionChain() {

        return this.dispositionChain;

    }

    @Autowired

    public void setDispositionChain(DispositionChain dispositionChain) {

        this.dispositionChain = dispositionChain;

    }

    

    /**

     * Candidate chain

     */

    protected CandidateChain candidateChain;

    public CandidateChain getCandidateChain() {

        return this.candidateChain;

    }

    @Autowired

    public void setCandidateChain(CandidateChain candidateChain) {

        this.candidateChain = candidateChain;

    }

상기 구성원 변수는 스프링 용기 대상, Crawl Metadata 메타데이터, ServerCache 서비스 캐시, Frontier 대상,SeedModule 피드 모듈,statisticsTracker 통계 추적, 그리고 뒤에 있는 프로세서 체인FetchChain Disposition Chain Candidate Chain 등 기본적으로 붙여지지 않은 채집 작업 설정과 관련된 매개 변수, 예를 들어 스레드 수량 등을 포함한다.
그것의 초기화 방법은 초기 상태를 설정합니다
public void start() {

        // cache AlertThreadGroup for later ToePool launch

        AlertThreadGroup atg = AlertThreadGroup.current();

        if(atg!=null) {

            alertThreadGroup = atg;

        }

        

        if(isRunning) {

            return; 

        }

       

        sExit = CrawlStatus.FINISHED_ABNORMAL;



        // force creation of DNS Cache now -- avoids CacheCleaner in toe-threads group

        // also cap size at 1 (we never wanta cached value; 0 is non-operative)

        Lookup.getDefaultCache(DClass.IN).setMaxEntries(1);

        

        reserveMemory = new LinkedList<char[]>();

        for(int i = 0; i < RESERVE_BLOCKS; i++) {

            reserveMemory.add(new char[RESERVE_BLOCK_SIZE]);

        }

        isRunning = true; 

    }

ToePool 클래스는 Thread Group 스레드 그룹 클래스에서 상속되며, 구성원 변수는 다음과 같습니다.
public static int DEFAULT_TOE_PRIORITY = Thread.NORM_PRIORITY - 1;

    

    protected CrawlController controller;

    protected int nextSerialNumber = 1;

    protected int targetSize = 0; 

위에서 언급한 Crawl Controller 대상에서 ToePool을 초기화하는 방법을 다시 한 번 살펴보겠습니다
 protected void setupToePool() {

        toePool = new ToePool(alertThreadGroup,this);

        // TODO: make # of toes self-optimizing

        toePool.setSize(getMaxToeThreads());

        toePool.waitForAll();

    }

전송 스레드 그룹(상위 스레드 그룹) 및 Crawl Controller 객체
ToeThread 클래스의 구조 함수는 다음과 같습니다.
 /**

     * Constructor. Creates a pool of ToeThreads. 

     *

     * @param c A reference to the CrawlController for the current crawl.

     */

    public ToePool(AlertThreadGroup atg, CrawlController c) {

        super(atg, "ToeThreads");        

        this.controller = c;

        setDaemon(true);

    }

부모 스레드 그룹 객체 설정 및 Crawl Controller 객체 초기화
void setSize (int newsize) 방법으로 스레드 탱크 크기를 설정하고 지정한 수량의 스레드를 시작합니다
/**

     * Change the number of ToeThreads.

     *

     * @param newsize The new number of ToeThreads.

     */

    public void setSize(int newsize)

    {

        targetSize = newsize;

        int difference = newsize - getToeCount(); 

        if (difference > 0) {

            // must create threads

            for(int i = 1; i <= difference; i++) {

                startNewThread();

            }

        } else {

            // must retire extra threads

            int retainedToes = targetSize; 

            Thread[] toes = this.getToes();

            for (int i = 0; i < toes.length ; i++) {

                if(!(toes[i] instanceof ToeThread)) {

                    continue;

                }

                retainedToes--;

                if (retainedToes>=0) {

                    continue; // this toe is spared

                }

                // otherwise:

                ToeThread tt = (ToeThread)toes[i];

                tt.retire();

            }

        }

    }

관건은 이 방법에서 start New Thread ();
private synchronized void startNewThread() {

        ToeThread newThread = new ToeThread(this, nextSerialNumber++);

        newThread.setPriority(DEFAULT_TOE_PRIORITY);

        newThread.start();

    }

여기에 새 스레드를 만들고 현재 스레드 그룹 ToePool 개체를 매개 변수로 전송하고 부팅 방법을 호출합니다
ToeThread 클래스는 Thread 클래스에서 상속되며 구성원 변수는 다음과 같습니다.
public enum Step {

        NASCENT, ABOUT_TO_GET_URI, FINISHED, 

        ABOUT_TO_BEGIN_PROCESSOR, HANDLING_RUNTIME_EXCEPTION, 

        ABOUT_TO_RETURN_URI, FINISHING_PROCESS

    }



    private static Logger logger =

        Logger.getLogger("org.archive.crawler.framework.ToeThread");



    private CrawlController controller;

    private int serialNumber;

    

    /**

     * Each ToeThead has an instance of HttpRecord that gets used

     * over and over by each request.

     * 

     * @see org.archive.util.RecorderMarker

     */

    private Recorder httpRecorder = null;



    // activity monitoring, debugging, and problem detection

    private Step step = Step.NASCENT;

    private long atStepSince;

    private String currentProcessorName = "";

    

    private String coreName;

    private CrawlURI currentCuri;

    private long lastStartTime;

    private long lastFinishTime;



    

    // default priority; may not be meaningful in recent JVMs

    private static final int DEFAULT_PRIORITY = Thread.NORM_PRIORITY-2;

    

    // indicator that a thread is now surplus based on current desired

    // count; it should wrap up cleanly

    private volatile boolean shouldRetire = false;

ToeThread 클래스의 구조 함수를 살펴보겠습니다.
/**

     * Create a ToeThread

     * 

     * @param g ToeThreadGroup

     * @param sn serial number

     */

    public ToeThread(ToePool g, int sn) {

        // TODO: add crawl name?

        super(g,"ToeThread #" + sn);

        coreName="ToeThread #" + sn + ": ";

        controller = g.getController();

        serialNumber = sn;

        setPriority(DEFAULT_PRIORITY);

        int outBufferSize = controller.getRecorderOutBufferBytes();

        int inBufferSize = controller.getRecorderInBufferBytes();

        httpRecorder = new Recorder(controller.getScratchDir().getFile(),

            "tt" + sn + "http", outBufferSize, inBufferSize);

        lastFinishTime = System.currentTimeMillis();

    }

스레드 그룹 객체 설정, 스레드 번호 설정, Crawl Controller Controller 객체 초기화 등
스레드를 시작할 때 ToeThread 스레드 객체의 void run () 방법은 다음과 같습니다
/** (non-Javadoc)

     * @see java.lang.Thread#run()

     */

    public void run() {

        String name = controller.getMetadata().getJobName();

        logger.fine(getName()+" started for order '"+name+"'");

        Recorder.setHttpRecorder(httpRecorder); 

        

        try {

            while ( true ) {

                ArchiveUtils.continueCheck();

                

                setStep(Step.ABOUT_TO_GET_URI, null);



                CrawlURI curi = controller.getFrontier().next();

                

                

                synchronized(this) {

                    ArchiveUtils.continueCheck();

                    setCurrentCuri(curi);

                    currentCuri.setThreadNumber(this.serialNumber);

                    lastStartTime = System.currentTimeMillis();

                    currentCuri.setRecorder(httpRecorder);

                }

                

                try {

                    KeyedProperties.loadOverridesFrom(curi);

                    

                    //System.out.println("FetchChain:"+controller.getFetchChain().getClass().getName());

                    

                    

                    controller.getFetchChain().process(curi,this);

                    //System.out.println("Frontier:"+controller.getFrontier().getClass().getName());

                    controller.getFrontier().beginDisposition(curi);

                    

                    //System.out.println("DispositionChain:"+controller.getDispositionChain().getClass().getName());

                    controller.getDispositionChain().process(curi,this);

  

                } catch (RuntimeExceptionWrapper e) {

                    // Workaround to get cause from BDB

                    if(e.getCause() == null) {

                        e.initCause(e.getCause());

                    }

                    recoverableProblem(e);

                } catch (AssertionError ae) {

                    // This risks leaving crawl in fatally inconsistent state, 

                    // but is often reasonable for per-Processor assertion problems 

                    recoverableProblem(ae);

                } catch (RuntimeException e) {

                    recoverableProblem(e);

                } catch (InterruptedException e) {

                    if(currentCuri!=null) {

                        recoverableProblem(e);

                        Thread.interrupted(); // clear interrupt status

                    } else {

                        throw e;

                    }

                } catch (StackOverflowError err) {

                    recoverableProblem(err);

                } catch (Error err) {

                    // OutOfMemory and any others

                    seriousError(err); 

                } finally {

                    httpRecorder.endReplays();

                    KeyedProperties.clearOverridesFrom(curi); 

                }

                

                setStep(Step.ABOUT_TO_RETURN_URI, null);

                ArchiveUtils.continueCheck();



                synchronized(this) {

                    controller.getFrontier().finished(currentCuri);

                    controller.getFrontier().endDisposition();

                    setCurrentCuri(null);

                }

                curi = null;

                

                setStep(Step.FINISHING_PROCESS, null);

                lastFinishTime = System.currentTimeMillis();

                if(shouldRetire) {

                    break; // from while(true)

                }

            }

        } catch (InterruptedException e) {

            if(currentCuri!=null){

                logger.log(Level.SEVERE,"Interrupt leaving unfinished CrawlURI "+getName()+" - job may hang",e);

            }

            // thread interrupted, ok to end

            logger.log(Level.FINE,this.getName()+ " ended with Interruption");

        } catch (Exception e) {

            // everything else (including interruption)

            logger.log(Level.SEVERE,"Fatal exception in "+getName(),e);

        } catch (OutOfMemoryError err) {

            seriousError(err);

        } finally {

            controller.getFrontier().endDisposition();



        }



        setCurrentCuri(null);

        // Do cleanup so that objects can be GC.

        this.httpRecorder.closeRecorders();

        this.httpRecorder = null;



        logger.fine(getName()+" finished for order '"+name+"'");

        setStep(Step.FINISHED, null);

        controller = null;

    }

ToePool 클래스의 void waitForAll() 방법은 다음과 같습니다.
public void waitForAll() {

        while (true) try {

            if (isAllAlive(getToes())) {

                return;

            }

            Thread.sleep(1000);

        } catch (InterruptedException e) {

            throw new IllegalStateException(e);

        }

    }

활성 스레드가 있는지 여부
private static boolean isAllAlive(Thread[] threads) {

        for (Thread t: threads) {

            if ((t != null) && (!t.isAlive())) {

                return false;

            }

        }

        return true;

    }

Crawl Controller 대상이 라인을 시작할 때, BdbFrontier 대상의void unpause () 방법을 호출합니다. BdbFrontier 클래스의 부모 클래스인 AbstractFrontier 클래스에서
org.archive.crawler.frontier.BdbFrontier
         org.archive.crawler.frontier.AbstractFrontier
public void unpause() {

        requestState(State.RUN);

    }

BdbFrontier 객체의 상태를 설정합니다volatile State target State = State.PAUSE; 
다음은 BdbFrontier 객체의 상태와 방법을 분석해 보겠습니다.
--------------------------------------------------------------------------- 
본 시리즈의 Heritrix 3.1.0 원본 해석은 본인이 창작한 것입니다.
전재 는 출처 가 블로그 정원 고슴도치 의 온순함 을 밝혀 주십시오
본문 링크http://www.cnblogs.com/chenying99/archive/2013/04/18/3027672.html

좋은 웹페이지 즐겨찾기