1. Куча / Говнокод #27243

    0

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    impl Drop for FileDesc {
        fn drop(&mut self) {
            // Note that errors are ignored when closing a file descriptor. The
            // reason for this is that if an error occurs we don't actually know if
            // the file descriptor was closed or not, and if we retried (for
            // something like EINTR), we might close another valid file descriptor
            // opened after we closed ours.
            let _ = unsafe { libc::close(self.fd) };
        }
    }

    https://github.com/rust-lang/rust/blob/master/library/std/src/sys/unix/fd.rs#L294
    Похуй на ошибки возврата, да? Ведь из деструктора вернуть код ошибки нельзя, а исключения... А, это ж Раст, хуй с ними с исключениями короче.
    Для ШЫНДОШЫ такая же хуйня, но тут они даже камент написать постыдились: https://github.com/rust-lang/rust/blob/master/library/std/src/sys/windows/handle.rs#L54

    Вручную скинуть буфер на диск - тоже нечем, потому что функция, которой я пользовался в сишке, тут бесполезна:
    https://github.com/rust-lang/rust/blob/master/library/std/src/sys/unix/fs.rs#L861
    https://github.com/rust-lang/rust/blob/master/library/std/src/sys/windows/fs.rs#L438

    Короче, мне тут продакшон код надо писать за зарплату, а я не знаю, как вернуть юзеру информацию о неудачном закрытии. Что делать-тоа?!

    Запостил: TarasB, 09 Февраля 2021

    Комментарии (54) RSS

    • В рот мне куриные лапы
      Ответить
    • > как вернуть юзеру информацию о неудачном закрытии

      Сделать явный close(), commit() или что там по смыслу подходит твоему коду и всегда вызывать его в конце успешной ветки. Там ты сможешь вернуть ошибку если что-то недофлашилось. А если дело до деструктора дойдёт -- забить хер на ошибку.

      Х.з. как ещё это решить.

      З.Ы. С возвращением!
      Ответить
      • libc::close(self.fd) зовётся только в этом методе. Другого способа его вызвать нету.
        Ответить
        • Лол, уже второй язык, который на close() обосрался... В джаве тоже некоторые обёртки над стримом проглатывали исключение и оставляли закоррапченный файл.
          Ответить
          • зацени лучше вот это: петухи из постгреса кукарекают что они наплодили процессов и почему-то - почему же??? - фсинк проваливается в одном, а другой об этом не знает

            https://mydbanotebook.org/post/fsync/
            https://postgrespro.com/list/thread-id/2379543

            а виновато конечно ядро, а не ебанарии, отказывающиеся мерджить поддержку int64 в 2021
            Ответить
            • > а виновато конечно ядро

              А разве нет? Там вроде глубже проблема, что рандомная прога или даже само ядро может случайно триггернуть флаш страничек твоего файла и обосраться, а потом fsync молча скажет, что всё заебись.
              Ответить
              • Насколько понимаю, внутри одного процесса такого произойти не может. Они жалуются, что форкаются и шарят дескрипторы, только вот же ведь дела, процессы-то разные.
                Ответить
                • Там вот такой паттерн получается, если я правильно понял:

                  1) Открываем файл, пишем туда, успешно закрываем обычным close()
                  2) Через какое-то время ядро в фоне флашит буфера на диск, получает ошибку записи и забивает на неё
                  3) Открываем файл, пишем туда, делаем fsync() и close()
                  4) fsync() успешен, файл в середине запорот, профит!

                  Т.е. вроде бы и косяк постгри, что файл заново переоткрыли. А с другой стороны возникает вопрос -- а не возникнет ли такая ситуация и без переоткрытия?
                  Ответить
                  • > а не возникнет ли такая ситуация и без переоткрытия

                    Ну т.е. к примеру:

                    1) Открываем файл, пишем туда, держим его открытым ещё час-другой
                    2) Через какое-то время ядро флашит буфера на диск, получает ошибку записи
                    3) Зовём fsync()

                    Есть ли гарантия, что fsync() зарепортит нам ошибку из пункта 2?
                    Ответить
                    • Since Linux 4.13, errors from write-back will be reported to all file descriptors that might have written the data which triggered the error.

                      Т.е. эту часть всё-таки пофиксили и такая гарантия есть. Если ядро свежее 2017 года.
                      Ответить
                      • > Если ядро свежее 2017 года.

                        ну мы же говорим про постгрес

                        там реально люди в каком-то 99 живут
                        Ответить
                      • Ядро куриное.
                        Ответить
                        • [color=yellow]Желток?[/color]
                          Ответить
                          • Помнится мне, как я измученный транслитом, я на уроке англиячьего прочел слово "yellow" как "уэллоу",
                            чем вызвал неодобрительный взгляд училки. Она меня еще и передразнила.
                            Ответить
                • > внутри одного процесса такого произойти не может

                  Да нихуя... Проблема, которую в ядре 4.13 фиксили, стреляла и для процессов и для тредов и даже в однопоточной хуйне. Если джва хендла работали с разными кусками одного и того же файла, то они могли зафлашить чужой кусок и обработать его ошибку. Теперь ошибку от write-back кеша получают все заинтересованные, а не только первый.

                  Постгресовая бага в общем-то тоже от тредов/процессов не зависит. Если ты файл закрыл, то потом переоткрывать его и флашить уже поздно. Ядро трекает ошибки только для открытых хендлов, на заброшенные ему похуй.
                  Ответить
                  • З.Ы. Бля, хотел попробовать, а там ядро пересобирать надо. Дефолтное не умеет ошибки записи инжектить.
                    Ответить
                  • Окей, не одного процесса, одного хендла. Я в общем не вижу почему с файлом должен работать один контекст, а ошибки за него ловить второй. По мне так это наоборот корректное поведение.
                    Ответить
                    • Ну жопа в том, что fsync() весь файл флашит, не только записанные через твой хендл куски. Т.е. чужие ошибки ты в любом случае будешь получать. Просто теперь есть гарантия, что ты свои не проебёшь из-за соседа.

                      А работать с одним файлом через несколько хендлов в разных потоках/процессах -- вполне норм для СУБД, имхо. В прыщах же один хендл не получится юзать для параллельных записей.
                      Ответить
                      • ну да, можно наДУПать себе много хендлов, и насикать их потом в нужные места
                        Ответить
                        • Надупать вроде не катит, надо именно открывать.
                          Ответить
                          • почему не катит?

                            а , всё

                            у меня тут это

                            тред не читай
                            @
                            сразу отвечай

                            случился
                            Ответить
                            • Потому что позиция общая будет. Почитай ман.
                              Ответить
                              • да, ты прав
                                if the file offset is modified by
                                using lseek(2) on one of the file descriptors, the offset is also
                                changed for the other.
                                Ответить
                  • >зафлашить чужой кусок и обработать его ошибку.
                    Есть мнение, что писать в один и тот же файл из двух разных процессов не очень хорошо.

                    Хотя конечно в СУБД ты можешь поделить между ними странички
                    Ответить
                    • теоретически процесс 1 может писать в диапазоне N .. N + X, а процесс 2 в диапазоне N + X + 1 .. N + 2X

                      но емнип постгрес как раз всё делит на постраничные файлы...
                      Ответить
                      • Да, именно так. на странички по 8К.
                        По сути это файловая система внутри файла (ну вроде тосты отдельно хранятся).

                        Потому я и сказал, что для СУБД это ОК. А в целом странно.

                        Кстати, некоторые субд (оракл, MS-SQL) умеют срать на сырые партиции вообще. Странно, что постгря так не умеет.
                        Ответить
                        • > Странно, что постгря так не умеет.

                          Да чуваки решили сэкономить на разработке. Типа в ядре должен быть хороший кеш-менеджер, зачем свой писать. Поэтому абузят файлуху в хвост и в гриву.

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

                            Хвала яхве, что хоть размер их странички кратен размеру страницы памяти
                            Ответить
            • > mydbanotebook
              - хрюкнул как myebanoebook
              Ответить
        • блядьшто

          ой, это про ВОЗВРАЩЕНИЕ, если что
          Ответить
        • Тогда можно сделать свою собственную уникальную говнообертку над close
          Ответить
    • А из деструктора исключения не зашквар ли кидать, даже если было так можно?
      Ответить
      • Зашквар конечно. Но там хотя бы терминейт будет, а не успешно записанный до середины файл.
        Ответить
    • Ну, кстати, у std::fs::File есть sync_all (аля fsync) и sync_data (аля fdatasync). И там даже в доке написано, что деструктор может молча проебсти данные, надо юзать эти sync в конце успешной ветки.
      Ответить
      • Пишут, что не надо: https://github.com/rust-lang/rust/issues/51775

        Call File::sync_data or File::sync_all if you want to do your best to ensure that all of the data has been written fully through to the disk.

        These are very expensive operations, so we don't call them automatically. Code that needs to make guarantees about data consistency should use them as necessary.
        Ответить
        • А ещё почему это библиотечный fs::write так не делает?
          https://github.com/rust-lang/rust/blob/master/library/std/src/fs.rs#L307
          Ответить
        • Пиздец у них двоемыслие, как-будто разные люди писали разные фрагменты этого кода, не общаясь друг с другом... А вытащить дескриптор и позвать close() ты не можешь т.к. они потом тоже безусловно позовут в деструкторе и закроют что-то левое? Ну тогда остаётся свою обёртку писать.

          > very expensive

          Ну... это реальная цена записи на диск, не более того. По сравнению с читерской записью во write-back кеш дорого, конечно.
          Ответить
          • > А вытащить дескриптор и позвать close() ты не можешь
            Не могу, он приватный
            Ответить
            • Гомосексуалист, чего такого страшного случилось в твоей жизи, что ты отчаялся и начал давать в попу променял 'пасцаль' на 'ссцы'??
              Ответить
    • Надо было быть полным додиком, чтобы задать вопрос на говнокоде. Это не стековерфлоу!
      Ответить
    •                                        Achtung!                                          

      Wir werden angegriffen! Alle posten besetzen. Ich wederchole: wir werden angegriffen!
      Ответить
    • > Вручную скинуть буфер на диск - тоже нечем, потому что функция, которой я пользовался в сишке, тут бесполезна

      Мои глаза!!!
      Тарас перешёл на дrustню (!) и ностальгирует по Сишке (!!).

      > Похуй на ошибки возврата, да?
      > это ж Раст, хуй с ними с исключениями короче.
      Да, «Си» это не самый хуёвый язык как оказалось.
      Ответить

    Добавить комментарий