Статьи

Обнаружение (запись) сбоев при использовании отображенных в память файлов в Java

Файлы, отображаемые в память, являются хорошим и часто игнорируемым инструментом. Я не буду вдаваться в подробности о том, как они работают (используйте сила Гугл Люк!), Но я быстро подытожу их достоинства

  • ленивая загрузка и запись в кеш, предоставляемые операционной системой (вам не нужно писать свою собственную, и можно с уверенностью сказать, что операционная система работает хорошо)
  • легкое чтение сложных двоичных данных (например, таких, в которых закодированы все виды относительных смещений)
  • может использоваться в качестве очень высокопроизводительного механизма IPC
  • записывается на диск, даже если ваш процесс падает (если ОС выживает)
  • очень высокая скорость записи, потому что вы не блокируете (асинхронный сброс обеспечивается ОС), и вам не нужно входить в режим ядра

Однако при всей этой асинхронности мне было интересно: что произойдет в случае отказа диска? Как ОС может уведомить ваш процесс о том, что ей не удалось записать на диск то, что вы записали в память?

Немного поиска нашел ответы:

  • Под Linux ваш процесс получает SIGBUS, когда ОС пытается записать память обратно на диск, но не удается
  • Под Windows вы получите ошибку EXCEPTION_IN_PAGE_ERROR при следующем вызове функции ОС для дескриптора файла

Желая подтвердить информацию, я запустил программу быстрого тестирования , подключил жертвенный USB-накопитель к своему ноутбуку и сделал пару тестов. Выводы:

  • Конечно же, Linux генерирует SIGBUS, а у Java (OpenJDK 1.7.0_51-b00) нет обработчика, что приводит к сбою процесса:
    1
    2
    3
    4
    5
    6
    7
    8
    # A fatal error has been detected by the Java Runtime Environment:
    #
    #  SIGBUS (0x7) at pc=0x00007f9bb5042396, pid=26654, tid=140306951444224
    #
    # JRE version: OpenJDK Runtime Environment (7.0_51) (build 1.7.0_51-b00)
    # Java VM: OpenJDK 64-Bit Server VM (24.45-b08 mixed mode linux-amd64 compressed oops)
    # Problematic frame:
    # v  ~StubRoutines::jlong_disjoint_arraycopy

    С другой стороны, вы знаете , что что-то пошло ужасно неправильно, так как ваш процесс перестал быть. С другой стороны, вы можете не сразу (если вы не читали этот пост)

  • Linux также может генерировать более «традиционные» ошибки, если вы попытаетесь очистить файл, например:
    1
    2
    3
    4
    5
    Exception in thread "main" java.io.IOException: Input/output error
        at sun.nio.ch.FileDispatcherImpl.force0(Native Method)
        at sun.nio.ch.FileDispatcherImpl.force(FileDispatcherImpl.java:76)
        at sun.nio.ch.FileChannelImpl.force(FileChannelImpl.java:376)
        at Main.main(Main.java:84)
  • Windows генерирует исключения только при повторной работе с файловым дескриптором (например, путем его сброса — как в Linux — но также и при создании новых отображений — чего-то, чего не было в Linux):
    1
    2
    3
    4
    5
    6
    Exception in thread "main" java.io.IOException: The volume for a file has been externally altered so that the opened file is no longer valid
            at sun.nio.ch.FileDispatcherImpl.size0(Native Method)
            at sun.nio.ch.FileDispatcherImpl.size(FileDispatcherImpl.java:96)
            at sun.nio.ch.FileChannelImpl.size(FileChannelImpl.java:307)
            at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:849)
            at Main.main(Main.java:64)

Вывод: файлы с отображением в памяти великолепны — как очень острый нож — это здорово: с ними можно очень быстро делать отличные вещи, но они также могут порезать вам палец. Если вы хотите использовать отображенные в память файлы из-за преимуществ, которые они предлагают:

  • быть готовым к краху. Иметь план, когда это произойдет (горячий резерв, теплый резерв, ничего не делать — все это допустимые варианты, но решите заранее)
  • если вы хотите быть уверены, что данные находятся на диске, очистите их . Когда это вернется, вы можете (почти) быть уверены, что данные находятся на диске (мы не попадем в удивительный мир дисковых / контроллеров кэшей или виртуализированных серверов здесь).