본문으로 건너뛰기

[Grafana Loki] batchDecoratorReader에서 읽기 에러 시 패닉을 방지하는 수정

PR 링크: grafana/loki#20787 상태: Merged | 변경: +18 / -15

들어가며

Grafana Loki의 pkg/dataobj/sections/pointers 패키지에서 레코드 배치를 읽을 때 스트림 라벨 이름 컬럼을 추가하는 데코레이터가 있습니다. 이 데코레이터는 내부 리더에서 배치를 읽은 후 추가 컬럼을 붙이는데, non-EOF 에러가 발생하면 데코레이션 로직을 건너뛰고 원본 배치를 바로 반환했습니다. 그런데 외부 리더는 데코레이터의 스키마(추가 컬럼 포함)에 맞는 배치를 기대하므로 스키마 불일치로 패닉이 발생합니다.

핵심 코드 분석

Before: non-EOF 에러 시 데코레이션 건너뛰기

func (d *recordBatchLabelDecorator) Read(ctx context.Context,
    alloc *memoryv2.Allocator, batchSize int) (*columnarv2.RecordBatch, error) {

    rb, err := d.inner.Read(ctx, alloc, batchSize)
    if err != nil && !errors.Is(err, io.EOF) {
        return rb, err  // 데코레이션 없이 반환 -> 스키마 불일치 -> 패닉
    }

    if d.streamIDColumnIndex == -1 {
        return rb, err
    }
    // 데코레이션 로직...
}

After: 항상 데코레이션 적용 + nil 체크

func (d *recordBatchLabelDecorator) read(ctx context.Context,
    alloc *memoryv2.Allocator, batchSize int) (*columnarv2.RecordBatch, error) {

    rb, err := d.inner.Read(ctx, alloc, batchSize)
    // 에러가 있더라도 rb가 nil이 아니면 데코레이션을 적용해야 함

    if d.streamIDColumnIndex == -1 || rb == nil {
        return rb, err
    }
    // 데코레이션 로직...
    // err은 호출자에게 그대로 전달
}

추가로 모든 메서드를 private(소문자)로 변경하여 내부 인터페이스임을 명확히 했습니다.

왜 이게 좋은가

  • 패닉 방지: 에러가 있더라도 유효한 레코드 배치가 있으면 데코레이션을 적용하여 스키마 일관성을 유지합니다.
  • io.EOF 의존 제거: EOF 여부와 관계없이 rb == nil 체크로 안전하게 처리합니다.
  • 에러 전파 유지: 에러는 사라지지 않고 호출자에게 그대로 전달됩니다. 데코레이션은 데이터가 있을 때만 적용됩니다.
  • 캡슐화 강화: 메서드를 private으로 변경하여 외부에서 직접 호출하는 것을 방지합니다.

참고 자료

댓글

관련 포스트

PR Analysis 의 다른글