manywaypark's Blog
개발, 검색, 함수

[FUN] Spiral Array

함수형 언어/Erlang 2008. 8. 13. 18:11 by manywaypark
여기에서 호기심을 조금 느꼈는데, 링크된 여기를 보고는 완전 몰입.

문제를 푸는 것자체는 그다지 어렵지 않았으나, 멋있게 풀어보려고, 오늘 출근길 지하철에서 타블렛에 좀 끄적였다.
W by H 행렬이라 보고, top left에서, 시계방향, 반시계방향 Spiral Array를 출력해주는 것을 만들었다.
(물론 요즘은 erlang에 심취해있으므로,  구현언어는 당연히 erlang이다.)

요지는 조건 검사 같은 것을 하는 것이아니라, 수열을 사용한다.
즉, 동일한 상태 이동의 반복 회수가 수열이다. 연속된 transition의 개수를 구하는 함수를 f(x)라 하면,
f(x) = f(x - 2) - 1

x가 2보다 크면 무조건 성립이고, x = 1, 2 일때의 값은 clockwise, counterclockwise에 따라 W 또는 H로 조금 달라지기는 하지만 중요한 요점은 수열을 이용해 계산으로 구한다는것이다. 자세한 건 코드 참조!

성능은 1000 x 1000의 결과 구하는데 3초정도 걸리는 것같다.

실행예:
(emacs@desktop)2> sa:do(5,4).
   1    2    3    4    5
  14   15   16   17    6
  13   20   19   18    7
  12   11   10    9    8
ok
(emacs@desktop)3> sa:do(4,5).
   1    2    3    4
  14   15   16    5
  13   20   17    6
  12   19   18    7
  11   10    9    8
ok
(emacs@desktop)5> element(1, timer:tc(sa,solve, [1000,1000])) / 1000000.
3.126565

code listing:

2008-08-18 : 거의 동일한 방법으로 푼 사람이 이미 있었다. 맨앞에 몇개와 끝부분의 erlang 버전만 확인하고서 획기적인 방법이라고 좋아라하고 있었다니.... Orz. 그래도 high order function을 사용해서 functional에 걸맞는 멋진 프로그램이라고 나 자신에게 조금은 구차한(?) 최면을 거는 중이다.

happy hackin'

일단 eunit으로 테스트를 하는 것을 가정한다.

unit test - makefile에서...
make file에 다음과 같은 부분을 추가한 후에, make test 하면 간편하게 명령행에서 unit test를 수행할 수있다.
(makefile 뼈대는 Programming Erlang을 기초로 했다.)

......
MODS = doc str_util db i18n tiny_scan
......

test: compile test_subdirs
    rm -rf Mnesia.nonode@nohost # removes previous mneisa db (optional).
    @for m in ${MODS};\
    do \
        echo "testing $$m";\
        ${ERL} -noshell -pz "subdir1" -pz "subdir2" -s $$m test -s init stop;\
    done

test_subdirs:
    cd subdir1; make test
    cd subdir2; make test

unit test, coverage test - 개발중 REPL(distel 또는 erl prompt) 에서...
REPL을 사용해서 (멋지게) 코딩-테스트를 반복중이라면, 다음과 같은 모듈을 하나 디렉토리에 넣어서 test:unit() 또는 test:cover() 를 실행시켜서 unit test 및 coverage test를 시시때때로 수행해 볼 수 있다.


테스트는 아무리 강조해도 지나치지 않다.
경험상 대부분의 버그는 테스트되지 않거나, 적절하지 못한 테스트(셋)들을 통과한 코드에 기생한다.

happy hackin'



해당 version: R12B-3

xmerl을 사용하여 다량의 xml 파일들을 파싱하는 도중에 특정 파일에서 CPU/메모리사용량이 치솟고 다음과 같은 에러메시지와 함께 erlang이 죽어버렸다.

eheap_alloc: Cannot allocate xxxxx bytes of memory (of type "heap").

