1. 程式人生 > >MogileFS啟動流程,原始碼分析

MogileFS啟動流程,原始碼分析

MogileFS啟動流程

例項化MogileFS::Server並執行

my $server; # server singleton
sub server {
    my ($pkg) = @_; 
    return $server ||= bless {}, $pkg;#空就建立物件,有就返回,單例
}
$server->run();

讀取配置

優先順序,命令列>配置檔案>預設配置

MogileFS::Config->load_config;

獲得資料庫操作控制代碼

MogileFS::Store是資料庫操作的基類,實際返回的物件是MogileFS::Store::MySQL

MogileFS::Config->check_database;
my $sto = eval { Mgd::get_store() };
sub get_store {
    return $store = MogileFS::Store->new;
}
$sto->ping;
sub ping {
    my $self = shift;
    return $self->dbh->ping;
}
$self->{dbh} = DBI->connect($self->{dsn}, $self->{user}, $self->{pass}

設定fidid fidid就是資料庫中fid的最大值,但對這次啟動來說是最小值

my $min_fidid = $sto->max_fidid;
sub max_fidid {
    my $self = shift;
    return $self->dbh->selectrow_array("SELECT MAX(fid) FROM file");
}

設定為守護程序 MogileFS::Util->daemonize()

兩次fork後成為守護程序

第一次fork後,父程序關閉,子程序成為孤兒程序,init接管

setsid讓孤兒程序脫離會話,併成為程序組,脫離終端。

忽略掛起訊號

第二次fork後,父程序關閉,子程序成為孤兒程序,init接管,成為守護程序

據說呼叫第二次fork可以徹底排除取得會話的可能

daemonize() if MogileFS->config("daemonize");
sub daemonize {
    if ($pid = fork) { exit 0; }
    croak "Cannot detach from controlling terminal"
        unless $sess_id = POSIX::setsid();
    $SIG{'HUP'} = 'IGNORE';
    if ($pid = fork) { exit 0; }
    chdir "/";
    umask 0;
}

設定程序訊號處理

程式自己中斷的訊號TERM和外部中斷訊號INT是類似的,幹掉所有子程序,刪除PID檔案

管道訊號忽略,(只有寫,沒有讀的管道,會發出這種訊號)

$SIG{TERM}  = sub {
    my @children = MogileFS::ProcManager->child_pids;
    print STDERR scalar @children, " children to kill.\n" if $DEBUG;
    my $count = kill( 'TERM' => @children );
    print STDERR "Sent SIGTERM to $count children.\n" if $DEBUG;
    MogileFS::ProcManager->remove_pidfile;
    Mgd::log('info', 'ending run due to SIGTERM');
    Sys::Syslog::closelog();

    exit 0;
};
$SIG{INT} = sub{同上}
$SIG{PIPE} = 'IGNORE';

建立伺服器端socket

Danga::Socket是一個socket事件驅動,處理客戶端請求的是MogileFS::Connection::Client

設定%OtherFds

my @servers;
foreach my $listen (@{ MogileFS->config('listen') }) {
    my $server = IO::Socket::INET->new(LocalAddr => $listen,
                                       Type      => SOCK_STREAM,
                                       Proto     => 'tcp',
                                       Blocking  => 0,
                                       Reuse     => 1,#呼叫Reuse可以免去伺服器在終止到重啟之間的所停留的時間
                                       Listen    => 1024 ) #監聽佇列,其實就是連線數
        or die "Error creating socket: [email protected]\n";
    $server->sockopt(SO_KEEPALIVE, 1); 
    # save sub to accept a client
    push @servers, $server;

    Danga::Socket->AddOtherFds( fileno($server) => sub {
            while (my $csock = $server->accept) {
                MogileFS::Connection::Client->new($csock);#也會被加到%DescriptorMap
            }   
        } );
}

設定socket事件處理後的回撥,並開始迴圈

MogileFS::ProcManager 程序管理工具

EventLoop = FirstTimeEventLoop; 符號表設定,呼叫的是FirstTimeEventLoop

MogileFS::ProcManager->push_pre_fork_cleanup(sub {
    # so children don't hold server connection open
    #關閉連線的匿名函式,給子程序用的
    close($_) foreach @servers;
});

# setup the post event loop callback to spawn jobs, and the timeout
Danga::Socket->DebugLevel(3);#始終是0
Danga::Socket->SetLoopTimeout( 250 ); #事件超時 250 milliseconds
Danga::Socket->SetPostLoopCallback(MogileFS::ProcManager->PostEventLoopChecker);#每次事件驅動完成後執行的函式
Danga::Socket->EventLoop();

Socket輪詢器選擇

我本機為Poll,以後呼叫EventLoop就是PollEventLoop了,Poll需要輪詢,

線上應該為Epoll,Epoll核心提供反射模式,無需輪詢

Epoll和Poll那種更好,可能取決於活躍的Socket。。。,如果全是活躍的呢

sub FirstTimeEventLoop {
    my $class = shift;

    _InitPoller();

    if ($HaveEpoll) {
        EpollEventLoop($class);
    } elsif ($HaveKQueue) {
        KQueueEventLoop($class);
    } else {
        PollEventLoop($class);
    }
}
*EventLoop = *PollEventLoop;

第一次輪詢開始

還記得Danga::Socket->SetPostLoopCallback(MogileFS::ProcManager->PostEventLoopChecker);嗎?,第一次輪詢直接回調

還記得%OtherFds嗎,主程序的socket在裡面,%DescriptorMap暫時還沒,不過這個雜湊很重要

my @poll;
foreach my $fd ( keys %OtherFds ) {
    push @poll, $fd, POLLIN;
}    
while ( my ($fd, $sock) = each %DescriptorMap ) {
    push @poll, $fd, $sock->{event_watch};
}
my $count = IO::Poll::_poll($timeout, @poll);
unless ($count) {
    return unless PostEventLoop();
    next;
}

建立Monitor子程序

建立一副IPC通訊一個給父程序,一個給子程序,並切無緩衝

socketpair(my $parents_ipc, my $childs_ipc, AF_UNIX, SOCK_STREAM, PF_UNSPEC )
        or die( "Sockpair failed" );
select((select( $parents_ipc ), $|++)[0]);
select((select( $childs_ipc  ), $|++)[0]);

父類返回MogileFS::Connection::Worker物件,構造引數是IPC中的一個

MogileFS::Connection::Worker繼承Danga::Socket,會增加到$DescriptorMap{$fd} = $self;

MogileFS::ProcManager->RegisterWorkerConn 設定POLLIN和$ChildrenByJob{$worker->job}->{$worker->pid} = $worker;

# if i'm the parent
if ($pid) {
    sigprocmask(SIG_UNBLOCK, $sigset)
        or return error("Can't unblock SIGINT for fork: $!");

    close($childs_ipc);  # unnecessary but explicit
    IO::Handle::blocking($parents_ipc, 0);

    my $worker_conn = MogileFS::Connection::Worker->new($parents_ipc);
    $worker_conn->pid($pid);
    $worker_conn->job($job);
    MogileFS::ProcManager->RegisterWorkerConn($worker_conn);
    return $worker_conn;
}

子類通過job_to_class獲取MogileFS::Worker::Monitor,然後例項化,呼叫work運作起來

會增加到$DescriptorMap{$fd} = $self;但是不要和主程序的混淆,完全兩個程序裡的

子類不會執行到exit,子程序也呼叫了Danga的socket事件迴圈

$_->() foreach @prefork_cleanup;
my $class = MogileFS::ProcManager->job_to_class($job)
        or die "No worker class defined for job '$job'\n";
my $worker = $class->new($childs_ipc);

# set our frontend into child mode
MogileFS::ProcManager->SetAsChild($worker);

$worker->work;
exit 0;

Monitor程序開始工作

Monitor監控資料庫和Storage的情況

最重要的是Monitor啟動後,傳送了訊息":monitor_just_ran",接著就一直迴圈監聽和處理了

my $db_monitor;
$db_monitor = sub {
    $self->parent_ping;#和p保持連線
    $self->cache_refresh;#監控資料庫配置,及時通知p
    $db_monitor_ran++;
    Danga::Socket->AddTimer(4, $db_monitor);#每4秒查詢一次
};  

$db_monitor->();
$self->read_from_parent;

my $main_monitor;
$main_monitor = sub {
    $self->parent_ping;
    $self->usage_refresh;
    if ($db_monitor_ran) {
        $self->send_to_parent(":monitor_just_ran");
        $db_monitor_ran = 0;
    }   
    Danga::Socket->AddTimer(2.5, $main_monitor);
};  

$main_monitor->();
Danga::Socket->AddOtherFds($self->psock_fd, sub{ $self->read_from_parent }); 
Danga::Socket->EventLoop;

MogileFSD程序處理:monitor_just_ran訊息

設定完需要的workers後,又和呼叫建立Monitor一樣,建立其他的workers

my $child = shift;
# Gas up other workers if monitor's completed for the first time.
if (! $monitor_good) {
    MogileFS::ProcManager->set_min_workers('queryworker' => MogileFS->config('query_jobs'));
    MogileFS::ProcManager->set_min_workers('delete'      => MogileFS->config('delete_jobs'));
    MogileFS::ProcManager->set_min_workers('replicate'   => MogileFS->config('replicate_jobs'));
    MogileFS::ProcManager->set_min_workers('reaper'      => MogileFS->config('reaper_jobs'));
    MogileFS::ProcManager->set_min_workers('fsck'        => MogileFS->config('fsck_jobs'));
    MogileFS::ProcManager->set_min_workers('job_master'  => 1);
    $monitor_good = 1;
    $allkidsup    = 0;
}

相關推薦

MogileFS啟動流程原始碼分析

MogileFS啟動流程 例項化MogileFS::Server並執行 my $server; # server singleton sub server { my ($pkg) = @_; return $server ||= bless {}, $pk

Activity啟動流程介面繪製到事件處理的整個流程(基於Android6.0原始碼)(2)

void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) { synchronized (this) { ...... mWindowAttributes

springboot部署到tomcat啟動以及線上部署原始碼分析

1.專案環境說明:tomcat8.5.11, springboot 1.5.6.RELEASE,maven3.3.92.war包eclipse配置tomcat啟動。<project xmlns="http://maven.apache.org/POM/4.0.0" xm

Java NIO框架Netty教程(十六)-ServerBootStrap啟動流程源碼分析

ucc ask pip 以及 梳理 學習曲線 owa pan server 有一段事件沒有更新文章了,各種原因都有吧。搬家的瑣事,搬家後的安逸呵呵。不過,OneCoder明白,絕不能放松。對於Netty的學習,也該稍微深入一點了。 所以,這次OneCoder花了幾天時間,仔

Dubbo學習筆記10:Dubbo服務消費方啟動流程源碼分析

exec checked 自己 當前 In rpc mod png collect 同理我們看下服務消費端啟動流程時序圖: 在《Dubbo整體架構分析》一文中,我們提到服務消費方需要使用ReferenceConfig API來消費服務,具體是調用代碼(1)get()方法來

PyTorch--雙向遞迴神經網路(B-RNN)概念原始碼分析

  關於概念:   BRNN連線兩個相反的隱藏層到同一個輸出.基於生成性深度學習,輸出層能夠同時的從前向和後向接收資訊.該架構是1997年被Schuster和Paliwal提出的.引入BRNNS是為了增加網路所用的輸入資訊量.例如,多層感知機(MLPS)和延時神經網路(TDNNS)在輸入資料的靈活性方面是非

HashTable與HashMap的區別資料結構類檔案結構原始碼分析

轉載https://www.imooc.com/article/details/id/23015 與HashMap的區別 1 HashMap是非同步的,沒有對讀寫等操作進行鎖保護,所以是執行緒不安全的,在多執行緒場景下會出現資料不一致的問題。而HashTable是同步的,所有的讀寫等操作都進

RAC啟動流程啟動程序隔離機制相關資訊

RAC的啟動流程 第一步:高可用性服務層 (HAS) 第二步:叢集就緒服務層 (CRS) ./crsctl start has ./crsctl start crs ohasd程序是系統INIT生成,ohasd程序是啟動Clusterware的起點,高可用性服務層由GPNPD,GIPC,

hog訓練流程原始碼分析

           一、網上一些參考資料        在部落格目標檢測學習_1(用opencv自帶hog實現行人檢測) 中已經使用了opencv自帶的函式detectMultiScale()實

struts2流程原始碼分析

struts 架構圖 分析這個架構圖,我們可以從4個部分,也就struts訪問的4個階段的流程來分析 這4個階段包括:Action對映、Action轉發、Action執行、結果返回 首先是Action對映階段 當請求到來的時候,首先是struts的核心過濾器接收到請求,然後通過ActionMapp

Django CBV流程原始碼分析

       Django 實現檢視的方法有兩種,一種是FBV(function base view)即基於函式的檢視,還一種高階的就是CBV(class base view),通過閱讀原始碼你會發現它本質上還是基於FBV的。FBV的優點是用法和寫法都比較簡單適合剛開始

JAVA:HashMap常用方法對於自定義類的儲存原始碼分析

public static void main(String[] args) { //hashMap儲存結構為陣列+連結串列 //資料儲存方式為鍵值對 HashMap<String, Integer> hashMap = ne

Activity的啟動過程(原始碼分析

startActivity正常啟動分析 通過startActivity(intent)來啟動活動,跟進原始碼看一下 首先Activity類裡面過載了多個startActivity()方法,引數不同而已 @Override public void startAc

Java程式設計師從笨鳥到菜鳥之(四十)細談struts2(四)struts2中action執行流程原始碼分析

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!                首先我們看一下struts官方給我們提供的struts執行流程從上面流程圖我們可以看出struts執行的流程大體分一下階段:1. 初始的請求通過一條標準的過濾器

Uipath啟動流程調試斷點添加(RPA)

啟用 tps 之前 family 輸出 設計 recent 即使 目的 打開一個項目 打開項目有兩個選項,使用“開始”窗格右側的最近部分或使用窗口左上角的“打開”按鈕。 運行一個項目 要從UiPath Studio運行項目,您可以使用設計選項卡(F5)中

AudioRecord 流程原始碼分析

本文轉自:http://www.cnblogs.com/qiengo/p/4220386.html   Android是架構分為三層: 底層      Linux Kernel中間層  主要由C++實現 (Android 60%原始碼都是C++實現)應用層  主要由JAVA開發的應用程式

(1/2) 為了理解 UWP 的啟動流程我從零開始建立了一個 UWP 程式

每次使用 Visual Studio 的模板建立一個 UWP 程式,我們會在專案中發現大量的專案檔案、配置、應用啟動流程程式碼和介面程式碼。然而這些檔案在 UWP 程式中到底是如何工作起來的? 我從零開始建立了一個 UWP 程式,用於探索這些檔案的用途,瞭解

Ceph 學習——OSD讀寫流程原始碼分析(一)

直接上圖: 同樣當前最新的版本,和之前的版本有所不同,有一些模組簡化了,類的名字也改了。先介紹圖中涉及的相關的類,然後在對類中具體函式主要呼叫流程進行分析。 OSD 模組主要的類 盜圖:其中ReplicatedPG 在最新的版本中

Android系統程序Zygote啟動過程的原始碼分析

        在Android系統中,所有的應用程式程序以及系統服務程序SystemServer都是由Zygote程序孕育(fork)出來的,這也許就是為什麼要把它稱為Zygote(受精卵)的原因吧。由於Zygote程序在Android系統中有著如此重要的地位,本文將詳細分

dedecms講解-dedetag.class.php模板解析和屬性解析原始碼分析

其他相對簡單,這2個稍微複雜: 模板解析: /** * 解析模板 * * @access public * @return string */ function ParseTemplet()