2012-10-09 1 views
1

갑자기 모든 청크가 약 4050 바이트 (특히 4050, 4051 및 4074 바이트)의 순서로 잘 리게되면 약 10b에서 16,000b의 청크로 파일을 작성합니다. 이것은 후속 쓰기가 작성해야 할 데이터를 덮어 쓰며 내 데이터를 엉망으로 만들 것이라는 의미입니다. 4050b 미만의 모든 청크는 잘 작성됩니다.어떤 상황에서 c의 write() - 함수가 요청한 것보다 적은 양의 데이터를 쓸 수 있습니까?

불행히도, 나는 그것을 재현 할 수 없습니다. 내가 가지고있는 것은 망가진 파일이다. 그래서 나는 이것을 일으킬만한 것을 찾기 위해 디버깅을하고있다.

디버깅을하면 c 코드의 write() 함수가 자바 코드 FileChannel.write()라고 불리는 것을 알 수 있습니다. 그러나 표준 라이브러리는 c의 쓰기를 호출하고 0보다 큰 바이트 만 검사합니다. 그것을위한 문서는 그것이 요구 된 모든 데이터를 쓸 것이라고 보장하지 않으며 단지 얼마나 많은 양이 쓰여 졌는지를 알려줄 것입니다.

Java 토지에서 다시 쓰여진 바이트는 확인하지 않습니다.하지만 함수 서명은 거의 똑같습니다. 따라서 수정 사항이 간단합니다. 그러나, 나는 이것을 재현 할 수 없기 때문에, 나는 실제 문제를 고쳤다는 것을 모른다. 그래서 나는 어떤 C 전문가가 내가 담배를 피우고 있다고 말하거나 write()가 한 번에 약 4050 바이트 이상을 쓸 수없는 합법적 인 상황이 있음을 알려주기를 바라고있다.

이 버전은 64 비트 Linux 커널 버전 3.0.0-26에서 실행됩니다.

편집 : 아래의 의견에 따라 확장하려면 : 나는 정상적인 파일 시스템 파일에 쓰고 있어요

. 나는이 컨텍스트에서 비 차단 의미가 무엇인지 모르겠다. 콜백이나 다른 것을 사용하지는 않지만, 명시 적으로 디스크에 플러시하도록 OS에 지시하는 것은 각 청크에 대해 수행되지 않는다. 파일은 Java의 RandomAccessFile, 'rw'모드를 사용하여 열립니다.

+0

재생산 할 수 없다는 것은 무엇을 의미합니까? 문제가 더 이상 발생하지 않습니까? –

+0

쓰고있는 위치와 대상 파일 설명자가 비 차단 모드에있을 가능성에 대한 자세한 내용을 추가 할 수 있습니까? – bobah

+0

코드가 Java 인 경우 Java API의 동작에 대해 물어야합니다. 예를 들어,'java.io.BufferedOutputStream.write()'를 사용하고 있다면, 데이터의 전체 양이 적어도 버퍼에 쓰여질 것이다 - 당신은'flush()'또는'close()'를 할 필요가있다. 버퍼가 기입 해졌는지 어떠했는지), 예외가 Throw됩니다. 이 사양은 기본 시스템 호출이 작동하는 방식과 관계가 없습니다. –

답변

5

:

ulimit -Sf 
ulimit -Hf 

또는이 C 프로그램을 사용하여 : :

이러한 제한은 다음 명령을 사용하여 볼 수 있습니다

RLIMIT_FSIZE 
      The maximum size of files that the process may create. Attempts 
      to extend a file beyond this limit result in delivery of a 
      SIGXFSZ signal. By default, this signal terminates a process, 
      but a process can catch this signal instead, in which case the 
      relevant system call (e.g., write(2), truncate(2)) fails with 
      the error EFBIG. 

:

The number of bytes written may be less than count if, for example, 
    there is insufficient space on the underlying physical medium, or the 
    RLIMIT_FSIZE resource limit is encountered (see setrlimit(2)), or the 
    call was interrupted by a signal handler after having written less than 
    count bytes. (See also pipe(7).) 

man 2 setrlimit에서리눅스 프로그래머 매뉴얼에서

#include <stdio.h> 
#include <errno.h> 
#include <sys/resource.h> 

int main() 
{ 
    struct rlimit rl; 
    if (getrlimit(RLIMIT_FSIZE, &rl) == 0) { 
     printf("%d %d\n", rl.rlim_cur, rl.rlim_max); 
    } else { 
     fprintf(stderr, "error: %d\n", errno); 
    } 
    return 0; 
} 
+0

이것은 이것이 원인이라는 것을 암시하지만 예제에 따라 4050 바이트 씩 동작을 설명하지는 않습니다. 디스크 공간이라면, 쓰는 것을 멈추어야합니다. 맞습니까? – jakewins

+1

@ jakewins, 신호 처리기는 언제든지 시작할 수 있습니다. 이 사실을 알기 시작한 버퍼 크기는 소프트 및 하드웨어 조합으로 쓰기가 충분히 자주 중단되는 지점에 불과합니다. 'write' 호출을 적절하게 사용하면이 모든 것이 문제가되지 않습니다. 반환 값 (그리고 결국'errno')를 확인하고 모든 것을 기록 할 때까지 반복하십시오. 그렇지 않으면 그런 식으로 일해야합니다. –

+0

동의하고 코드를 확실히 수정할 것입니다. 그러나 4050 바이트 이후에 끊어지는 명백한 패턴이 궁금합니다. 거기에 쓰여진 금액을 집어 들고 이후에 트리거하는 신호 처리기가있을 수 있습니까? 이 숫자는 정확히 4050이 아니며 매회마다 조금씩 다를 수 있기 때문에 일종의 경쟁 조건 인 것으로 보입니다. – jakewins

3

문제를 재현하는 가장 간단한 방법은 느린 소비자를 사용하는 것입니다. 이렇게하면 write()를 호출 할 때 송신 버퍼가 거의 가득 차게되어 사용자가 지정한 모든 데이터를 쓸 수있는 것은 아닙니다. 이 문제를보다 분명하게하기 위해 송신 및 수신 버퍼 크기를 줄일 수 있습니다. man 2 write에서

4

쓰기에 (1) : 기록이 얼마나

은 당신이 쓰는에 따라 달라집니다 "쓰기() ... 파일에 최대에 카운트 바이트를 쓴다" 동기 쓰기 사용 여부에 따라 달라집니다.

예. 그것이 파이프 소켓이라면 파이프/소켓 버퍼를 가득 채울 수 없습니다 (동기 모드에서는 버퍼에서 사용할 수있는 것보다 많음).

+0

이 점에 대한 그 점을 지적 - 나는 디스크에 정상적인 파일을 쓰고 있는데, OS가 갑자기 4050 바이트 정도의 버퍼에 파일에 쓴다 고 할 수 있습니까? – jakewins

관련 문제