[CBRD-26537] supports an API that collects OOS OIDs from heap RECDES, even without class_repr#6829
Conversation
|
/run sql medium shell |
|
/run sql medium shell |
|
Last reviewed commit: 51087f5 |
|
/run sql medium shell |
|
Last reviewed commit: 3ec5830 |
|
모든 greptile 피드백 반영 완료했습니다. |
|
/run medium sql |
|
Last reviewed commit: a921293 |
|
Last reviewed commit: 8101801 |
|
/run sql medium |
|
/run sql medium |
|
Last reviewed commit: 8674481 |
|
8674481 커밋에서 test_sql, test_medium 통과 |
|
/run shell |
| return ER_OUT_OF_VIRTUAL_MEMORY; | ||
| } | ||
| offset = or_get_offset_internal (buf, &rc, offset_size); | ||
| offset = OR_GET_VAR_LENGTH (or_get_offset_internal (buf, &rc, offset_size)); |
There was a problem hiding this comment.
- offset을 구할 때 OR_GET_VAR_LENGTH 매크로 사용은 어색합니다. or_get_offset_internal() 함수에서 ~OR_VAR_FALG_MASK 처리를 해주는게 어떨까요?
- offset 연산 시 OR_VAR_FALG_MASK 처리가 필요해 짐에 따라서 다른 offset 함수들을 정리해주는게 어떨까요? or_get_big_var_offset(), or_get_offset() 등 사용되지 않는 함수들을 제거 -> or_get_offset_internal()를 or_get_offset() 함수로 랩핑하고, 외부에서는 or_get_offset()를 사용
There was a problem hiding this comment.
반영했습니다.
or_get_offset_internal()내부에서~OR_VAR_FLAG_MASK처리하도록 변경하고, 모든 caller에서OR_GET_VAR_LENGTH()래핑 제거했습니다.OR_GET_OFFSET_INTERNAL매크로도 동일하게 적용.or_get_big_var_offset(),or_get_offset()(get 계열) — caller가 없어 삭제했습니다.or_put_offset()은transform_cl.c에서 많이 사용 중이라 유지했습니다.
|
/run sql medium |
|
Last reviewed commit: 020d7f4 |
| #define OR_GET_VAR_FLAG(length) ((int) (length) & OR_VAR_FALG_MASK) | ||
| #define OR_GET_VAR_LENGTH(length) ((int) (length) & (~OR_VAR_FALG_MASK)) | ||
| #define OR_GET_VAR_FLAG(length) ((int) (length) & OR_VAR_FLAG_MASK) | ||
| #define OR_GET_VAR_LENGTH(length) ((int) (length) & (~OR_VAR_FLAG_MASK)) |
There was a problem hiding this comment.
| #define OR_GET_VAR_LENGTH(length) ((int) (length) & (~OR_VAR_FLAG_MASK)) | |
| #define OR_GET_VAR_OFFSET(length) ((int) (length) & (~OR_VAR_FLAG_MASK)) |
|
/run sql medium |
|
Last reviewed commit: "review(or): OR_GET_V..." |
| oos_debug ("there exists an OOS with OID %hd|%d|%hd at offset %d index %d", OID_AS_ARGS (&oid), offset, | ||
| index); |
There was a problem hiding this comment.
디버그 로그에서
offset이 플래그 포함 원시값으로 기록됨
offset 변수는 OR_GET_BYTE/SHORT/INT로 읽은 원시 VOT 엔트리 값으로, OR_VAR_BIT_OOS (0x1) 및 OR_VAR_BIT_LAST_ELEMENT (0x2) 플래그 비트가 포함된 상태입니다. 이 값을 그대로 "offset"으로 로깅하면 실제 바이트 오프셋과 다른 값(최대 3 차이)이 출력되어 디버깅 시 혼란을 줄 수 있습니다.
예: offset = 0x401이면 실제 오프셋은 0x400이지만 로그에는 0x401로 찍힙니다.
OR_GET_VAR_OFFSET(offset)을 사용하거나 oid_ptr - recdes->data로 실제 오프셋을 출력하는 것을 권장합니다:
| oos_debug ("there exists an OOS with OID %hd|%d|%hd at offset %d index %d", OID_AS_ARGS (&oid), offset, | |
| index); | |
| oos_debug ("there exists an OOS with OID %hd|%d|%hd at offset %d index %d", OID_AS_ARGS (&oid), | |
| OR_GET_VAR_OFFSET (offset), index); |
| { | ||
| assert (false && "OID read would exceed record bounds"); | ||
| return ER_FAILED; | ||
| } | ||
| OR_BUF buf; | ||
| or_init (&buf, (char *) oid_ptr, OR_OID_SIZE); | ||
| int err = or_get_oid (&buf, &oid); | ||
| if (err != NO_ERROR) | ||
| { | ||
| assert (false && "or_get_oid failed unexpectedly"); | ||
| return ER_FAILED; | ||
| } | ||
| if (OID_ISNULL (&oid)) | ||
| { | ||
| assert (false && "OID read from OOS slot is null — corrupted record?"); | ||
| return ER_FAILED; | ||
| } | ||
| oos_debug ("there exists an OOS with OID %hd|%d|%hd at offset %d index %d", OID_AS_ARGS (&oid), offset, | ||
| index); | ||
| oos_oids.emplace_back (oid); |
There was a problem hiding this comment.
에러 반환 시
oos_oids가 부분 채워진 상태로 남음
oos_oids.clear()는 함수 진입 시 한 번만 호출됩니다. 이후 루프 중간에 ER_FAILED를 반환하는 경우(예: 27717, 27725, 27729행의 경계 초과·or_get_oid 실패·null OID 검출), 이미 emplace_back된 OID들이 oos_oids에 남아있는 채로 반환됩니다.
현재는 호출자가 반환값을 항상 확인한다고 가정하지만, 향후 실수로 반환값을 무시하는 코드가 생기면 부분 OID 목록이 조용히 사용될 수 있습니다. DBMS 커널에서 복제·로깅 경로에 잘못된 OID 목록이 전달되면 데이터 불일치 위험이 있습니다.
에러 반환 직전에 oos_oids.clear()를 호출하여 호출자에게 안전한 상태를 보장하는 것을 권장합니다:
if (oid_ptr + OR_OID_SIZE > (char *) recdes->data + recdes->length)
{
assert (false && "OID read would exceed record bounds");
oos_oids.clear ();
return ER_FAILED;
}
// ... (or_get_oid, OID_ISNULL 에러 경로도 동일하게 처리)|
✅ TC Branch Finalized for Engine PR was merged. Cleanup Results: TC develop branch is ready for the next PR. |
|
✅ TC Branch Finalized for Engine PR was merged. Cleanup Results: TC develop branch is ready for the next PR. |
http://jira.cubrid.org/browse/CBRD-26537
Purpose
RECDES만으로 OOS OID 목록을 조회할 수 있는 API(heap_recdes_get_oos_oids)를 추가한다.기존에는 OOS OID를 읽기 위해
attrinfo(즉,classrepr)가 반드시 필요했다.attrinfo없이 rawRECDES만 다루는 로깅·복제 경로에서는 이 정보를 얻기 어렵기 때문에,RECDES만으로도 가변 오프셋 테이블의 끝을 알 수 있는 방법이 필요했다.Implementation
object_representation.h에OR_VAR_BIT_LAST_ELEMENT (0x2)플래그 및 관련 매크로를 추가한다.OR_VAR_BIT_RESERVED를OR_VAR_BIT_LAST_ELEMENT로 명칭 변경.OR_SET_VAR_LAST_ELEMENT,OR_IS_LAST_ELEMENT매크로 추가.heap_attrinfo_transform_variable_to_disk에서 마지막 가변 속성을 직렬화할 때OR_SET_VAR_LAST_ELEMENT로 해당 플래그를 설정한다.attrinfo->num_values를 몰라도 가변 오프셋 테이블의 끝을 판단할 수 있다.heap_recdes_get_oos_oids(const RECDES *)함수를 새로 추가한다.RECDES의 MVCC 헤더에OR_MVCC_FLAG_HAS_OOS가 없으면 빈 벡터를 반환한다.OR_IS_OOS플래그가 있는 엔트리에서 OID를 읽어 벡터에 추가한다.OR_IS_LAST_ELEMENT플래그를 만나면 순회를 종료하고 수집된 OID 목록을 반환한다.Remarks
검증
위와 같은 테스트를 통과해야 한다.
결과