Linux에서는 파일 시스템 시간이 항상 시스템 시간보다 몇 밀리초 정도 지연되는 것처럼 보이므로 매우 좁은 시간 범위(밀리초) 내에서 특정 시간 이전 또는 이후에 파일이 수정되었는지 확인하려는 경우 불일치가 발생할 수 있습니다.
나노초 해상도를 지원하는 파일 시스템이 있는 Linux 시스템(저는 256바이트 inode 및 ZFS와 함께 ext4를 사용해 보았습니다)에서 다음을 수행하려고 하면:
date +%H:%M:%S.%N; echo "hello" > test1; stat -c %y test1 | cut -d" " -f 2
두 번째 출력 값(파일 수정 시간)은 항상 첫 번째 출력 값(시스템 시간)보다 몇 밀리초 뒤쳐집니다. 예를 들면 다음과 같습니다.
17:26:42.400823099
17:26:42.395348462
반대 방향이어야 하지만 파일이 test1
수정되었기 때문에뒤쪽에date
명령을 호출하십시오 .
Python에서도 동일한 결과를 얻을 수 있습니다.
import os, time
def test():
print(time.time())
with open("test1", "w") as f:
f.write("hello")
print(os.stat("test1").st_mtime)
test()
1698255477.3125281
1698255477.3070245
왜 이런 일이 발생합니까? 이를 방지하고 시스템 시간을 파일 시스템 시간과 일치하게 만드는 방법이 있습니까? 지금까지 내가 찾은 유일한 해결 방법은 다음과 같이 더미 임시 파일을 만들고 수정 시간을 가져와서 파일 시스템 "시간"(실제로 의미하는 것이 무엇이든)을 얻는 것입니다.
def get_filesystem_time():
"""
get the current filesystem time by creating a temporary file and getting
its modification time.
"""
with tempfile.NamedTemporaryFile() as f:
return os.stat(f.name).st_mtime
하지만 더 깨끗한 해결책이 있는지 궁금합니다.
답변1
파일 타임스탬프에 사용되는 시간은 경과된 마지막 타이머이며, 이는 항상 약간 과거입니다.이 current_time
기능은inode.c
수신 전화 ktime_get_coarse_real_ts64
:
/**
* current_time - Return FS time
* @inode: inode.
*
* Return the current time truncated to the time granularity supported by
* the fs.
*
* Note that inode and inode->sb cannot be NULL.
* Otherwise, the function warns and returns time without truncation.
*/
struct timespec64 current_time(struct inode *inode)
{
struct timespec64 now;
ktime_get_coarse_real_ts64(&now);
if (unlikely(!inode->i_sb)) {
WARN(1, "current_time() called with uninitialized super_block in the inode");
return now;
}
return timestamp_truncate(now, inode);
}
후자는 다음의 일부이다다음 함수군을 기록하세요.:
이는 대략적이지 않은 버전보다 빠르지만 사용자 공간에 해당
CLOCK_MONOTONIC_COARSE
하고CLOCK_REALTIME_COARSE
사용자 공간에서 사용할 수 없는 동등한 부팅 시간/tai/원시 타임베이스에 따라 정확도가 떨어집니다.여기에 반환된 시간은 마지막 타이머 틱에 해당하며 아마도 과거 10밀리초(CONFIG_HZ=100의 경우)였으며 "jiffies" 변수를 읽는 것과 같습니다. 이러한 [함수]는 빠른 경로에서 호출될 때만 유용하며 여전히 초보다 나은 정밀도를 기대하지만 예를 들어 inode 타임스탬프의 경우 "jiffies"를 쉽게 사용할 수 없습니다. 하드웨어 클럭 액세스를 건너뛰면 신뢰할 수 있는 사이클 카운터가 있는 대부분의 최신 시스템에서 약 100 CPU 사이클이 절약되지만, 외부 클럭 소스가 있는 구형 하드웨어에서는 최대 몇 마이크로초까지 절약할 수 있습니다.
inode 타임스탬프에 대한 구체적인 언급을 참고하세요.
커널을 수정하는 것 외에는 이것을 완전히 피할 수 있는 방법이 없습니다. 증가시켜 영향을 줄일 수 있습니다 CONFIG_HZ
.최근에 이를 개선하자는 제안이 있었습니다., 어느아직 연구 중.
답변2
스티븐 키트의답변정확한 것 같습니다.
C 파일 시스템에서 사용되는 것과 동일한 "거친" 시계를 실제로 가져옴으로써 적어도 내 커널 구성에서는 이것을 꽤 잘 재현할 수 있습니다.프로그램항상 얻다두꺼운파일에 액세스하기 전의 실시간 시계는 파일의 타임스탬프를 사용하거나 (드물게) 한 시스템 시계 주기 이전의 타임스탬프를 사용합니다.
// excerpt from the program linked above, not a relicensing
// …
clock_gettime(CLOCK_REALTIME_COARSE, &now_coarse);
clock_gettime(CLOCK_REALTIME, &now);
int fd = open("temp", O_WRONLY | O_CREAT);
write(fd, data, length);
close(fd);
clock_gettime(CLOCK_REALTIME, &now_after);
stat("temp", &props);
printf("Differences relative to coarse clock before:\n"
"Fine Realtime before: %+8jd ns\n"
"File Modification Time: %+8jd ns\n"
"Realtime clock after: %+8jd ns\n",
ns_difference(&now_coarse, &now),
ns_difference(&now_coarse, &props.st_mtim),
ns_difference(&now_coarse, &now_after));
다음과 같은 것을 생산합니다
Differences relative to coarse clock before:
Fine Realtime before: +1551810 ns
File Modification Time: +0 ns
Realtime clock after: +1626199 ns
앞서 언급한 대략적인 틱 기간 델타 상황은 거의 발생하지 않으며 now_coarse
시스템 틱이 정확히 파일 획득과 수정 사이에 있을 때 발생합니다.
Differences relative to coarse clock before:
Fine Realtime before: +1497562 ns
File Modification Time: +999992 ns
Realtime clock after: +1609943 ns
그런데,통계자료이 "틱"이 발생하는 10,000개의 이벤트를 수집할 때까지 위의 작업을 수행하면 가능한 지연 범위가 매우 작다는 것을 보여줍니다.
Total processed: 777618
Observed tick progressions: 10000
Percentage: 0.013
Minimum tick delta: 999992
Maximum tick delta: 999993
Average tick delta: 999992.905900
즉, 따옴표 사이의 델타와 관련하여 타이밍이 매우 가깝습니다.