특정 파일 하나에서만 이 현상이 생겼는데, 파일을 열어보니 복잡한 테이블과, entity들을 많이 사용한 xml이었다. 조금 복잡하긴 했지만 정상적인 xml이었다.

검색한 결과 xmerl_scan의 버그임이 밝혀졌다.
(R12B-4 에서는 패치된 버전이 포함될 것이라고 한다).

링크에 나와있는대로 한줄만 고쳐주면 에러없이 잘 동작한다.



happy hackin'

erlang build 하기

함수형 언어/Erlang 2008. 7. 29. 23:22 by manywaypark
압축풀고 README에 있는 프로그램들 깔려있는지 확인하고,
$ ./configure --enable-hipe --enable-threads
$ make
$ sudo make install

(odd) case error of
checking for C compiler default output file name... configure: error: C compiler cannot create executables
See `config.log' for more details.
-> install libc (apt-get install libc6-dev).
end.

2008-11-01: 간만에 새로 ubuntu를 설치한 박스에서 erlang을 build하려고 시도하니, 필요한 패키지가 정확하게 드러났다.
현재 최신의 OTP-R12B-4를 빌드할 때 모든 기능을 활성화 하기위한 패키지들은 다음과같다.
m4
autoconf
g++
libc6-dev
libncurses5-dev
unixodbc-dev
libssl-dev

happy hackin'
erlang의 one-time assignment를 이용한 간단한 리팩토링에 관해서 설명한다.

erlang에서의 변수 특성:
  1. erlang은 변수에 값(value)를 한번만 할당(assign)할 수 있다.
  2. 한번 값이 할당된 변수는 이전과 동일한 값을 할당하지 않으면 에러가 난다.

확인:
(emacs@desktop)54> Foo = 1.
1
(emacs@desktop)55> Foo = 1.
1
(emacs@desktop)56> Foo = 2.
** exception error: no match of right hand side value 2

리팩토링은 보통 코드의 결과는 그대로 유지하면서 내부를 개선하는 것으로 정의된다.

변수 특성을 이용한 리팩토링 절차:
  1. 리팩토링할 함수를 정한다.
  2. 함수의 결과값을 변수에 저장한다. (적절한 인자를 줄 수도 있다)
  3. 함수 리팩토링 & 컴파일
  4. 같은 변수에 새 함수의 결과값을 대입해본다.
  5. 에러 체크.

간단한 함수의 경우는 이 방법이 별 필요가 없을 수도 있지만, 수백 수천개의 list element들을 결과로 리턴하는 경우에는 꽤나 유용하다.

각각 다른 변수(Before, After)에 대입해서 =:= 연산자로 비교할 수도 있겠지만, 그냥 같은 변수에 대입해 보는 것이 조금 더 편하다. (자연스런 REPL loop + history 기능 활용)

물론 여기서 설명한 것은 간단히 빨리 테스트해보아야할 경우를 위한 것이다. 실제 제품개발에는 eunit같은 unit test tool을 적용해 조직화된 테스트셋을 구성해야한다.

happy hackin'

xml 파일을 저장하기위해 다음과 같은 함수를 만들었다.
save_xml(Path, RootEl) ->
    {ok,IOF}=file:open(Path,[write]),
    Export=xmerl:export_simple([RootEl], xmerl_xml),
    io:format(IOF,"~s~n", [lists:flatten(Export)]),
    file:close(IOF).

에러가 났다.
83> foo:save_xml("/tmp/foo.xml", Root).
** exception exit: {badarg,[{io,format,
                                [<0.3348.0>,"~s~n",
                                 [[60,63,120,109,108,32,118,101,114,115,105,
                                   111,110,61,34,49,46,48,34|...]]]},
                            {erl_eval,do_apply,5},
                            {shell,exprs,6},
                            {shell,eval_exprs,6},
                            {shell,eval_loop,3}]}
     in function  io:o_request/2

이거 분명히 예전에 공부할 때 예제가 동작하는 것을 확인한 함수였는데....
binary로 써보기로했다.
84> Export=xmerl:export_simple([Root], xmerl_xml).
      ........
85> file:write_file("/tmp/1.xml", list_to_binary(lists:flatten(Export))).
** exception error: bad argument
     in function  list_to_binary/1
        called as list_to_binary([60,63,120,109,108,32,118,101,114,115,105,
                                  111,110,61,34,49,46,48,34,63,62,60,111,108,
                                  100,114,103,112|...])

한글이 포함되어 안되는 것으로 짐작이 갔다.
99> list_to_binary([0, 1, 2]).
<<0,1,2>>
100> list_to_binary([0, 1, 2, 255]).
<<0,1,2,255>>
101> list_to_binary([0, 1, 2, 255, 256]).
** exception error: bad argument
     in function  list_to_binary/1
        called as list_to_binary([0,1,2,255,256])

결론은 list_to_binary가 255를 넘어가는 non-ascii를 제대로 처리하지 못해서였다.
102> list_to_binary(xmerl_ucs:to_utf8([0, 1, 2, 255, 256])).
<<0,1,2,195,191,196,128>>
103> file:write_file("/tmp/1.xml", list_to_binary(xmerl_ucs:to_utf8(lists:flatten(Export)))).
ok

맨 처음 함수는 이런 식으로 변경:
save_xml(Path, RootEl) ->
    {ok,IOF}=file:open(Path,[write]),
    Export=xmerl:export_simple([RootEl], xmerl_xml),
    io:format(IOF,"~s~n", [xmerl_ucs:to_utf8(lists:flatten(Export))]),
    file:close(IOF).

참고: http://intertwingly.net/blog/2007/09/14/ASCII-ISO-8859-1-UCS-and-Erlang

happy hackin'
esolr를 사용하려고 좀 만지작 거리다가, 버그를 하나 발견해서, 리포팅했다.
설명에 나온 기본 세팅으로 하면 잘 되는 것처럼 보이지만, select_url과 search_url 두개의 key가 Option을 설정할 때와 읽어올 때 혼동되게 되어있어서, solr의 URL을 정해주면 제대로 동작하지 않는 버그였다.
딸리는 영어지만 원작자의 페이지에 댓글을 달아두었다. ^^;

happy hackin'
jetty에 동일한 war를 context path를 달리해서 여러 instance를 띄우는 방법에 관해 간략히 설명한다.
비교적 복잡한 solr를 예로 들겠다.

jetty 설치
jetty는 debian package를 다운로드 받아서 깔면 별 문제없이 잘 실행된다.
(ftp://ftp.mortbay.org/pub/)
현재 안정 버전중 최신인 jetty-6.1.11를 받았다.

동일 war 여러 instance 설정
동일한 war를 다른 context path 및 설정으로 실행시키고 싶었다.
solr로 예를 들자면, 몇개의 설정이 다른 solr가 떠서 url에 따라 다른 분야의 검색에 관한 서비스(인덱싱, 검색 질의 등)를 제공하는 것이다.
solr wiki에 관련 설명이 나오는데 좀 모호한 부분이 있어서 한번 정리해 보았다.
  1. 중복 deploy 방지 (disable WebAppDeployer): /etc/jetty6/contexts 쪽의 설정만 사용하게 하기위해서 /etc/jetty6/jetty.xml에서 다음 부분을 삭제하거나, 주석처리한다.
        <Call name="addLifeCycle">
          <Arg>
            <New class="org.mortbay.jetty.deployer.WebAppDeployer">
              <Set name="contexts"><Ref id="Contexts"/></Set>
              <Set name="webAppDir"><SystemProperty name="jetty.home" default="."/>/webapps</Set>
          <Set name="parentLoaderPriority">false</Set>
          <Set name="extract">true</Set>
          <Set name="allowDuplicates">false</Set>
              <Set name="defaultsDescriptor"><SystemProperty name="jetty.home" default="."/>/etc/webdefault.xml</Set>
            </New>
          </Arg>
        </Call>
    jetty.home/webapps에 있는 war를 자동으로 deploy하게 하는 부분인데, contexts에 있는 설정에서 webapps를 참조하게 할 것이므로 비활성화 시키는 것이다 (다른 디렉토리를 사용하면 이 과정이 아마 필요없을듯하다).

  2. 설정 파일 생성 (동일한 war를 사용하는 다른 instance도 contextPath를 달리해서 생성가능하다.)
    /etc/jetty6/contexts/people.xml :
    <?xml version="1.0"  encoding="ISO-8859-1"?>
    <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
    <Configure class="org.mortbay.jetty.webapp.WebAppContext">
      <!-- Required -->
      <Set name="contextPath">/people</Set>
      <Set name="war"><SystemProperty name="jetty.home" default="."/>/webapps/apache-solr-1.3-dev.war</Set>

      <Set name="defaultsDescriptor"><SystemProperty name="jetty.home" default="."/>/etc/webdefault.xml</Set>
      <Set name="overrideDescriptor"><SystemProperty name="jetty.home" default="."/>/contexts/override.d/override-people.xml</Set>

      <!-- Active JNDI so we can specify "solr/home" -->
      <Array id="plusConfig" type="java.lang.String">
          <Item>org.mortbay.jetty.webapp.WebInfConfiguration</Item>
          <Item>org.mortbay.jetty.plus.webapp.EnvConfiguration</Item>
          <Item>org.mortbay.jetty.plus.webapp.Configuration</Item>
          <Item>org.mortbay.jetty.webapp.JettyWebXmlConfiguration</Item>
          <!-- <Item>org.mortbay.jetty.webapp.TagLibConfiguration</Item> -->
      </Array>
      <Set name="ConfigurationClasses"><Ref id="plusConfig"/></Set>

      <!-- Adding <New class="org.mortbay.jetty.plus.naming.EnvEntry"> -->
      <!-- here sets a GLOBAL jndi value. Arg!                         -->
      <!-- So we specify "solr/home" in the overrideDescriptor instead -->
    </Configure>

    /etc/jetty6/contexts/override.d/override-people.xml :
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <web-app
       xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
       version="2.5">

    <!-- This web.xml format file is applied to the people webapp
         AFTER it has been configured by the default descriptor
         and the WEB-INF/web.xml descriptor -->

      <env-entry>
        <env-entry-name>solr/home</env-entry-name>
        <env-entry-value>./people</env-entry-value>
        <env-entry-type>java.lang.String</env-entry-type>
      </env-entry>

      <!-- NOTE: If Solr looked at something like this:                -->
      <!-- NOTE:   getServletContext().getInitParameter("solr.home");  -->
      <!-- NOTE: we could do the following w/o mucking with JNDI       -->
      <!--
      <context-param>
        <param-name>solr.home</param-name>
        <param-value>fixme-some-path</param-value>
      </context-param>
      -->
     
    </web-app>

  3. 위의 두 파일은 인물 검색용 이라고 가정하자. 위의 파일에서 파일명과 파일 내용에 나오는 people을 book으로 바꾸어서 저장하면, 이제 http://localhost:8080/pepple/admin, http://localhost:8080/book/admin 두개의 독립된 solr를 하나의 servlet engine - jetty -에서 실행시키고 있는 것이다.

  4. 두 context path에서 실행은 되는데 아마도 에러가 날것이다.
    solr 관련 설정이 없어서 인데, "solr/home"으로 지정한 디렉토리에, solr의 example에 있는 solr 디렉토리 내의 파일들을 다 복사해주면 된다.
    즉 위의 설명대로 파일 및 디렉토리를 구성했다면,
    # JETTY_HOME은 보통 /usr/share/jetty6 이다.
    $ cp -R /path/to/solr/example/solr/* $JETTY_HOME/people/
    $ cp -R /path/to/solr/example/solr/* $JETTY_HOME/book/

  5. 그래도 에러날 것이다.
    이제 정말 마지막 설정하나,
    $JETTY_HOME/(people|book)/conf/solrconfig.xml 에서
    <dataDir>${solr.data.dir:./solr/data}</dataDir>로 되어 있는 부분을
    <dataDir>${solr.data.dir:./people/data}</dataDir>
    <dataDir>${solr.data.dir:./book/data}</dataDir>
    으로 각각 고친다.

  6. 이젠 에러 안날 것이다.
happy hackin'

ps. 요즘 들어 jetty를 많이 사용한다. 가볍고 편리하다. 특히나 jetty-maven-plugin은 말 그대로 zero-configuration!!

Programming Erlang을 읽고...

잡담 2008. 6. 24. 19:22 by manywaypark
가장 기억에 남는 부분은,
최대한 아름다운 코드를 작성하라. 성능 문제가 없다면 그대로 쓴다. 성능 문제가 있다면 profiling 후 결과에 따라 최적화한다. 또한 성능 이슈때문에 코드의 아름다움을 해쳤다면, 최대한 자세히 문서화해야만한다.

읽는 순간 거의 외워버렸는데 원문을 인용하려했으나 책장을 넘겨가며 찾으려니 정말 찾기가 힘들다. ^^;
그리고... 힘들게 원서로 다 읽었는데, 부록을 읽고 있을때쯤 번역서 출간소식을 접했다. Orz.

happy hackin'

[TIP] 내지는 잡담

tips & tricks/Linux/Unix 2008. 6. 21. 04:23 by manywaypark
집에서 좀 볼일이 있어서 회사 서버로 접속을 했다가 Ubuntu 서버들을 간만에 upgrade하려했더니 업데이트 서버에서 파일이 없다는 식의 에러가 나면서 안됐다.
살펴보니 edgy였다. http://(kr|us).archive.ubuntu.com/ubuntu/dists/ 에 직접 브라우저로 들어가서 살펴보니 egdy는 아예 디렉토리도 없다. Orz.
가만히 생각해보니 모든 서버를 Dapper (LTS)로 했다가, 한놈만 갑자기 죽는 현상이 있어서 egdy로 올렸던 것이 떠올랐다.

표준적인(?) 방법으로,
/etc/apt/sources.list에서 edgy를 몽땅 feisty로 바꾸고
apt-get update
apt-get upgrade
apt-get dist-upgrade
를 했는데,

다음과 같은 무시무시한 경고 메시지가 나왔다.
W: mdadm: unchecked configuration file: /etc/mdadm/mdadm.conf
W: mdadm: please read /usr/share/doc/mdadm/README.upgrading-2.5.3.gz .
W: mdadm: no arrays defined in configuration file.
W: mdadm: falling back to emergency procedure in initramfs.

'이거 잘못되면 주말에 회사 나가게 생겼구나. 3T짜리 레이드가 인식이 안될 수도 있겠다'

구글링을 해서 자료를 찾고, reboot을 하는 중에 계속 ping을 날리는데 ping
"Destination Host Unreachable"에서 "64 bytes from boxname (xxx.xxx.xxx.xxx)"으로 바뀔때 어찌나 기쁘던지...

해결법(google and copy and paste):
sudo apt-get remove mdadm
sudo apt-get install sysv-rc-conf
sudo sysv-rc-conf # Press space to "uncheck" each item on the mdadm and mdadm-radi lines)
sudo apt-get remove grub
sudo apt-get install grub
sudo update-grub
sudo dpkg --configure -a

참고:https://bugs.launchpad.net/ubuntu/+source/initramfs-tools/+bug/98911
1 ··· 22 23 24 25 26 27 28 ··· 31 
분류 전체보기 (306)
잡담 (20)
함수형 언어 (65)
emacs (16)
java (18)
tips & tricks (154)
사랑 (1)
가사 (0)
독서 (4)
mobile (6)
비함수형 언어 (2)

공지사항

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

04-26 12:04