Skip to content

Latest commit

 

History

History
187 lines (154 loc) · 8.12 KB

File metadata and controls

187 lines (154 loc) · 8.12 KB

FlowKey — 시스템 아키텍처

1. 설계 원칙

  1. Local-first, zero-network. 모든 상태는 ~/.flowkey/ 아래에만 존재.
  2. C가 엔진이다. 핫패스(이벤트 수집 · 저널 · 매칭)는 C로, UI/플러그인은 IPC 너머의 별도 프로세스.
  3. 마이크로 최적화 가능한 자료구조부터. 캐시 라인 정렬, SPSC lock-free 링, arena/bump 할당, 인터닝, 메모리 매핑 저널, 배치 fsync.
  4. 장애 격리. observer / pattern / runner 는 동일 프로세스 내 다른 스레드 또는 별 프로세스. 한 모듈 크래시가 전체를 죽이지 않음.
  5. 결정적 재실행. 워크플로는 IR(중간 표현)로 직렬화되고, 같은 입력 → 같은 효과 → 같은 undo.

2. 프로세스 토폴로지

                ┌──────────────────────────────┐
                │           flowkeyd           │
                │  ┌────────┐   ┌───────────┐  │
   FS / App  ─▶ │  │observer│──▶│  ring(s)  │──┼──▶ journal (mmap, append-only)
   events       │  └────────┘   └─────┬─────┘  │
                │                     ▼        │
                │              ┌────────────┐  │
                │              │ pattern    │  │
                │              │ engine     │  │
                │              └─────┬──────┘  │
                │                    ▼         │
                │              ┌────────────┐  │
                │              │ workflow   │  │
                │              │ builder    │  │
                │              └─────┬──────┘  │
                │                    ▼         │
                │              ┌────────────┐  │
   IPC (UDS) ◀──┼──────────────│ runner /   │  │
                │              │ scheduler  │  │
                │              └────────────┘  │
                └──────────────────────────────┘
                          ▲
                          │  ~/.flowkey/flowkey.sock
                          │
                ┌─────────┴──────────┐
                │   flowctl  /  UI   │
                └────────────────────┘
  • observer 스레드: OS별 백엔드(macOS FSEvents → 나중에 inotify/ETW). 배압이 발생하면 이벤트는 drop with counter, 절대 차단하지 않음.
  • dispatcher 메인 루프: SPSC 링에서 이벤트를 빼서 journal에 append하고, pattern 엔진과 IPC 구독자에게 fan-out.
  • runner: 워크플로 실행. 모든 부수효과는 txn을 통해 기록.

3. 디렉터리 레이아웃

include/flowkey/        # public C 헤더
  core.h                  공통 매크로, 결과 타입
  arena.h                 bump allocator
  ring.h                  SPSC lock-free ring
  hash.h                  fast hash (wyhash-style)
  intern.h                path/string interning
  time.h                  monotonic ns
  log.h                   leveled async log
  event.h                 이벤트 타입/직렬화
  journal.h               append-only journal
  observer.h              관찰자 추상 인터페이스
  pattern.h               (stub) 패턴 엔진
  workflow.h              (stub) 워크플로 IR
  runner.h                (stub) 실행기
  ipc.h                   UDS 프로토콜

src/
  core/                   순수 C, 의존성 없음
  platform/macos/         CoreServices / AppKit 브리지
  platform/linux/         (예정) inotify, x11/wayland
  observer/               백엔드 등록 + fanout
  journal/                저널 구현
  daemon/                 flowkeyd main
  ipc/                    소켓 서버/클라이언트

cli/                      flowctl
tests/                    유닛 테스트 (단일 바이너리)
third_party/              (없음 — 의도적으로 zero-dep)

4. 코어 자료구조

4.1 Arena (bump allocator)

  • 청크 단위로 mmap 또는 malloc. 기본 64 KiB, growth 2x.
  • 정렬: 기본 16 B, 사용자가 지정 가능.
  • fk_arena_reset()는 모든 청크를 보존하고 포인터만 되돌림 → 이벤트 윈도 처리에서 GC 비용 0.

