장애 정보
| 장애 번호 | 701515a |
| 현상 | 1. DEDUPLICATE LOB 컬럼에서 두 행이 같은 내용을 공유할 때, 한 행의 LOB 컬럼을 TRIM(0)해도 해당 행의 LOB 컬럼이 갱신되지 않아 길이가 0이 되지 않고 공유 데이터를 그대로 참조한다. 이후 해당 행을 DELETE하면 다른 행이 참조하고 있는 데이터가 회수되어 내용이 손상된다. 2. DEDUPLICATE LOB의 공유 참조가 0이 되어 dedup 상태가 해제된 후(TRIM 등), 해당 행에 다시 WRITEAPPEND를 수행하면 "Row containing LOB column is not locked"(TBR-26007) 오류가 발생하여 영구히 쓰기 불가능해진다. 3. 암호화(ENCRYPT) LOB의 아직 할당되지 않은 페이지에 offset이 0이 아닌 값으로 데이터를 쓰면, 데이터가 지정된 위치가 아닌 블록의 맨 앞에 기록되고 지정된 위치는 공백으로 남는다. 순차적인 append 작업에서는 이 현상이 드러나지 않는다. 4. 압축(COMPRESS) LOB의 압축 단위(CU) 번호가 16비트 제한으로 인해 65,536개를 초과하면 번호가 겹쳐 65,537번째 CU가 첫 번째 CU 위치에 기록되어 내용이 손상된다. 기본 설정 기준 약 254GB 이상에서 발생한다. 5. 압축 LOB의 길이가 정확히 CU 경계와 일치하는 상태에서 데이터를 append하면 존재하지 않는 CU를 읽으려 하여 오류로 세션이 끊긴다. 6. 데이터가 행 안에 저장된(in-row) 압축 LOB을 TRIM하면 LOB 세그먼트에 없는 CU를 정리하려 하여 서버 내부 오류로 세션이 끊긴다. 빈 LOB에 TRIM(0)을 수행해도 동일한 경로로 오류가 발생한다. 7. LOB 쓰기 시 길이 상한 검사가 매우 큰 offset(2^64 부근 또는 약 35TB 구간)을 통과시켜 오류를 거부하지 않고, 절단된 페이지 번호까지 포함하여 빈 블록을 채우는 대량 쓰기가 발생한다. 8. 압축 LOB에 PSM(DBMS_LOB.WRITEAPPEND)을 사용하여 같은 변수에 연속으로 2회 이상 데이터를 이어 쓰면, 두 번째 호출에서 길이를 0으로 보고 offset 0에 쓰려다 서버 내부 오류로 세션이 끊긴다. 이 현상은 신규 LOB 생성 시와 재오픈한 in-row LOB 모두에서 발생한다. |
| 원인 | 1. DEDUPLICATE LOB을 길이 0으로 TRIM하면 빈 LOB으로 바뀌는데, 빈 LOB은 행 갱신 대상에서 제외되어 행이 공유 데이터를 계속 가리킨 채 참조 수만 줄어든다. 2. DEDUPLICATE LOB의 공유 참조가 0이 되어 dedup이 풀릴 때 행의 LOB 컬럼이 갱신되지 않아 dedup 표시가 남고, 이후 write가 상태 불일치로 실패한다. 3. 암호화 LOB을 새 블록에 기록할 때 블록 안의 시작 위치(offset)를 무시하고 항상 블록 맨 앞에 복사한다. 4. 압축 단위(CU) 번호를 16비트로 다뤄 65,536개를 넘으면 번호가 다시 0부터 시작한다. 5. 길이가 CU 경계와 정확히 같을 때 append하면, 아직 기록되지 않은 다음 CU를 기존 데이터로 보고 읽으려 한다. 6. 행 안에 저장된(in-row) 압축 LOB은 LOB 세그먼트에 CU가 없는데, TRIM이 이를 확인하지 않고 세그먼트의 CU를 정리하려 한다. 7. write 길이 상한 검사를 offset + 길이의 덧셈으로 하여 매우 큰 값에서 합이 넘쳐(overflow) 검사를 통과하고, 상한 자체도 실제 저장 가능한 크기보다 크게 잡혀 있다. 8. 압축 LOB의 길이 조회가 디스크에 기록된 길이만 돌려주고 압축 버퍼에 남은 데이터를 빼서, 두 번째 WRITEAPPEND가 길이를 0으로 보고 처음 위치에 쓰려 한다. |
| 해결 | 1. 길이가 0인 TRIM 연산으로 빈 LOB이 생성된 경우에도 해당 행의 LOB 컬럼을 갱신한다. 2. 중복 제거 상태가 해제될 때 행의 LOB 컬럼을 갱신하여 중복 제거 표시를 제거한다. 3. 새 블록에 대해 지정한 시작 위치에 데이터를 복사한다. 4. CU 번호를 32비트로 확장한다. 5. 아직 기록되지 않은 CU는 읽지 않고 새 CU로 바로 이어 쓴다. 6. 압축 LOB의 크기가 작아 테이블 row에 저장된 경우 TRIM 연산 시 세그먼트 CU를 정리하지 않고 길이만 갱신한다. 7. 상한 검사를 넘침이 발생하지 않는 뺄셈 방식으로 변경하고, 상한 값을 실제 저장 가능한 크기로 조정한다. 8. 길이 조회 시 압축 버퍼에 남아 있는 데이터까지 포함하여 조회한다. |
| 발생시점 | 26.10.06. |
| 패치필요버전 | 6FS07PS 7FS02PS |
패치 정보
| 패치명 | FS02PS_701515a |
| 메이저 버전 | 7 |
| 마이너 버전 | FS02PS |
| 버전 제목 | Advanced LOB 개발 과정에서 발견된 LOB 오류 수정 |
| 배포가능일 | 26.11.10. |
| 호환성 | • TAC 롤링 패치: 가능 • TSC 롤링 패치: 가능 • 백업 데이터 호환: 가능 • 프로토콜 호환: 가능 • 데이터 포맷 호환: 가능 |
| AP 영향도 | • 플랜 변경 여부: 아니오 • 결과 값 변경 여부: 아니오 • SQL 문법 변경 여부: 아니오 • 시스템 오브젝트 변경 여부: 아니오 • 기존 기능 변경 여부: 아니오 |
| 파라미터 | - |
| 우회방안 | - |