« 2013年1月 | トップページ | 2013年3月 »
OpenDolphin-1.3.0 での受付システムは,受付は orca で行い,orca から受付情報を claim で OpenDolphin の受付サーバ(pvt server)に送る仕組みになっている。送られた受付情報は,pvt server で pvt 情報として記録されるが,OpenDolphin クライアントは pvt 情報が更新された時点では,それを知ることができない。そのため,クライアントは pvt 情報を一定時間毎(当院カスタマイズでは 5〜30秒毎)にサーバに取りに行って,取ってきた情報をクライアントの受付画面に表示していた。
この方式では,受付があってからクライアント画面に表示されるまでに,必然的に最大 30秒のタイムラグが生じてしまう。また, pvt 情報更新があってもなくても,クライアントはサーバに常に情報を取りに行くことになるので, 無駄なサーバアクセスが生じてしまう。最新の OpenDolphin では,pvt 情報更新があった時点でクライアントにその情報が送られるようになっているらしいが,当院のシステムは jndi なレガシーシステムで最新方式は使えない。
まあしょうがないかな,と思っていたのであるが,ふと「サーバが pvt 情報に変化があった時点で,LAN 全体に broadcast して,それをクライアントが勝手に拾って,拾った時点で pvt 情報を取りに行ったらいいのでは」と,素人くさいアイデアを思いついた。これなら簡単に実装できるので,早速プログラムしてみたところ,とりあえずうまく動いた。
受付リストがほぼリアルタイムで更新されるようになってよかったのであるが,もう少し素人くさくない方法はないかと思って調べたら,jms (java message service) という,まさにこれという仕組みがあることがわかった。そして,それは増田先生が既に 1.4m 時代に導入されていた方法であることもわかった。orz
増田先生のコードを参考にさせていただいて,無事 jms を導入して,受付リストのリアルタイム更新ができるようになった。しかし,デバッグの段階で,健康保険情報関連の LazyInitializationException が出て困ったので,検索パネルと同じく,健康保険情報はカルテを開くときに初めて fetch するように書き換えたところ,受付リストの表示が劇的に速くなり,Exception も出なくなった。
<hornetq-server> <persistence-enabled>true</persistence-enabled> <security-domain>openDolphin</security-domain> : <security-settings> <security-setting match="#"> <permission type="send" roles="user"/> <permission type="consume" roles="user"/> <permission type="createNonDurableQueue" roles="user"/> <permission type="deleteNonDurableQueue" roles="user"/> </security-setting> </security-settings> : <jms-destinations> <jms-topic name="pvt"> <entry name="topic/pvt"/> <entry name="java:jboss/exported/jms/topic/pvt"/> </jms-topic> </jms-destinations> </hornetq-server>ダウンロード standalone-full.xml (21.9K)
if [ "x$JAVA_OPTS" = "x" ]; then JAVA_OPTS="-Xms64m -Xmx512m -XX:MaxPermSize=256m -Djava.net.preferIPv4Stack=true -Dorg.jboss.resolver.warning=true -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000" JAVA_OPTS="$JAVA_OPTS -Djboss.modules.system.pkgs=$JBOSS_MODULES_SYSTEM_PKGS -Djava.awt.headless=true" # JAVA_OPTS="$JAVA_OPTS -Djboss.server.default.config=standalone.xml" JAVA_OPTS="$JAVA_OPTS -Djboss.server.default.config=standalone-full.xml" JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=UTF8"ダウンロード standalone.conf (2.3K)
addPvt,updatePvt で pvt 情報を送信する
private void broadcast(PatientVisitModel pvt) { TopicConnection connection = null; try { InitialContext ic = new InitialContext(); TopicConnectionFactory cf = (TopicConnectionFactory) ic.lookup("/ConnectionFactory"); Topic topic = (Topic) ic.lookup("topic/pvt"); connection = cf.createTopicConnection(); TopicSession session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer publisher = session.createProducer(topic); connection.start(); ObjectMessage message = session.createObjectMessage(pvt); publisher.send(message); } catch (NamingException ex) { logger.error("RemotePvtService broadcast error: " + ex.getMessage()); } catch (JMSException ex) { logger.error("RemotePvtService broadcast error: " + ex.getMessage()); } finally { if (connection != null) { try { connection.close(); //logger.info("TopicConnection closed"); } catch (JMSException ex) { logger.error("RemotePvtService broadcast error: " + ex.getMessage()); } } } }
RemotePvtServiceImpl.java で送信された pvt を受け取り,テーブルを更新する。
private void startPvtMessageReceiver () { try { // ログイン情報 String pk = Project.getFacilityId() + ":" + Project.getUserId(); String password = Project.getUserPassword(); String host = Project.getHostAddress(); int port = Project.getHostPort(); // InitialContext 取得 Properties env = new Properties(); env.put(InitialContext.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory"); env.put("jboss.naming.client.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT", "false"); //env.put("jboss.naming.client.connect.options.org.xnio.Options.SASL_DISALLOWED_MECHAHISMS", "JBOSS-LOCAL-USER"); env.put(InitialContext.PROVIDER_URL, String.format("remote://%s:%d", host, port)); env.put(InitialContext.SECURITY_PRINCIPAL, pk); env.put(InitialContext.SECURITY_CREDENTIALS, password); InitialContext ic = new InitialContext(env); // Lookup the connection factory TopicConnectionFactory cf = (TopicConnectionFactory) ic.lookup("jms/RemoteConnectionFactory"); // Lookup the JMS topic Topic topic = (Topic) ic.lookup("jms/topic/pvt"); // Create the JMS objects to connect to the server and manage a session topicConnection = cf.createTopicConnection(pk, password); TopicSession session = topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer subscriber = session.createConsumer(topic); // 通知された pvt を処理する subscriber.setMessageListener(new MessageListener(){ @Override public void onMessage(Message msg) { try { ObjectMessage message = (ObjectMessage) msg; PatientVisitModel hostPvt = (PatientVisitModel) message.getObject(); // 送られてきた pvt と同じものを local で探す PatientVisitModel localPvt = null; int row = -1; for (int i=0; i<pvtTableModel.getObjectCount(); i++) { PatientVisitModel p = (PatientVisitModel) pvtTableModel.getObject(i); if (p.getPatient().getId() == hostPvt.getPatient().getId()) { localPvt = p; row = i; break; } } int changedRow = -1; if (localPvt != null) { // localPvt がみつかれば,それは state 更新である if (localPvt.getState() != hostPvt.getState()) { localPvt.setState(hostPvt.getState()); changedRow = row; //logger.info("pvt state updated at row " + row); } // byomeicount の更新 if (localPvt.getByomeiCount() != hostPvt.getByomeiCount()) { localPvt.setByomeiCount(hostPvt.getByomeiCount()); changedRow = row; //logger.info("byomeiCount updated at row " + row); } // byomeicounttoday の更新 if (localPvt.getByomeiCountToday() != hostPvt.getByomeiCountToday()) { localPvt.setByomeiCountToday(hostPvt.getByomeiCountToday()); changedRow = row; //logger.info("byomeiCountToday updated at row " + row); } } else{ // localPvt がなければ,それは追加である row = pvtTableModel.getObjectCount(); // 番号付加 hostPvt.setNumber(row+1); pvtTableModel.addRow(hostPvt); changedRow = row; //logger.info("pvt added at row " + row); // 患者数セット setPvtCount(row+1); } // changeRow を fire,ただしカルテが開いていたら fire しない if (changedRow != -1 && !ChartImpl.isKarteOpened(localPvt)) { pvtTableModel.fireTableRowsUpdated(changedRow, changedRow); } } catch (JMSException e) {} } }); topicConnection.start(); } catch (NamingException e) { e.printStackTrace(System.err); } catch (JMSException e) { e.printStackTrace(System.err); } }
設定したカルテ検索期間内にカルテが1件もない場合,見つかるまで自動的にさかのぼって,最低1件は履歴に表示するようにした。例えば,5年以上前に1度受診した患者さんが久しぶりに受診した場合など,カルテ検索期間を5年にしておいても,それ以前のカルテが自動的に検索されて履歴に表示される。
private void updateHistory(List newHistory) { // ソーティングする if (newHistory != null && !newHistory.isEmpty()) { : } else { // カルテが見つかるまで抽出期間を自動的に延ばす int selected = extractionCombo.getSelectedIndex(); if (selected < extractionCombo.getItemCount() - 1) { extractionCombo.setSelectedIndex(++selected); //System.out.println("extraction period extended to " + extractionObjects[selected]); } else { // 最後まで見つからない=初診カルテ countField.setText("0 件"); } }
以前のコードで「乾癬」を全文検索してみたところ,PatientModel で 217件のヒットがあり,結果の表示までに15秒程度かかってしまった。どこで時間をとっているか調べてみたところ,最終受診日と健康保険情報の取得のところで大量のクエリが発生しており,ここで 14.2秒を消費していた。
そこで,最終受診日を取得するクエリを 1回ですますように工夫し,さらに健康保険情報をあらかじめ取得せず,カルテをオープンする時に初めて取りに行くようにしたところ,15秒かかっていた検索時間を 1秒以下に減らすことができた。
試しにリニューアルしたコードで「紅斑」を検索してみたところ,7,377件のヒットがあり,さすがにここまで多いと表示までに 30秒かかってしまった。件数があまり多い場合には,100件ずつ分けて表示する等の対処方法が考えられるが,今のところ,こんな検索をする方が悪いということにしておく。
// pvt をまとめて取得する(高速化のため) List<PatientVisitModel> pvts = em.createQuery("from PatientVisitModel p " + "where p.facilityId = :fid and p.status != :status and (p.patient in (:pts)) order by p.pvtDate desc") .setParameter("fid", fid) .setParameter("pts", ret) .setParameter("status", KarteState.CANCEL_PVT) .getResultList(); // まとめて取った pvt から最新の日付を PatientModel にセット for (PatientModel pm : ret) { for (PatientVisitModel pvt : pvts) { // 最初にマッチした pvt が最新 (last visit) if (pm.getId() == pvt.getPatient().getId()) { pm.setLastVisit(pvt.getPvtDate()); break; } } }
public void openKarte(final PatientModel patient) { if (canOpen(patient)) { Thread t = new Thread() { @Override public void run() { // 健康保険情報をフェッチする PatientDelegater pdl = new PatientDelegater(); pdl.fetchHealthInsurance(patient); :
Hibernate search で,AND/OR 検索が普通にできるのは Apache Lucene Query Parser というのが検索語を解釈してクエリに変換してくれているからであった。つまり,PatientModel をインデックスしてあれば,検索語のレベルで PatientModel の id で絞り込み検索ができるようになる。
そこで,下のようにインデックスを追加した。なお,DocumentModel は KarteEntryBean を extend してあり,DocumentModel が @Indexed されているので,KarteEntryBean も @Indexed 状態になっている。
KarteEntryBean.java @IndexedEmbedded KarteBean karte KarteBean.java @IndexedEmbedded PatientModel patient
インデックスをつけると,@Field がついていなくても @Id は自動的に検索対象になる。つまり,上記のインデックス付けをすると,KarteBean と PatientModel の id が自動的に検索対象になり,それぞれ "karte.id","karte.patient.id" というキーで検索できる。例えば PatientModel の primary key = 945 で絞り込みをしたい場合,"SearchText AND karte.patient.id:945" という検索語で検索できるようになる。今回作成した全文検索の絞り込み検索モードにこれを利用している。
Java Swing Hacks を参考に,入力履歴を覚えておいて補完する CompletableJTextField.java を作った。いろいろ Listener をつけて,入力中に矢印キーで履歴を選択できるようにしたり,リターンキーで自動的に補完履歴に登録されるようにしたり,補完ウインドウが出ているときにフォーカスを失った場合や,フレームを動かした場合の処理なども加えている。なお,補完ウインドウを半透明にするコード(com.sun.awt.AWTUtilities.setWindowOpacity)は java 7 では動かないらしい。
検索パネルの動作を見直した。
「患者検索」「カルテ検索」「メモ検索」の選択ボタンをなくして(左),できるだけ自動判定するようにした。
検索フィールドに数字を入力してリターンを押すと患者番号検索になる(右)。何も入力せずにリターンを押すか,検索フィールド右の「×」を押すと,検索結果はクリアされて,最初の状態(左)に戻る。
なお,検索後にテキストの背景が黄色くなっているのは(右),後で説明する「絞り込み検索モード」になっていることを表している。
西暦形式の日付を入力すると受診日検索となる(左)。年号形式の日付を入力すると誕生日検索となる(右)。
「カタカナ」「ひらがな」だけを入力すると名前のカナ検索になる(左)。それ以外の文字を入れると,カルテ内の全文検索になる(右)。ただし,薬の名前を検索するときに患者名検索になってしまって不便なので,名前検索で結果が 0 の時は,引き続き全文検索に切り替えて検索しなおすようにプログラムしてある。
上記の自動判定検索で,ほとんどの場合は大丈夫と思われるが,より正確に検索モードを指定したい場合は,検索語の前に半角アルファベット+スペースを入力する。"N " をつければ,漢字の名前で検索することができる(左)。虫眼鏡をクリックすると,入力に必要なアルファベットをメニューから選べるようにした。
同じメニューで絞り込み検索モードの on/off,インデックス作成もできるようにした(左)。また,検索フィールドの入力履歴を覚えておいて,補完できるようにした(右)。
絞り込みモードが on の場合,検索してテーブルに検索結果リストができると,検索フィールドの背景が黄色くなり,自動的に絞り込み検索モードに入る。このモードでは,検索結果リストの中からだけ検索するようになる。つまり,例えば受診日検索で 2013-02-12 の受診患者リストを検索し(左),絞り込みモードでその日の「北大」から紹介された患者さんを抽出するという風に使うことができる(右)。
うまくいったかどうかのテスト。
さて,動作は問題ないようなので,開発用マシンで全インデックスを作成してみたところ,117,673 件の DocumentModel にインデックスするのに4時間近くかかってしまった。(インデックスが 4分以下で終了していた時代が懐かしい)
INFO boot.logger - IndexTask started at Mon Feb 11 04:58:28 JST 2013 INFO boot.logger - IndexTask ended at Mon Feb 11 08:44:58 JST 2013
そこで,MassIndexer というのを試してみた。どうせ index は1回つくればいいことなので,client への進捗フィードバックとか全部すっとばしてコーディングしてみたところ,1時間22分で終了した。ただし注意点として,デフォルトの standalone.xml の設定だとトランザクションが 300秒 (5分) で timeout して止まってしまうので,インデックス作成の時だけ,かかる時間以上に設定しておく必要がある。下の例では 14,400秒 (4時間) に設定した。
standalone.xml の該当部分
<subsystem xmlns="urn:jboss:domain:transactions:1.2"> <core-environment> <process-id> <uuid/> </process-id> </core-environment> <recovery-environment socket-binding="txn-recovery-environment" status-socket-binding="txn-status-manager"/> <coordinator-environment default-timeout="14400" /> </subsystem>
OpenDolphin における hibernate search 導入のフロンティアといえば何といっても増田先生である。現在当院で使っているコードは増田先生の初期バージョンのものであるが,今回 JBoss AS 7.1 導入に合わせて,最新版の 2.3m から hibernate search 関連部分コードを使わせていただいて導入した。初期バージョンでは ModuleModel で index されていたが,現在の 2.3m では DocumentModel に index するように変更されている。
@Entity //@Indexed(index="module") // masuda @Table(name = "d_module") public class ModuleModel extends KarteEntryBean { : @Lob // masuda @Field(index = Index.YES) @FieldBridge(impl = ModuleModelBridge.class) @Analyzer(impl = CJKAnalyzer.class) // masuda
@Indexed(index="document") // hibernate search @Entity @Table(name = "d_document") public class DocumentModel extends KarteEntryBean { : @IndexedEmbedded // hibernate search @OneToMany(mappedBy="document", cascade={CascadeType.PERSIST, CascadeType.REMOVE}) private Collectionmodules;
public void clearIndex() { FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(em); fullTextEntityManager.purgeAll(DocumentModel.class); : public void makeInitialIndex(Long fromId, Long toId) { final FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(em); final String sql = "from DocumentModel m where m.status = 'F' and m.id >= :min and m.id < :max"; List<DocumentModel> modules = em.createQuery(sql) : for (DocumentModel dm : modules) { fullTextEntityManager.index(dm); : public ListgetPatientOfKarte(String text) { : final Analyzer analyzer = fullTextEntityManager.getSearchFactory().getAnalyzer(DocumentModel.class); : org.apache.lucene.queryParser.QueryParser parser = new QueryParser(ver, "modules.beanBytes", analyzer); :
@Override public long addDocument(DocumentModel document) { : // オリジナルを取得し 終了日と status = M を設定する DocumentModel old = em.find(DocumentModel.class, parentPk); old.setEnded(ended); old.setStatus(STATUS_MODIFIED); // HibernateSearchのFulTextEntityManagerを用意。修正済みのものはインデックスから削除する by masuda-sensei final FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(em); fullTextEntityManager.purge(DocumentModel.class, parentPk); :
$ mvn install:install-file -Dfile=glulogic.jar -DgroupId=jp.motomachi-hifuka -DartifactId=glulogic -Dversion=1.0 -Dpackaging=jar $ mvn install:install-file -Dfile=quaqua-pns.jar -DgroupId=jp.motomachi-hifuka -DartifactId=quaqua-pns -Dversion=7.3.4-pns -Dpackaging=jar
<property name="hibernate.search.default.directory_provider" value="filesystem"/>
@Field(index = Index.YES)
public ListgetPatientTextSearch2(String text) { final FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(em); final Analyzer analyzer = fullTextEntityManager.getSearchFactory().getAnalyzer(ModuleModel.class); final org.apache.lucene.util.Version ver = org.apache.lucene.util.Version.LUCENE_35; try { // create native Lucene query org.apache.lucene.queryParser.QueryParser parser = new QueryParser(ver, "beanBytes", analyzer);
========================================================================= JBoss Bootstrap Environment JBOSS_HOME: /Applications/jboss-as-7.1.4.Final : 04:12:30,356 INFO [CONSOLE] (Thread-84) PvtServer: waiting for connection 04:12:30,368 INFO [org.jboss.as.server] (ServerService Thread Pool -- 28) JBAS018559: "opendolphin-ea-ear-1.3.0.8.ear" をデプロイしました。 :
#!/bin/sh JBOSS_HOME=/usr/local/jboss case "$1" in start) echo "Starting JBoss AS" start-stop-daemon --start --quiet --background --exec ${JBOSS_HOME}/bin/standalone.sh -- -b 0.0.0.0 ;; stop) echo "Stopping JBoss AS" start-stop-daemon --start --quiet --background --exec ${JBOSS_HOME}/bin/jboss-cli.sh -- --connect command=:shutdown ;; *) echo "Usage: /etc/init.d/jboss {start|stop}" exit 1 ;; esac exit 0
$ cd jboss-as-7.1 $ export JAVA_HOME=`/usr/libexec/java_home -v 1.6` $ ./build.sh : $ cp -r build/target/jboss-as-7.1.4.Final-SNAPSHOT /Applications/
JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=UTF8"
$ ./standalone.sh -b 0.0.0.0 ========================================================================= JBoss Bootstrap Environment JBOSS_HOME: /Applications/jboss-as-7.1.4.Final JAVA: /Library/Java/JavaVirtualMachines/1.6.0_29-b11-402.jdk/Contents/Home/bin/java JAVA_OPTS: -d32 -client -Xms64m -Xmx512m -XX:MaxPermSize=256m -Djava.net.preferIPv4Stack=true -Dorg.jboss.resolver.warning=true -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true -Djboss.server.default.config=standalone.xml -Dfile.encoding=UTF8 ========================================================================= 20:51:46,707 INFO [org.jboss.modules] JBoss Modules version 1.1.3.GA 20:51:46,854 INFO [org.jboss.msc] JBoss MSC version 1.0.2.GA 20:51:46,906 INFO [org.jboss.as] JBAS015899: JBoss AS 7.1.4.Final-SNAPSHOT "Arges" が起動しています。 20:51:47,491 INFO [org.xnio] XNIO Version 3.0.7.GA 20:51:47,493 INFO [org.jboss.as.server] JBAS015888: socket-binding (management-http) を使い http 管理サービスを作成しています。 20:51:47,497 INFO [org.xnio.nio] XNIO NIO Implementation Version 3.0.7.GA 20:51:47,503 INFO [org.jboss.remoting] JBoss Remoting version 3.2.13.GA : 20:51:47,937 INFO [org.jboss.as] (Controller Boot Thread) JBAS015874: JBoss AS 7.1.4.Final-SNAPSHOT "Arges" は 1482ms でスタートしました - サービス 222 個のうち 144 個を開始しました (76 のサービスはパッシブあるいはオンデマンドとなっています)。
<?xml version="1.0" encoding="UTF-8"?> <module xmlns="urn:jboss:module:1.0" name="org.postgresql"> <resources> <resource-root path="postgresql-9.1-901.jdbc4.jar"/> </resources> <dependencies> <module name="javax.api"/> </dependencies> </module>
<subsystem xmlns="urn:jboss:domain:datasources:1.0"> <datasources> <datasource jta="true" jndi-name="java:/PostgresDS" pool-name="PostgresDS" enabled="true" use-ccm="false"> <connection-url>jdbc:postgresql://localhost:5432/dolphin</connection-url> <driver-class>org.postgresql.Driver</driver-class> <driver>postgresql</driver> <security> <user-name>dolphin</user-name> </security> <validation> <validate-on-match>false</validate-on-match> <background-validation>false</background-validation> </validation> <statement> <share-prepared-statements>false</share-prepared-statements> </statement> </datasource> <drivers> <driver name="postgresql" module="org.postgresql"/> </drivers> </datasources> </subsystem>
<security-realm name="DolphinRealm"> <authentication> <jaas name="openDolphin"/> </authentication> </security-realm>
<subsystem xmlns="urn:jboss:domain:remoting:1.1"> <connector name="remoting-connector" socket-binding="remoting" security-realm="DolphinRealm"/> </subsystem>
<security-domain name="openDolphin" cache-type="default"> <authentication> <login-module code="Database" flag="required"> <module-option name="dsJndiName" value="java:/PostgresDS"/> <module-option name="principalsQuery" value="SELECT PASSWORD FROM D_USERS WHERE USERID=?"/> <module-option name="rolesQuery" value="SELECT C_ROLE, 'Roles' FROM D_ROLES WHERE USER_ID=?"/> <module-option name="hashAlgorithm" value="MD5"/> <module-option name="hashEncoding" value="hex"/> </login-module> </authentication> </security-domain>
dolphin=# select count(*) from d_patient; count ------- 15997 (1 row)
dolphin=# select count(*) from d_module; count -------- 585721 (1 row)
Filesystem Size Used Avail Use% Mounted on /dev/xvda1 46G 8.3G 36G 20% / udev 600M 4.0K 600M 1% /dev tmpfs 249M 168K 248M 1% /run none 5.0M 0 5.0M 0% /run/lock none 621M 0 621M 0% /run/shm
/dev/xvda1 28G 4.3G 22G 17% / none 745M 108K 745M 1% /dev none 777M 0 777M 0% /dev/shm none 777M 72K 776M 1% /var/run none 777M 0 777M 0% /var/lock none 777M 0 777M 0% /lib/init/rw
Backup/dolphin_db.dump.gpg 1,178,307,353 Backup/orca_db.dump.gpg 53,630,204
$ grep -c stampInfo stamp.xml 1944
orca サーバをやっと ubuntu 8.04 hardy から 10.04 lucid にアップデートしたが,dolphin サーバの方は hardy のままであった。そこで,将来的には orca も ubuntu 12.04 precise の 64bit に移行することになるので,先に dolphin サーバを precise 64bit に移行してみることにした。
既に xen の dom-0 は precise 64bit にしてあるので,xen dom-0 と同じカーネルを dom-U でもつかえる。なので,わざわざ debootstrap を使ってインストールしなくても,普通に cd から新しいパーティションにインストールして,xen で dom-0 のカーネルを使って,新規インストールしたパーティションから dom-U を立ち上げればよい。
desktop バージョンのインストーラーは勝手に MBR を書き直したりしてうざいので,サーバー版のインストーラを使ってインストールした。ちなみに,precise から,server 版と desktop 版のカーネルに違いはないらしい。まずはテスト環境の mac mini の sdb4 に 30GB のパーティションを作ってインストールしてみた。
インストール自体は特に問題なかったので,以下はインストール後の dom-U 設定の記録。
$ sudo aptitude install ethtool $ cat /etc/network/interfaces # The loopback network interface auto lo iface lo inet loopback # The primary network interface auto eth0 iface eth0 inet static address 192.168.1.102 netmask 255.255.255.0 network 192.168.1.0 broadcast 192.168.1.255 gateway 192.168.1.1 dns-nameservers 192.168.1.1 offload-tso off
$ sudo aptitude install openjdk6-jdk $ java -version Java version "1.6.0_24" OpenJDK Runtime Environment (IcedTea6 1.11.5) (6b24-1.11.5-0ubuntu1~12.04.1) OpenJDK 64-Bit Server VM (build 20.0-b12, mixed mode)
export JAVA_HOME='/usr/lib/jvm/java-6-openjdk-amd64'
$ sudo aptitude install postgresql $ sudo -u postgres createuser dolphin Shall the new role be a superuser? (y/n) y $ sudo -u postgres createdb dolphin $ pg_restore -Fc -d dolphin dolphin_db.dump
$ psql dolphin=# alter user dolphin with password '' ;pg_hba.conf
local all all trust
# cd /etc/init.d/ # ln -s /usr/local/jboss/bin/jboss_init_ubuntu.sh jboss # update-rc.d jboss defaults
テスト環境で動作を確認した後,実運用開始したが,今のところ問題なく動いている。ついでに,ファイルサーバ(samba)も 32bit から 64bit にインストールしなおした。あとは orca だけである。