4.2 SPSC Ring

  • 단일 생산자(observer) / 단일 소비자(dispatcher).
  • 용량은 2의 거듭제곱, 마스크 비트 연산.
  • head/tail서로 다른 캐시 라인(64 B)에 배치 → false sharing 회피.
  • atomic_store_explicit(memory_order_release) / atomic_load_explicit(memory_order_acquire)만 사용. 락 없음.
  • 가득 차면 drop_count만 증가 (관측은 절대 OS를 막지 않는다).

4.3 이벤트

struct fk_event {           // 32 bytes — half cache line
    uint64_t ts_ns;         // monotonic timestamp
    uint64_t seq;           // 전역 시퀀스
    uint32_t path_id;       // interned (primary)
    uint32_t aux_id;        // interned (secondary, e.g. rename target)
    uint16_t kind;          // fk_event_kind
    uint16_t flags;
    uint32_t pid;
};

페이로드(파일 내용 등)는 절대 이 구조체에 넣지 않는다. 큰 데이터는 journal의 별도 blob 영역에 offset으로 기록.

4.4 Interning

  • 경로 문자열은 path table에 저장하고 32-bit id로 참조.
  • open-addressing 해시(load factor ≤ 0.5), wyhash.
  • 핵심 이득: 이벤트 비교 = 정수 비교, 저널 크기 감소.

4.5 Journal

  • ~/.flowkey/journal/NNNNNN.log 세그먼트, 64 MiB rotate.
  • 헤더 8 B + payload + CRC32C 4 B. 토른 라이트 감지 가능.
  • writer는 pwrite + 주기적 fdatasync (기본 250 ms 또는 64 KiB).
  • reader는 mmap(PROT_READ), 순차 scan은 prefetch hint 사용.
  • path table은 별도 paths.tab (append-only) + 메모리 캐시.

5. 이벤트 종류 (v0)

kind 의미 path_id aux_id
FS_CREATE 파일/디렉터리 생성 경로
FS_MODIFY 내용 수정 경로
FS_RENAME 이름 변경 from to
FS_DELETE 삭제 경로
APP_LAUNCH 앱 실행 bundle id
APP_EXIT 앱 종료 bundle id
WIN_FOCUS 윈도 포커스 bundle id title id
CLIPBOARD 클립보드 변경 mime id size
HOTKEY 등록된 단축키 hotkey id

6. IPC

  • Unix domain socket: ~/.flowkey/flowkey.sock (perm 0600).
  • 메시지 = u32 len | u16 type | u16 flags | bytes payload.
  • 페이로드 인코딩: v0는 사람이 읽기 쉬운 줄 기반 텍스트 (OK seq=…), v1부터 길이 접두 바이너리(MessagePack-like) 도입.

7. 안전 실행 (Runner) — 설계 노트

  • 모든 부수효과 op는 4개 함수로 정의된다: plan(ctx)dry_run(ctx)apply(ctx, txn)revert(ctx, txn).
  • txn은 journal에 op 단위로 기록되고, undo는 역순으로 revert 호출.
  • 파일 삭제는 항상 휴지통 경유. never unlink directly.
  • rename/move는 동일 볼륨이면 renamex_np 사용, 다른 볼륨이면 copy → fsync → unlink(src) 3단계 + 중단점.

8. 비기능 요구사항 (목표 수치)

항목 목표
유휴 시 CPU < 0.2% (M1, 사용자 home 관찰)
유휴 시 RSS < 25 MiB
이벤트 처리 지연 p99 < 1 ms (observer → journal append)
이벤트 손실 정상 부하 0, 폭주 시 drop count 보고
디스크 쓰기 ≤ 200 KiB/min (평균 사용자)
데몬 시작 < 50 ms (cold)

9. 비목표 (v0)

  • 윈도 좌표 / 픽셀 매크로
  • 클라우드 동기화
  • 멀티 유저
  • iOS / mobile

10. 의존성 정책

  • 표준 C11 + POSIX + 플랫폼 프레임워크만.
  • 외부 라이브러리 추가는 PR에서 정당화 필요(third_party/ 명시).
  • 빌드는 clang + make만으로 가능.