Skip to content

expiretime 동작 방식

Minkyeong Kim edited this page Jan 18, 2024 · 14 revisions

ASCII 형태로 전달받은 exptime에 대한 서버의 동작 방식

  1. ASCII 문자열 형태의 exptime 수신

  2. 해당 exptime 문자열을 long(64bit 정수형)타입으로 읽은 후 int32_t(부호가 있는 32bit 정수형)으로 형변환

    • long을 더 작은 크기의 int32_t로 변환 → 상위 32bit의 데이터가 손실됨 (invalid data)

      클라이언트가 long 을 사용하여 32bit 정수형을 초과하는 값을 전송하면, 제대로 된 동작이 불가.

    • 서버에서 이를 처리하는 코드(safe_strtol)

      bool safe_strtol(const char *str, int32_t *out) {
          assert(out != NULL);
          errno = 0;
          *out = 0;
          char *endptr;
          long l = strtol(str, &endptr, 10); // ASCII 문자열을 long 형태로 변환
          if (errno == ERANGE)
              return false;
          if (isspace(*endptr) || (*endptr == '\0' && endptr != str)) {
              *out = l; // long 형태로 변환된 값을 int32_t 변수에 다시 넣음
              return true;
          }
          return false;
      }
  3. int32_t 타입의 exptime을 언제 만료되어야 하는지에 대한 상대적인 값으로 변환 후 캐시에 저장

    • 캐시 서버는 아래의 두 가지 시간 변수를 설정

      • 구동 시간 : process_started
        • 자료형 : time_t (long)
        • 서버가 구동 시작한 시점의 unix 시간 저장
      • 현재 시간 : current_time
        • 자료형 : rel_time_t (uint32_t)
        • 서버가 구동 후부터 현재까지 흐른 시간(초) 을 보관
        • libevent의 timer event 이용하여 매 1초마다 현재의 unix 시간에서 process_started 뺀 값을 저장
    • 위의 두 변수를 통해 아래의 방식으로 exptime을 상대값으로 변환하여 저장

      • exptime > 30days (클라이언트가 unix 시간 형태의 exptime을 설정한 경우)

        • 입력받은 exptime에서 process_started 뺀 값을 저장

        • example :

          클라이언트가 전송한 exptime = 1577805000

          서버의 process_started = 1577804300

          → 캐시에 저장되는 exptime = 700 (1577805000 - 1577804300)

      • exptime ≤ 30days (클라이언트가 몇 초 후에 만료될 지의 exptime을 설정한 경우)

        • 입력받은 exptime에서 current_time 합한 값을 저장

        • example :

          클라이언트가 전송한 exptime = 600

          서버의 current_time = 100

          → 캐시에 저장되는 exptime = 700 (600 + 100)

    • 두 경우 모두 서버 기준으로 만료되는 시간이 계산되며, 부호없는 32bit 정수형(uint32_t)으로 저장

      • 캐시에 저장하는 값이 unix 시간 자체가 아닌 서버 구동 시간에 따른 상대적인 값

        → 32bit unix 시간에서 생기는 2038년 문제에 영향을 받지 않음

      • 서버 구동 시간(process_started)보다 uint32_t 의 최대값인 4294967295초(약 136년)보다 큰 값의 시간이 아니라면 캐시에 저장되는 자료형은 uint32_t 를 사용해도 문제가 없음

    • 서버에서 이를 처리하는 코드(realtime)

      static rel_time_t realtime(const time_t exptime)
      {
          if (exptime == 0) return 0;
          if (exptime < 0) {
      #ifdef ENABLE_STICKY_ITEM
              if (exptime == -1) return (rel_time_t)(-1);
      #endif
              return (rel_time_t)1;
          }
          if (exptime > REALTIME_MAXDELTA) {
              // 30일을 초과할 때
              if (exptime <= process_started)
                  return (rel_time_t)1;
      	// 입력받은 exptime(unix time)에서 서버가 구동 시작한 값을 뺌.
              return (rel_time_t)(exptime - process_started);
          } else {                           
              // 30일 이하일 때
      	// 입력받은 exptime에서 서버가 구동 이후 현재까지 흐른 시간을 더함.
              return (rel_time_t)(exptime + current_time);
          }
      }

서버의 exptime 처리 방식에 대해 필요한 자료형 변경점

  • 클라이언트로부터 값을 전달받는 변수의 자료형은 64bit 정수형으로 변경 필요
  • 캐시에 저장되는 자료형은 32bit 정수형을 그대로 사용해도 무방

저장된 exptime 을 다시 활용하는 경우

  • invalid item 검사 : current_time (현재 시간)이 cache item에 저장된 exptime을 초과했는지 여부에 따라 판별
  • getattr 명령 : 저장된 exptime에서 다시 current_time 을 빼서 앞으로 몇 초 후에 만료가 되는지 출력
    • 서버에서 이를 처리하는 코드(human_readable_time)

      static rel_time_t human_readable_time(const rel_time_t exptime)
      {
          if (exptime == 0) {
              return exptime;
      #ifdef ENABLE_STICKY_ITEM
          } else if (exptime == (rel_time_t)-1) {
              return exptime;
      #endif
          } else {
              if (exptime <= current_time) {
                  return (rel_time_t)-2;
              } else {
                  return exptime - current_time;
              }
          }
      }

클라이언트에서의 exptime에 대한 int 자료형 변경에 대한 검토

  • 서버에서 사용하는 프로그래밍 언어는 C → 정수 자료형에 대하여 부호 유무 결정이 가능
  • 클라이언트에서 사용하는 프로그래밍 언어는 Java, C++ → Java는 무조건 부호가 있는 정수 자료형만 가능
    • 서버의 시간 계산은 uint32_t 로 부호가 없기에 Java의 int 와 호환이 안될 가능성이 있음.
    • 예를 들어, 계산 결과가 2147483648초(약 68년)를 초과할 때, Java에서는 음수로 인식되어 잘못된 연산을 가져올 수 있음

→ Java 클라이언트에서 서버와 송수신하는 시간 관련 변수들의 자료형을 모두 Long 타입으로 변경이 필요함.