elasticsearch 
ソースコードを 
読みはじめてみた 
! 
@furandon_pig 
第6回elasticsearch勉強会
自己紹介 
• Twitter ID: @furandon_pig 
• 宮沢賢治の「フランドン農学校の豚」が由来です 
• 家では日々NetBSDを利用しています 
• elasticsearchを業務で使ったことはありません…… 
• が、「あの書籍」は購入済です
本日の発表内容 
• タイトルでネタバレ。 
• 「elasticsearchソースコードを読み始めてみた」 
• elasticsearchの学習 
• 動かして理解(わか)る→せいかい! 
• ソースコードから理解(わか)ろうとする→まちがい!
Q. なぜソースから読んだ? 
• 前回のelasticsearch勉強会にて…… 
• 私「elasticsearchのソースコードを読むにはどこ 
から?」 
• 開発者の方「クエリをレシーブしてリザルトをリ 
ターンする部分からリードするとベターだよ」 
• 訳:クエリを受けて結果を返す部分から読むの 
が早道だよ
本日の発表内容(その2) 
• ……というやり取りを経てソースコードリーディング 
• curl -XGET http://localhost:9200/ を受けたときの動作を 
ソースコードレベルで把握したい→目標 
• が、クエリをレシーブしてリザル(略)までたどり着くまでが 
タイヘン! 
• ソースコードから理解(わか)ろうとする→まちがい! 
• まずは順当に起動処理から追いかけることにしてみました
まずはソースコードを準備 
$ sudo yum install git 
$ sudo yum install maven 
! 
$ git clone https://github.com/elasticsearch/elasticsearch.git 
$ mvn clean package -DskipTests 
6
まずは bin/elasticsearch 
bin/elasticsearch: 
1 #!/bin/sh 
… 
127 launch_service() 
128 { 
… 
144 if [ "x$daemonized" = "x" ]; then 
145 es_parms="$es_parms -Des.foreground=yes" 
146 exec "$JAVA" $JAVA_OPTS $ES_JAVA_OPTS $es_parms - 
Des.path.home="$ES_HOME" -cp "$ES_CLASSPATH" $props  
147 org.elasticsearch.bootstrap.Elasticsearch 
… 
150 else 
151 # Startup Elasticsearch, background it, and write the 
pid. 
… 
155 fi 
156 } 
… 
216 # Start up the service 
217 launch_service "$pidfile" "$daemonized" "$properties" 
7
class Elasticsearch(1/2) 
src/main/java/org/elasticsearch/bootstrap/Elasticsearch.java: 
25 public class Elasticsearch extends Bootstrap { 
26 
27 public static void close(String[] args) { 
28 Bootstrap.close(args); 
29 } 
30 
31 public static void main(String[] args) { 
32 Bootstrap.main(args); 
33 } 
34 } 
8
class Elasticsearch(2/2) 
Bootstrap 
Elasticsearch 
• class Bootstrapをラップしてい 
るだけ
Bootstrap.main() 
src/main/java/org/elasticsearch/bootstrap/Bootstrap.java: 
145 public static void main(String[] args) { 
146 System.setProperty("es.logger.prefix", ""); 
147 bootstrap = new Bootstrap(); 
… 
197 String stage = "Initialization"; 
198 try { 
199 if (!foreground) { 
200 Loggers.disableConsoleLogging(); 
201 System.out.close(); 
202 } 
203 bootstrap.setup(true, tuple); 
204 
205 stage = "Startup"; 
206 bootstrap.start(); 
… 
233 } catch (Throwable e) { 
… 
250 } 
251 } 
10
Bootstrap.{setup,start}() 
src/main/java/org/elasticsearch/bootstrap/Bootstrap.java: 
50 /** 
51 * A main entry point when starting from the command line. 
52 */ 
53 public class Bootstrap { 
… 
62 private void setup(boolean addShutdownHook, Tuple<Settings, 
Environment> tuple) throws Exception { 
… 
69 NodeBuilder nodeBuilder = 
NodeBuilder.nodeBuilder().settings(tuple.v1()).loadConfigSettings(fa 
lse); 
70 node = nodeBuilder.build(); 
… 
79 } 
… 
118 /** 
119 * hook for JSVC 
120 */ 
121 public void start() { 
122 node.start(); 
123 } 
11
NodeBuilder 
src/main/java/org/elasticsearch/node/NodeBuilder.java: 
26 /** 
27 * A node builder is used to construct a {@link Node} instance. 
… 
57 */ 
58 public class NodeBuilder { 
… 
64 /** 
65 * A convenient factory method to create a {@link 
NodeBuilder}. 
66 */ 
67 public static NodeBuilder nodeBuilder() { 
68 return new NodeBuilder(); 
69 } 
… 
155 /** 
156 * Builds the node without starting it. 
157 */ 
158 public Node build() { 
159 return new InternalNode(settings.build(), 
loadConfigSettings); 
160 } 
12
class InternalNode 
AutoClosable 
Releasable 
<<interface>> 
Node 
final 
InternalNode 
• ノードに関する情報を保持しているクラス 
• elasticsearchの各々のサーバのこと
InternalNode(1/2) 
src/main/java/org/elasticsearch/node/internal/InternalNode.java: 
111 public final class InternalNode implements Node { 
… 
116 private final Injector injector; 
… 
126 public InternalNode(Settings preparedSettings, boolean 
loadConfigSettings) throws ElasticsearchException { 
… 
138 logger.info("initializing …"); 
… 
157 try { 
… 
194 injector = modules.createInjector(); 
… 
204 logger.info("initialized"); 
205 } 
14
InternalNode 
src/main/java/org/elasticsearch/node/internal/InternalNode.java: 
217 public Node start() { 
… 
223 logger.info("starting ..."); 
… 
241 injector.getInstance(SearchService.class).start(); 
242 injector.getInstance(MonitorService.class).start(); 
243 injector.getInstance(RestController.class).start(); 
… 
258 logger.info("started"); 
259 
260 return this; 
261 } 
15
Node, Reasable, AutoCLosable 
src/main/java/org/elasticsearch/node/Node.java: 
35 public interface Node extends Releasable{ 
… 
47 /** 
48 * Start the node. If the node is already started, this 
method is no-op. 
49 */ 
50 Node start(); 
… 
66 } 
! 
src/main/java/org/elasticsearch/common/lease/Releasable.java: 
27 public interface Releasable extends AutoCloseable { 
28 
29 void close() throws ElasticsearchException; 
30 } 
! 
src/main/java/org/elasticsearch/common/lease/Releasable.java: 
27 public interface Releasable extends AutoCloseable { 
28 
29 void close() throws ElasticsearchException; 
30 } 
16
(最掲)bootstrap.main() 
src/main/java/org/elasticsearch/bootstrap/Bootstrap.java: 
145 public static void main(String[] args) { 
146 System.setProperty("es.logger.prefix", ""); 
147 bootstrap = new Bootstrap(); 
… 
197 String stage = "Initialization"; 
198 try { 
199 if (!foreground) { 
200 Loggers.disableConsoleLogging(); 
201 System.out.close(); 
202 } 
203 bootstrap.setup(true, tuple); 
204 
205 stage = "Startup"; 
206 bootstrap.start(); 
… 
233 } catch (Throwable e) { 
… 
250 } 
251 } 
17
InternalNode 
src/main/java/org/elasticsearch/node/internal/InternalNode.java: 
217 public Node start() { 
… 
223 logger.info("starting ..."); 
… 
241 injector.getInstance(SearchService.class).start(); 
242 injector.getInstance(MonitorService.class).start(); 
243 injector.getInstance(RestController.class).start(); 
… 
258 logger.info("started"); 
259 
260 return this; 
261 } 
18
class MonitorService 
ClosableComponent 
LifecycleComponent 
AbstractComponent 
<<abstract>> 
AbstractLifecycleComponent 
MonitorService 
• 各サービスの実体
MonitorService 
src/main/java/org/elasticsearch/monitor/MonitorService.java: 
36 public class MonitorService extends 
AbstractLifecycleComponent<MonitorService> { 
… 
83 @Override 
84 protected void doStart() throws ElasticsearchException { 
85 jvmMonitorService.start(); 
86 } 
! 
src/main/java/org/elasticsearch/common/component/AbstractLifecycleComponent.java: 
31 public abstract class AbstractLifecycleComponent<T> extends AbstractComponent 
implements LifecycleComponent<T> { 
… 
77 @Override 
78 public T start() throws ElasticsearchException { 
… 
85 doStart(); 
86 lifecycle.moveToStarted(); 
87 for (LifecycleListener listener : listeners) { 
88 listener.afterStart(); 
89 } 
90 return (T) this; 
91 } 
20
(再掲)InternalNode 
src/main/java/org/elasticsearch/node/internal/InternalNode.java: 
217 public Node start() { 
… 
223 logger.info("starting ..."); 
… 
241 injector.getInstance(SearchService.class).start(); 
242 injector.getInstance(MonitorService.class).start(); 
243 injector.getInstance(RestController.class).start(); 
… 
258 logger.info("started"); 
259 
260 return this; 
261 } 
21
まとめ 
• elasticsearchのソースコードを読み始めてみました 
• 順当にクラスを追いかけていけば読めます……が 
• 一つ前のメソッド呼び出しに戻ることが多い感じ 
• Abstractクラスの実装を追いかけるような場合 
• DI(Dependency Injection)が(個人的に)よく分かっていないので、 
InternalNodeまわりは読むのがツラい 
• 手続き指向おじさん(仮)には少し慣れが必要なソースコード 
• (まだほんのちょっとしか使ってないけど)UMLって便利だね!

elasticsearchソースコードを読みはじめてみた

  • 1.
    elasticsearch ソースコードを 読みはじめてみた ! @furandon_pig 第6回elasticsearch勉強会
  • 2.
    自己紹介 • TwitterID: @furandon_pig • 宮沢賢治の「フランドン農学校の豚」が由来です • 家では日々NetBSDを利用しています • elasticsearchを業務で使ったことはありません…… • が、「あの書籍」は購入済です
  • 3.
    本日の発表内容 • タイトルでネタバレ。 • 「elasticsearchソースコードを読み始めてみた」 • elasticsearchの学習 • 動かして理解(わか)る→せいかい! • ソースコードから理解(わか)ろうとする→まちがい!
  • 4.
    Q. なぜソースから読んだ? •前回のelasticsearch勉強会にて…… • 私「elasticsearchのソースコードを読むにはどこ から?」 • 開発者の方「クエリをレシーブしてリザルトをリ ターンする部分からリードするとベターだよ」 • 訳:クエリを受けて結果を返す部分から読むの が早道だよ
  • 5.
    本日の発表内容(その2) • ……というやり取りを経てソースコードリーディング • curl -XGET http://localhost:9200/ を受けたときの動作を ソースコードレベルで把握したい→目標 • が、クエリをレシーブしてリザル(略)までたどり着くまでが タイヘン! • ソースコードから理解(わか)ろうとする→まちがい! • まずは順当に起動処理から追いかけることにしてみました
  • 6.
    まずはソースコードを準備 $ sudoyum install git $ sudo yum install maven ! $ git clone https://github.com/elasticsearch/elasticsearch.git $ mvn clean package -DskipTests 6
  • 7.
    まずは bin/elasticsearch bin/elasticsearch: 1 #!/bin/sh … 127 launch_service() 128 { … 144 if [ "x$daemonized" = "x" ]; then 145 es_parms="$es_parms -Des.foreground=yes" 146 exec "$JAVA" $JAVA_OPTS $ES_JAVA_OPTS $es_parms - Des.path.home="$ES_HOME" -cp "$ES_CLASSPATH" $props 147 org.elasticsearch.bootstrap.Elasticsearch … 150 else 151 # Startup Elasticsearch, background it, and write the pid. … 155 fi 156 } … 216 # Start up the service 217 launch_service "$pidfile" "$daemonized" "$properties" 7
  • 8.
    class Elasticsearch(1/2) src/main/java/org/elasticsearch/bootstrap/Elasticsearch.java: 25 public class Elasticsearch extends Bootstrap { 26 27 public static void close(String[] args) { 28 Bootstrap.close(args); 29 } 30 31 public static void main(String[] args) { 32 Bootstrap.main(args); 33 } 34 } 8
  • 9.
    class Elasticsearch(2/2) Bootstrap Elasticsearch • class Bootstrapをラップしてい るだけ
  • 10.
    Bootstrap.main() src/main/java/org/elasticsearch/bootstrap/Bootstrap.java: 145public static void main(String[] args) { 146 System.setProperty("es.logger.prefix", ""); 147 bootstrap = new Bootstrap(); … 197 String stage = "Initialization"; 198 try { 199 if (!foreground) { 200 Loggers.disableConsoleLogging(); 201 System.out.close(); 202 } 203 bootstrap.setup(true, tuple); 204 205 stage = "Startup"; 206 bootstrap.start(); … 233 } catch (Throwable e) { … 250 } 251 } 10
  • 11.
    Bootstrap.{setup,start}() src/main/java/org/elasticsearch/bootstrap/Bootstrap.java: 50/** 51 * A main entry point when starting from the command line. 52 */ 53 public class Bootstrap { … 62 private void setup(boolean addShutdownHook, Tuple<Settings, Environment> tuple) throws Exception { … 69 NodeBuilder nodeBuilder = NodeBuilder.nodeBuilder().settings(tuple.v1()).loadConfigSettings(fa lse); 70 node = nodeBuilder.build(); … 79 } … 118 /** 119 * hook for JSVC 120 */ 121 public void start() { 122 node.start(); 123 } 11
  • 12.
    NodeBuilder src/main/java/org/elasticsearch/node/NodeBuilder.java: 26/** 27 * A node builder is used to construct a {@link Node} instance. … 57 */ 58 public class NodeBuilder { … 64 /** 65 * A convenient factory method to create a {@link NodeBuilder}. 66 */ 67 public static NodeBuilder nodeBuilder() { 68 return new NodeBuilder(); 69 } … 155 /** 156 * Builds the node without starting it. 157 */ 158 public Node build() { 159 return new InternalNode(settings.build(), loadConfigSettings); 160 } 12
  • 13.
    class InternalNode AutoClosable Releasable <<interface>> Node final InternalNode • ノードに関する情報を保持しているクラス • elasticsearchの各々のサーバのこと
  • 14.
    InternalNode(1/2) src/main/java/org/elasticsearch/node/internal/InternalNode.java: 111public final class InternalNode implements Node { … 116 private final Injector injector; … 126 public InternalNode(Settings preparedSettings, boolean loadConfigSettings) throws ElasticsearchException { … 138 logger.info("initializing …"); … 157 try { … 194 injector = modules.createInjector(); … 204 logger.info("initialized"); 205 } 14
  • 15.
    InternalNode src/main/java/org/elasticsearch/node/internal/InternalNode.java: 217public Node start() { … 223 logger.info("starting ..."); … 241 injector.getInstance(SearchService.class).start(); 242 injector.getInstance(MonitorService.class).start(); 243 injector.getInstance(RestController.class).start(); … 258 logger.info("started"); 259 260 return this; 261 } 15
  • 16.
    Node, Reasable, AutoCLosable src/main/java/org/elasticsearch/node/Node.java: 35 public interface Node extends Releasable{ … 47 /** 48 * Start the node. If the node is already started, this method is no-op. 49 */ 50 Node start(); … 66 } ! src/main/java/org/elasticsearch/common/lease/Releasable.java: 27 public interface Releasable extends AutoCloseable { 28 29 void close() throws ElasticsearchException; 30 } ! src/main/java/org/elasticsearch/common/lease/Releasable.java: 27 public interface Releasable extends AutoCloseable { 28 29 void close() throws ElasticsearchException; 30 } 16
  • 17.
    (最掲)bootstrap.main() src/main/java/org/elasticsearch/bootstrap/Bootstrap.java: 145public static void main(String[] args) { 146 System.setProperty("es.logger.prefix", ""); 147 bootstrap = new Bootstrap(); … 197 String stage = "Initialization"; 198 try { 199 if (!foreground) { 200 Loggers.disableConsoleLogging(); 201 System.out.close(); 202 } 203 bootstrap.setup(true, tuple); 204 205 stage = "Startup"; 206 bootstrap.start(); … 233 } catch (Throwable e) { … 250 } 251 } 17
  • 18.
    InternalNode src/main/java/org/elasticsearch/node/internal/InternalNode.java: 217public Node start() { … 223 logger.info("starting ..."); … 241 injector.getInstance(SearchService.class).start(); 242 injector.getInstance(MonitorService.class).start(); 243 injector.getInstance(RestController.class).start(); … 258 logger.info("started"); 259 260 return this; 261 } 18
  • 19.
    class MonitorService ClosableComponent LifecycleComponent AbstractComponent <<abstract>> AbstractLifecycleComponent MonitorService • 各サービスの実体
  • 20.
    MonitorService src/main/java/org/elasticsearch/monitor/MonitorService.java: 36public class MonitorService extends AbstractLifecycleComponent<MonitorService> { … 83 @Override 84 protected void doStart() throws ElasticsearchException { 85 jvmMonitorService.start(); 86 } ! src/main/java/org/elasticsearch/common/component/AbstractLifecycleComponent.java: 31 public abstract class AbstractLifecycleComponent<T> extends AbstractComponent implements LifecycleComponent<T> { … 77 @Override 78 public T start() throws ElasticsearchException { … 85 doStart(); 86 lifecycle.moveToStarted(); 87 for (LifecycleListener listener : listeners) { 88 listener.afterStart(); 89 } 90 return (T) this; 91 } 20
  • 21.
    (再掲)InternalNode src/main/java/org/elasticsearch/node/internal/InternalNode.java: 217public Node start() { … 223 logger.info("starting ..."); … 241 injector.getInstance(SearchService.class).start(); 242 injector.getInstance(MonitorService.class).start(); 243 injector.getInstance(RestController.class).start(); … 258 logger.info("started"); 259 260 return this; 261 } 21
  • 22.
    まとめ • elasticsearchのソースコードを読み始めてみました • 順当にクラスを追いかけていけば読めます……が • 一つ前のメソッド呼び出しに戻ることが多い感じ • Abstractクラスの実装を追いかけるような場合 • DI(Dependency Injection)が(個人的に)よく分かっていないので、 InternalNodeまわりは読むのがツラい • 手続き指向おじさん(仮)には少し慣れが必要なソースコード • (まだほんのちょっとしか使ってないけど)UMLって便利だね!