1 minute read

Org-roam으로 관리하는 노드 개수가 늘면서 언제부턴가 노드를 검색하는 org-roam-node-find 함수와 노드를 삽입하는 org-roam-node-insert 함수가 느려지고 있다. 여기서 org-roam은 Emacs에 구현한 개인 지식 관리 모드다. Emacs 맛 Obsidian이라고 생각하면 된다.

(length (org-roam-node-list))
;;=> 5334

노드(노트) 개수가 5,000개가 넘어가고 있다. 이걸 다 SQLite에서 로드하고 가공하고 보여주느라 느리다. 비동기 로딩으로 푸는 방법도 있을 것 같지만 코드를 읽고 문제를 해결할 여유는 없다. 나와 비슷한 고민을 하고 임시 해결책을 제시한 ’Org-roam slows down as nodes increase.. solution? - reddit.com’ 글을 찾았다.

임시 해결책이 훌륭하다. Emacs 함수 메모이제이션(Memoization)을 지원하는 skeeto/emacs-memoize 패키지를 사용하는 방법이다. org-roam-node-find 함수와 org-roam-node-insert 함수가 공통으로 사용하는 성능 병목 지점인 org-roam-node-read--completions 함수를 메모이제이션하는 방법을 알려준다. 활용도가 높은 임시 해결책이다. 훌륭하다.

세팅 코드는 Doom Emacs를 기준이다.

packages.el 파일에 skeeto/emacs-memoize 패키지를 받을 수 있게 추가한다.

(package! memoize)

default-sort 를 꺼서 시간을 조금이라도 더 아낀다.

(after! org-roam
  (setq org-roam-node-default-sort nil))

메모이제이션은 10분 기준이다. 메모이제이션을 강제로 리셋할 수 있는 함수를 SPC n r c 키에 바인딩했다. 노드를 추가하거나 이름을 바꿨을 때, 10분을 기다리는 건 너무 가혹하다.

(after! org-roam
  (require 'memoize)

  (memoize 'org-roam-node-read--completions "10 minute")

  (defun memoize-force-update (func &optional timeout)
    (when (get func :memoize-original-function)
      (progn (memoize-restore func)
             (memoize func timeout))))

  (defun my/force-update-org-roam-node-read-if-memoized (&optional timeout)
    (interactive)
    (memoize-force-update 'org-roam-node-read--completions
                          (if timeout timeout memoize-default-timeout)))

  (run-with-idle-timer 60 t #'my/force-update-org-roam-node-read-if-memoized)

  (map! :leader
        (:prefix-map ("n" . "notes")
                     (:prefix ("r" . "roam")
                      :desc "Clear memoization" "c"
                      #'my/force-update-org-roam-node-read-if-memoized))))

엄청 쾌적해졌다. 게다가 Emacs에서 메모이제이션을 사용하는 방법도 배웠다.

링크

C-x C-s C-x C-c