Read Stream Mode

  • Read stream mode 매번 buffer 를 하나씩 읽어들이는 것이 아닌, access pattern 을 지정해주면 그것에 따라 buffer 들을 prefetch 해주는 read mode 이다.
  • 그리고 이에 대한 context 를 제공해주는 자료구조가 struct ReadStream 이다.
  • 여기서 access pattern 은 직접 지정해줄 수도 있고 (callback), sequential scan 을 자동으로 detect 하기도 한다.
  • 한번에 몇개나 읽어들일지 (distance) 에 대해서는 다음의 상황에 따라 adaptive 하게 지정된다:
    • (A) 만약에 이전에 요청한 것들이 이미 buffer 로 모두 올라왔다면, 하나만 읽어들인다.
    • (B) 만약에 이전에 요청한 것들이 buffer 로 올라오는 중이고 fadvice 는 사용하지 못한다면, 읽어들이는 개수를 2배 증가시킨다. 다만, 이때는 설정값 (io_combine_limit) 보다 커질 수는 없다.
    • (C) 만약에 이전에 요청한 것들이 buffer 로 올라오는 중이고 fadvice 도 사용할 수 있다면, 이때도 2배 증가시키되 설정값 (io_combine_limit) 보다도 커질 수 있다.
  • 즉, 위와 같은 전략으로 읽어들이는 개수가 늘어날때는 크게, 줄어드는 것은 서서히 줄어들게 할 수 있다.
    • 왜냐면 만약에 buffer 에 올라온 block 이 적을 때에는 많이 가져오도록 하고, 이미 많이 올라와 있다면 적게만 가져오게 해서 이 read stream 이 너무 많은 buffer 를 차지하지 않게 하기 위함이다.
  • 이 내용에 대한 구현인 read_stream_next_buffer() 를 같이 보면 좋다.

struct ReadStream Fields

  • 일단 아래의 그림과 같이 크게는 두개의 circular queue 로 구성된다.
    • 여기서 buf/data 는 buffer manager 의 에 있는 진짜 buffer 공간을 나타내는 것이다. 즉, ReadStream 에 대한 내용은 아니라는 것.
/**
 * For example, if the callback returns block numbers 10, 42, 43, 44, 60 in
 * successive calls, then these data structures might appear as follows:
 *
 *                          buffers buf/data       ios
 *
 *                          +----+  +-----+       +--------+
 *    (where client use) -> |    |  |     |  +----+ 42..44 | <- oldest_io_index
 *                          +----+  +-----+  |    +--------+
 *   oldest_buffer_index -> | 10 |  |  ?  |  | +--+ 60..60 |
 *                          +----+  +-----+  | |  +--------+
 *                          | 42 |  |  ?  |<-+ |  |        | <- next_io_index
 *                          +----+  +-----+    |  +--------+
 *                          | 43 |  |  ?  |    |  |        |
 *                          +----+  +-----+    |  +--------+
 *                          | 44 |  |  ?  |    |  |        |
 *                          +----+  +-----+    |  +--------+
 *                          | 60 |  |  ?  |<---+
 *                          +----+  +-----+
 *     next_buffer_index -> |    |  |     |
 *                          +----+  +-----+
 *
 * In the example, 5 buffers are pinned, and the next buffer to be streamed to
 * the client is block 10.  Block 10 was a hit and has no associated I/O, but
 * the range 42..44 requires an I/O wait before its buffers are returned, as
 * does block 60.
 */
  • buffers: Prefetch 되어서 가져오고 있거나, 아니면 이미 가져온 block 들을 저장하는 놈이다. 이때,
    • oldest_buffer_index: Circular queue head 이다.
    • next_buffer_index: Circular queue tail 이다.
    • max_pinned_buffers: Prefetch 가 완료되었거나, 아니면 진행중인 buffer 는 pinning 된다. 이때, 최대 몇개까지 pinning 할 수 있는지에 대한 정보이다.
      • 즉, 최대로 prefetch 완료 혹은 진행중일 수 있는 buffer 의 개수이다.
      • 여기서 생각할 점은 이 pin count 는 정확하게는 “read stream 이 담당하는 buffer 들을 몇개나 pinning 했냐” 이다.
      • 따라서 이 pin count 가 감소한다고 해서 실제로 buffer 에서 pin 이 빠지는 것은 아니고 “더이상 담당하지 않음” 이라고 이해하는 것이 좋다.
    • queue_size: buffer queue 의 크기이다.
      • 이 값은 max_pinned_buffers 보다 1 더 크게 설정되는데,
      • 이것은 이 queue 가 circular queue 이고 client 는 queue head 의 하나 이전 데이터로 작업을 하기 때문에 head 와 tail 간에 1 의 gap 이 필요하기 때문이다.
    • pinned_buffers: 현재 pinning 된 buffer 의 개수이다.
      • 즉, 현재 prefetch 완료 혹은 진행중일 수 있는 buffer 의 개수이자
      • 현재의 buffer queue 의 size 이다.
  • ios: 해당 prefetch 를 담당하는 IO worker 들을 저장하는 놈이다. 이때,
    • oldest_io_index: Circular queue head 이다.
    • next_io_index: Circular queue tail 이다.
    • max_ios: 최대로 운용할 수 있는 IO worker 의 개수이다.
    • ios_in_progress: 현재 운용되고 있는 IO worker 의 개수이다.
      • 즉, 현재의 ios queue 의 size 이다.
  • distance: 한번에 몇개나 갖고올 것이냐.
  • advice_enabled: fadvice 를 사용할 수 있냐에 대한 여부.
  • callback, callback_private_data: Access pattern 에 대한 정보를 제공하는 field 이다.
    • 여기서 callbackFunction pointer 로, 매번 이 함수를 호출해 다음에 접근할 bloick number 를 받아온다.
  • seq_blocknum: Sequential scan 인지 detect 하기 위해 이전 (혹은 이후) 에 접근한 block number 를 저장하는 곳이다.
  • pending_read_blocknum: 현재 IO 진행중인 block 번호.
    • 아마 scan direction 에 따라 한방향으로만 prefetch 되기 때문에, 가장 작은 (작은 번호에서 큰 수로의 방향일 경우) 값이 담기지 않나 싶다.
  • pending_read_nblocks: 현재 IO 진행중인 block 의 개수.
  • per_buffer_data_size: Queue head (oldest_buffer_index) 의 buffer data 의 크기
  • per_buffer_data: Queue head (oldest_buffer_index) 의 buffer data 를 가리키는 포인터
  • fast_path: 위에서 말한 (A) 시나리오인가에 대한 flag.
    • 즉, 모든 buffer 가 prefetch 되었으면 이 flag 가 켜지게 된다.
  • buffered_blocknum: Client 가 사용하고 있는 block 번호이다.