forked from vitalif/vitastor
Compare commits
1 Commits
master
...
epoch-dele
Author | SHA1 | Date |
---|---|---|
Vitaliy Filippov | 4461a7ba35 |
|
@ -2,6 +2,6 @@ cmake_minimum_required(VERSION 2.8)
|
|||
|
||||
project(vitastor)
|
||||
|
||||
set(VERSION "0.7.1")
|
||||
set(VERSION "0.6.17")
|
||||
|
||||
add_subdirectory(src)
|
||||
|
|
|
@ -96,5 +96,5 @@ Vitastor Network Public License 1.1, основанная на GNU GPL 3.0 с д
|
|||
и также на условиях GNU GPL 2.0 или более поздней версии. Так сделано в целях
|
||||
совместимости с таким ПО, как QEMU и fio.
|
||||
|
||||
Вы можете найти полный текст VNPL 1.1 на английском языке в файле [VNPL-1.1.txt](VNPL-1.1.txt),
|
||||
VNPL 1.1 на русском языке в файле [VNPL-1.1-RU.txt](VNPL-1.1-RU.txt), а GPL 2.0 в файле [GPL-2.0.txt](GPL-2.0.txt).
|
||||
Вы можете найти полный текст VNPL 1.1 в файле [VNPL-1.1.txt](VNPL-1.1.txt),
|
||||
а GPL 2.0 в файле [GPL-2.0.txt](GPL-2.0.txt).
|
||||
|
|
680
VNPL-1.1-RU.txt
680
VNPL-1.1-RU.txt
|
@ -1,680 +0,0 @@
|
|||
СЕТЕВАЯ ПУБЛИЧНАЯ ЛИЦЕНЗИЯ VITASTOR
|
||||
VITASTOR NETWORK PUBLIC LICENSE
|
||||
Версия 1.1, от 6 февраля 2021
|
||||
|
||||
Автор лицензии: Виталий Филиппов <vitalif@yourcmc.ru>, 2021 год
|
||||
Каждый имеет право копировать и распространять точные копии этой
|
||||
лицензии, но без внесения изменений.
|
||||
|
||||
ПРЕАМБУЛА
|
||||
|
||||
Сетевая Публичная Лицензия Vitastor - это свободная "копилефт" лицензия для
|
||||
для программного обеспечения (ПО) и других видов произведений, специально
|
||||
разработанная, чтобы гарантировать кооперацию с сообществом при разработке
|
||||
сетевых приложений.
|
||||
|
||||
Большинство лицензий на программное обеспечение и другие произведения
|
||||
спроектированы так, чтобы лишить Вас свободы делиться ими и изменять их.
|
||||
Сетевая Публичная Лицензия Vitastor, напротив, разработана с целью
|
||||
гарантировать Ваше право распространять и вносить изменения во все версии
|
||||
программного обеспечения -- для уверенности, что ПО останется свободным для
|
||||
всех пользователей.
|
||||
|
||||
Когда мы говорим о свободном ПО, мы имеем в виду свободу использования, а не
|
||||
бесплатность. Свободные лицензии, такие, как Сетевая Публичная Лицензия
|
||||
Vitastor, составлены для того, чтобы убедиться, что у Вас есть право
|
||||
распространять копии свободного ПО (и взимать плату за них, если Вы хотите),
|
||||
что Вы получаете исходные тексты или можете получить их, если захотите, что Вы
|
||||
можете изменять программное обеспечение или использовать его части в новых
|
||||
свободных программах, и что Вы знаете о своем праве делать всё это.
|
||||
|
||||
Разработчики, использующие Сетевую Публичную Лицензию Vitastor, гарантируют
|
||||
Ваши права при помощи следующих мер: (1) закрепляют авторское право на
|
||||
программное обеспечение, и (2) предлагают Вам принять условия настоящей
|
||||
Лицензии, закрепляющей Ваше право на создание копий, распространение и (или)
|
||||
модификацию программного обеспечения.
|
||||
|
||||
Еще одно преимущество защиты свободы всех пользователей заключается в том,
|
||||
что улучшения, сделанные в разных версиях программы, при их широком
|
||||
распространении становятся доступными для использования другими разработчиками.
|
||||
Многие разработчики программного обеспечения воодушевляются этим
|
||||
сотрудничеством и пользуются его преимуществами. Однако, если программное
|
||||
обеспечение используется на сетевых серверах, данный результат не всегда
|
||||
достигается. Генеральная публичная лицензия GNU разрешает создание измененных
|
||||
версий и предоставление неограниченного доступа к ним, не делая общедоступным
|
||||
их исходный текст. Даже генеральная публичная лицензия GNU Affero разрешает
|
||||
использование модифицированной версии свободной программы в закрытой среде, где
|
||||
внешние пользователи взаимодействуют с ней только через закрытый промежуточный
|
||||
интерфейс (прокси), опять же, без открытия в свободный публичный доступ как
|
||||
самой программы, так и прокси.
|
||||
|
||||
Сетевая Публичная Лицензия Vitastor разработана специально чтобы
|
||||
гарантировать, что в таких случаях и модифицированная версия программы, и
|
||||
прокси оставались доступными сообществу. Для этого лицензия требует от
|
||||
операторов сетевых серверов предоставлять исходный код оригинальной программы,
|
||||
а также всех других программ, взаимодействующих с ней на их серверах,
|
||||
пользователям этих серверов, на условиях свободных лицензий. Таким образом,
|
||||
публичное использование изменённой версии ПО на сервере, прямо или косвенно
|
||||
доступном пользователям, даёт пользователям доступ к исходным кодам изменённой
|
||||
версии.
|
||||
|
||||
Детальные определения используемых терминов и описание условий копирования,
|
||||
распространения и внесения изменений приведены ниже.
|
||||
|
||||
ТЕРМИНЫ И УСЛОВИЯ
|
||||
|
||||
0. Определения.
|
||||
|
||||
"Настоящая Лицензия" -- версия 1.1 Сетевой Публичной Лицензии Vitastor.
|
||||
|
||||
Под "Авторским правом" понимаются все законы, сходные с авторско-правовыми,
|
||||
которые применяются к любым видам работ, например, к топологиям микросхем.
|
||||
|
||||
Термином "Программа" обозначается любое охраноспособное произведение,
|
||||
используемое в соответствии с настоящей Лицензией. Лицензиат именуется "Вы".
|
||||
"Лицензиаты" и "получатели" могут быть как физическими лицами, так и
|
||||
организациями.
|
||||
|
||||
"Внесение изменений" в произведение означает копирование или адаптацию
|
||||
произведения целиком или в части, способом, требующим разрешения
|
||||
правообладателя, за исключением изготовления его точной копии. Получившееся
|
||||
произведение называется "измененной версией" предыдущего произведения или
|
||||
произведением, "основанным на" более ранней работе.
|
||||
|
||||
Термином "Лицензионное произведение" обозначается неизмененная Программа или
|
||||
произведение, основанное на Программе.
|
||||
|
||||
"Распространение" произведения означает совершение с ним действий, которые
|
||||
при отсутствии разрешения сделают Вас прямо или косвенно ответственным за
|
||||
нарушение действующего закона об авторском праве, за исключением запуска на
|
||||
компьютере или изменения копии, созданной в личных целях. Распространение
|
||||
включает в себя копирование, раздачу копий (с изменениями или без них),
|
||||
доведение до всеобщего сведения, а в некоторых странах -- и другие действия.
|
||||
|
||||
"Передача" произведения означает любой вид распространения, который позволяет
|
||||
другим лицам создавать или получать копии произведения. Обычное взаимодействие
|
||||
с пользователем через компьютерную сеть без создания копии передачей не
|
||||
является.
|
||||
|
||||
Интерактивный интерфейс пользователя должен отображать "Информация об
|
||||
авторском праве", достаточную для того, чтобы (1) обеспечить отображение
|
||||
соответствующего уведомления об авторских правах и (2) сообщить пользователю
|
||||
о том, что ему не предоставляются никакие гарантии на произведение (за
|
||||
исключением явным образом предоставленных гарантий), о том, что лицензиаты
|
||||
могут передавать произведение на условиях, описанных в настоящей Лицензии,
|
||||
а также о том, как ознакомиться с текстом настоящей Лицензии. Если интерфейс
|
||||
предоставляет собой список пользовательских команд или настроек, наподобие
|
||||
меню, это требование считается выполненным при наличии явно выделенного
|
||||
пункта в таком меню.
|
||||
|
||||
1. Исходный текст.
|
||||
|
||||
Под "Исходным текстом" понимается произведение в форме, которая более всего
|
||||
подходит для внесения в него изменений. "Объектным кодом" называется
|
||||
произведение в любой иной форме.
|
||||
|
||||
"Стандартный интерфейс" -- интерфейс, который либо является общепринятым
|
||||
стандартом, введенным общепризнанным органом по стандартизации, либо, в случае
|
||||
интерфейсов, характерных для конкретного языка программирования -- тот,
|
||||
который широко используется разработчиками, пишущими программы на этом языке.
|
||||
|
||||
"Системные библиотеки" исполняемого произведения включают в себя то, что не
|
||||
относится к произведению в целом и при этом (a) входит в обычный комплект
|
||||
Основного компонента, но при этом не является его частью и (b) служит только
|
||||
для обеспечения работы с этим Основным компонентом или для реализации
|
||||
Стандартного интерфейса, для которого существует общедоступная реализация,
|
||||
опубликованная в виде исходного текста. "Основным компонентом" в данном
|
||||
контексте назван главный существенный компонент (ядро, оконная система и т.д.)
|
||||
определенной операционной системы (если она используется), под управлением
|
||||
которой функционирует исполняемое произведение, либо компилятор, используемый
|
||||
для создания произведения или интерпретатор объектного кода, используемый для
|
||||
его запуска.
|
||||
|
||||
"Полный исходный текст" для произведения в форме объектного кода -- весь
|
||||
исходный текст, необходимый для создания, установки и (для исполняемого
|
||||
произведения) функционирования объектного кода, а также модификации
|
||||
произведения, включая сценарии, контролирующие эти действия. Однако он не
|
||||
включает в себя Системные библиотеки, необходимые для функционирования
|
||||
произведения, инструменты общего назначения или общедоступные свободные
|
||||
программы, которые используются в неизменном виде для выполнения этих
|
||||
действий, но не являются частью произведения. Полный исходный текст включает
|
||||
в себя, например, файлы описания интерфейса, прилагаемые к файлам исходного
|
||||
текста произведения, а также исходные тексты общих библиотек и динамически
|
||||
связанных подпрограмм, которые требуются для функционирования произведения
|
||||
и разработаны специально для этого, например, для прямой передачи данных
|
||||
или управления потоками между этими подпрограммами и другими частями
|
||||
произведения. Полный исходный текст не включает в себя то, что пользователи
|
||||
могут сгенерировать автоматически из других частей Полного исходного текста.
|
||||
Полным исходным текстом для произведения в форме исходных текстов является
|
||||
само это произведение.
|
||||
|
||||
2. Основные права.
|
||||
|
||||
Все права, предоставленные на основании настоящей Лицензии, действуют в
|
||||
течение срока действия авторских прав на Программу и не могут быть отозваны
|
||||
при условии, что сформулированные в ней условия соблюдены. Настоящая Лицензия
|
||||
однозначно подтверждает Ваши неограниченные права на запуск неизмененной
|
||||
Программы. Настоящая Лицензия распространяется на результаты функционирования
|
||||
Лицензионного произведения только в том случае, если они, учитывая их
|
||||
содержание, сами являются частью Лицензионного произведения. Настоящая
|
||||
Лицензия подтверждает Ваши права на свободное использование произведения
|
||||
или другие аналогичные полномочия, предусмотренные действующим
|
||||
законодательством об авторском праве.
|
||||
|
||||
Если Вы не осуществляете обычную передачу Лицензионного произведения, то
|
||||
можете как угодно создавать, запускать и распространять его копии до тех пор,
|
||||
пока ваша Лицензия сохраняет силу. Вы можете передавать Лицензионные
|
||||
произведения третьим лицам исключительно для того, чтобы они внесли в них
|
||||
изменения для Вас или предоставили Вам возможность их запуска, при условии,
|
||||
что Вы соглашаетесь с условиями настоящей Лицензии при передаче всех
|
||||
материалов, авторскими правами на которые Вы не обладаете. Лица, создающие
|
||||
или запускающие Лицензионные произведения для Вас, должны делать это
|
||||
исключительно от Вашего имени, под Вашим руководством и контролем, на
|
||||
условиях, которые запрещают им создание без Вашей санкции каких-либо копий
|
||||
материалов, на которые Вы обладаете авторским правом.
|
||||
|
||||
Любая другая передача разрешается исключительно при соблюдении описанных
|
||||
ниже условий. Сублицензирование не допускается; раздел 10 делает его не нужным.
|
||||
|
||||
3. Защита прав пользователей от законов, запрещающих обход технических средств.
|
||||
|
||||
Ни одно Лицензионное произведение не должно считаться содержащим эффективные
|
||||
технические средства, удовлетворяющие требованиям любого действующего закона,
|
||||
принятого для исполнения обязательств, предусмотренных статьей 11 Договора ВОИС
|
||||
по авторскому праву от 20 декабря 1996 года или аналогичных законов,
|
||||
запрещающих или ограничивающих обход таких технических средств.
|
||||
|
||||
При передаче Лицензионного произведения Вы отказываетесь от всех
|
||||
предоставляемых законом полномочий по запрету обхода технических средств,
|
||||
используемых авторами в связи с осуществлением их прав, признавая, что такой
|
||||
обход находится в рамках осуществления прав на использование Лицензионного
|
||||
произведения, предоставленных настоящей Лицензией; также Вы отказываетесь
|
||||
от любых попыток ограничить функционирование произведения или внесение в него
|
||||
изменений, направленных на реализацию предоставленных Вам законом прав на
|
||||
запрет пользователю обхода технических средств.
|
||||
|
||||
4. Передача неизмененных копий.
|
||||
|
||||
Вы можете передавать точные копии исходных текстов Программы в том виде,
|
||||
в котором Вы их получили, на любом носителе, при условии, что Вы прилагаете
|
||||
к каждой копии соответствующее уведомление об авторских правах способом,
|
||||
обеспечивающим ознакомление с ним пользователя; сохраняете все уведомления
|
||||
о том, что к тексту применима настоящая Лицензия и любые ограничения,
|
||||
добавленные в соответствии с разделом 7; сохраняете все уведомления об
|
||||
отсутствии каких-либо гарантий; предоставляете всем получателям вместе с
|
||||
Программой копию настоящей Лицензии.
|
||||
|
||||
Вы можете установить любую цену за каждую копию, которую Вы передаете,
|
||||
или распространять копии бесплатно; также Вы можете предложить поддержку
|
||||
или гарантию за отдельную плату.
|
||||
|
||||
5. Передача измененных исходных текстов.
|
||||
|
||||
Вы можете передавать исходный текст произведения, основанного на Программе,
|
||||
или изменений, необходимых для того, чтобы получить его из Программы, на
|
||||
условиях, описанных в разделе 4, при соблюдении следующих условий:
|
||||
|
||||
а) Произведение должно содержать уведомления о произведенных Вами
|
||||
изменениях с указанием их даты, сделанные способом, обеспечивающим
|
||||
ознакомление с ними пользователя.
|
||||
|
||||
b) Произведение должно содержать уведомление о том, что оно
|
||||
распространяется на условиях настоящей Лицензии, а также об условиях,
|
||||
добавленных в соответствии с разделом 7, сделанное способом,
|
||||
обеспечивающим ознакомление с ним пользователя. Данное требование имеет
|
||||
приоритет над требованиями раздела 4 "оставлять нетронутыми все
|
||||
уведомления".
|
||||
|
||||
c) Вы должны передать на условиях настоящей Лицензии всю работу целиком
|
||||
любому лицу, которое приобретает копию. Таким образом, настоящая Лицензия
|
||||
вместе с любыми применимыми условиями раздела 7 будет применяться к
|
||||
произведению в целом и всем его частям, независимо от их комплектности.
|
||||
Настоящая Лицензия не дает права на лицензирование произведения на любых
|
||||
других условиях, но это не лишает законной силы такое разрешение, если Вы
|
||||
получили его отдельно.
|
||||
|
||||
d) Если произведение имеет интерактивные пользовательские интерфейсы,
|
||||
каждый из них должен отображать Информацию об авторском праве; однако,
|
||||
если Программа имеет пользовательские интерфейсы, которые не отображают
|
||||
информацию об авторском праве, от Вашего произведения этого также не
|
||||
требуется.
|
||||
|
||||
Включение Лицензионного произведения в подборку на разделе хранения данных
|
||||
или на носителе, на котором распространяется произведение, вместе с другими
|
||||
отдельными самостоятельными произведениями, которые по своей природе не
|
||||
являются переработкой Лицензионного произведения и не объединены с ним,
|
||||
например, в программный комплекс, называется "набором", если авторские права
|
||||
на подборку не используются для ограничения доступа к ней или законных прав
|
||||
её пользователей сверх того, что предусматривают лицензии на отдельные
|
||||
произведения. Включение Лицензионного произведения в набор не влечет применения
|
||||
положений настоящей Лицензии к остальным его частям.
|
||||
|
||||
6. Передача произведения в формах, не относящихся к исходному тексту.
|
||||
|
||||
Вы можете передавать Лицензионное произведение в виде объектного кода в
|
||||
соответствии с положениями разделов 4 и 5, при условии, что Вы также передаете
|
||||
машиночитаемый Полный исходный текст в соответствии с условиями настоящей
|
||||
Лицензии, одним из следующих способов:
|
||||
|
||||
а) Передавая объектный код или содержащий его материальный продукт (включая
|
||||
распределенный материальный носитель), с приложением Полного исходного
|
||||
текста наматериальном носителе, обычно используемом для обмена программным
|
||||
обеспечением.
|
||||
|
||||
b) Передавая объектный код или содержащий его материальный продукт (включая
|
||||
носитель, на котором распространяется произведение), с письменным
|
||||
предложением, действительным в течение не менее трех лет либо до тех пор,
|
||||
пока Вы предоставляете запасные части или поддержку для данного продукта,
|
||||
о передаче любому обладателю объектного кода (1) копии Полного исходного
|
||||
текста для всего программного обеспечения, содержащегося в продукте, на
|
||||
которое распространяется действие настоящей Лицензии, на физическом
|
||||
носителе, обычно используемом для обмена программным обеспечением, по цене,
|
||||
не превышающей разумных затрат на передачу копии, или (2) доступа к Полному
|
||||
исходному тексту с возможностью его копирования с сетевого сервера без
|
||||
взимания платы.
|
||||
|
||||
с) Передавая отдельные копии объектного кода с письменной копией предложения
|
||||
о предоставлении Полного исходного текста. Этот вариант допускается только
|
||||
в отдельных случаях при распространении без извлечения прибыли, и только
|
||||
если Вы получили объектный код с таким предложением в соответствии
|
||||
с пунктом 6b.
|
||||
|
||||
d) Передавая объектный код посредством предоставления доступа к нему по
|
||||
определенному адресу (бесплатно или за дополнительную плату), и предлагая
|
||||
эквивалентный доступ к Полному исходному тексту таким же способом по тому же
|
||||
адресу без какой-либо дополнительной оплаты. От Вас не требуется принуждать
|
||||
получателей копировать Полный исходный текст вместе с объектным кодом. Если
|
||||
объектный код размещен на сетевом сервере, Полный исходный текст может
|
||||
находиться на другом сервере (управляемом Вами или третьим лицом), который
|
||||
предоставляет аналогичную возможность копирования; при этом Вы должны четко
|
||||
указать рядом с объектным кодом способ получения Полного исходного текста.
|
||||
Независимо от того, на каком сервере расположен Полный исходный текст, Вы
|
||||
обязаны убедиться в том, что он будет распространяться в течение времени,
|
||||
необходимого для соблюдения этих требований.
|
||||
|
||||
e) Передавая объектный код с использованием одноранговой (пиринговой) сети,
|
||||
при условии информирования других пользователей сети о том, где можно
|
||||
бесплатно получить объектный код и Полный исходный текст произведения
|
||||
способом, описанным в пункте 6d.
|
||||
|
||||
Не нужно включать в передаваемый объектный код его отделимые части, исходные
|
||||
тексты которых не входят в состав Полного исходного текста, такие как Системные
|
||||
библиотеки.
|
||||
|
||||
"Потребительский товар" это либо (1) "товар, предназначенный для личных нужд",
|
||||
под которым понимается любое материальное личное имущество, которое обычно
|
||||
используется для личных, семейных или домашних целей, или (2) что-либо
|
||||
спроектированное или продающееся для использования в жилище. При определении
|
||||
того, предназначен ли товар для личных нужд, сомнения должны толковаться в
|
||||
пользу положительного ответа на этот вопрос. Применительно к конкретному
|
||||
товару, используемому конкретным пользователем, под выражением "обычно
|
||||
используется" имеется в виду способ, которым данный вид товаров преимущественно
|
||||
или как правило используется, независимо от статуса конкретного пользователя
|
||||
или способа, которым конкретный пользователь использует, предполагает или
|
||||
будет использовать товар. Товар относится к предназначенным для личных нужд
|
||||
независимо от того, насколько часто он используется в коммерческой
|
||||
деятельности, промышленности или иной сфере, не относящейся к личным нуждам,
|
||||
за исключением случая, когда использование в этой сфере представляет собой
|
||||
единственный основной способ использования такого товара.
|
||||
|
||||
"Информация, необходимая для установки" Потребительского товара -- любые
|
||||
методы, процедуры, сведения, необходимые для авторизации, или другая
|
||||
информация, необходимая для установки и запуска в Потребительском товаре
|
||||
измененных версий Лицензионного произведения, полученных при изменении
|
||||
Полного исходного текста. Данная информация должна быть достаточной для
|
||||
того, чтобы обеспечить возможность внесения в исходный текст изменений,
|
||||
не приводящих к ограничению или нарушению его дальнейшей работоспособности.
|
||||
|
||||
Если вместе с Потребительским товаром или специально для использования
|
||||
в нём Вы передаете произведение в виде объектного кода на условиях, описанных
|
||||
в данном разделе, и такая передача является частью сделки, по которой право
|
||||
владения и пользования Потребительским товаром переходит к получателю
|
||||
пожизненно или на определенный срок (независимо от признаков сделки), Полный
|
||||
исходный текст, передаваемый согласно данному разделу, должен сопровождаться
|
||||
Информацией, необходимой для установки. Но это требование не применяется,
|
||||
если ни Вы, ни какое-либо третье лицо не сохраняет за собой возможности
|
||||
установки измененного объектного кода на Потребительский товар (например,
|
||||
произведение было установлено в постоянную память).
|
||||
|
||||
Требование о предоставлении Информации, необходимой для установки, не
|
||||
включает в себя требование продолжения оказания услуг по поддержке,
|
||||
предоставления гарантии или обновлений для произведения, которое было изменено
|
||||
или установлено получателем, либо для Потребительского товара, в котором оно
|
||||
было изменено или на который оно было установлено. В доступе к сети может быть
|
||||
отказано, если само внесение изменений существенно и негативно влияет на
|
||||
работу сети, нарушает правила обмена данными или не поддерживает протоколы для
|
||||
обмена данными по сети.
|
||||
|
||||
Передаваемый в соответствии с данным разделом Полный исходный текст и
|
||||
предоставленная Информация, необходимая для установки, должны быть записаны в
|
||||
формате, который имеет общедоступное описание (и общедоступную реализацию,
|
||||
опубликованную в форме исходного текста) и не должны требовать никаких
|
||||
специальных паролей или ключей для распаковки, чтения или копирования.
|
||||
|
||||
7. Дополнительные условия.
|
||||
|
||||
"Дополнительными разрешениями" называются условия, которые дополняют условия
|
||||
настоящей Лицензии, делая исключения из одного или нескольких её положений.
|
||||
Дополнительные разрешения, которые применимы ко всей Программе, должны
|
||||
рассматриваться как часть настоящей Лицензии, в той степени, в которой они
|
||||
соответствуют действующему законодательству. Если дополнительные разрешения
|
||||
применяются только к части Программы, эта часть может быть использована отдельно
|
||||
на измененных условиях, но вся Программа продолжает использоваться на условиях
|
||||
настоящей Лицензии без учета дополнительных разрешений.
|
||||
|
||||
Когда Вы передаете копию Лицензионного произведения, Вы можете по своему
|
||||
усмотрению исключить любые дополнительные разрешения, примененные к этой копии
|
||||
или к любой её части. (Для дополнительных разрешений может быть заявлено
|
||||
требование об их удалении в определенных случаях, когда Вы вносите изменения в
|
||||
произведение.) Вы можете добавлять дополнительные разрешения к добавленным Вами
|
||||
в Лицензионное произведение материалам, на которые Вы обладаете авторскими
|
||||
правами или правом выдачи соответствующего разрешения.
|
||||
|
||||
Независимо от любых других положений настоящей Лицензии, Вы можете дополнить
|
||||
следующими условиями положения настоящей Лицензии в отношении материала,
|
||||
добавленного к Лицензионному произведению (если это разрешено обладателями
|
||||
авторских прав на материал):
|
||||
|
||||
a) отказом от гарантий или ограничением ответственности, отличающимися от
|
||||
тех, что описаны в разделах 15 и 16 настоящей Лицензии; либо
|
||||
|
||||
b) требованием сохранения соответствующей информации о правах или об
|
||||
авторстве материала, или включения её в Информацию об авторском праве,
|
||||
отображаемую содержащим его произведением; либо
|
||||
|
||||
c) запретом на искажение информации об источнике происхождения материала
|
||||
или требованием того, чтобы измененные версии такого материала содержали
|
||||
корректную отметку об отличиях от исходной версии; либо
|
||||
|
||||
d) ограничением использования в целях рекламы имен лицензиаров или авторов
|
||||
материала; либо
|
||||
|
||||
e) отказом от предоставления прав на использование в качестве товарных
|
||||
знаков некоторых торговых наименований, товарных знаков или знаков
|
||||
обслуживания; либо
|
||||
|
||||
f) требованием от каждого, кто по договору передает материал (или его
|
||||
измененные версии), предоставления компенсации лицензиарам и авторам
|
||||
материала в виде принятия на себя любой ответственности, которую этот
|
||||
договор налагает на лицензиаров и авторов.
|
||||
|
||||
Все остальные ограничительные дополнительные условия считаются "дополнительными
|
||||
запретами" по смыслу раздела 10. Если программа, которую Вы получили, или любая
|
||||
её часть содержит уведомление о том, что наряду с настоящей Лицензией её
|
||||
использование регулируется условием, относящимся к дополнительным запретам, Вы
|
||||
можете удалить такое условие. Если лицензия содержит дополнительный запрет, но
|
||||
допускает лицензирование на измененных условиях или передачу в соответствии с
|
||||
настоящей Лицензией, Вы можете добавить к Лицензионному произведению материал,
|
||||
используемый на условиях такой лицензии, в том случае, если дополнительный
|
||||
запрет не сохраняется при таком изменении условий лицензии или передаче.
|
||||
|
||||
Если Вы добавляете условия для использования Лицензионного произведения в
|
||||
соответствии с настоящим разделом, Вы должны поместить в соответствующих файлах
|
||||
исходного текста уведомление о том, что к этим файлам применяются дополнительные
|
||||
условия, или указание на то, как ознакомиться с соответствующими условиями.
|
||||
|
||||
Дополнительные разрешающие или ограничивающие условия могут быть сформулированы
|
||||
в виде отдельной лицензии или зафиксированы как исключения; вышеуказанные
|
||||
требования применяются в любом случае.
|
||||
|
||||
8. Прекращение действия.
|
||||
|
||||
Вы не можете распространять Лицензионное произведение или вносить в него
|
||||
изменения на условиях, отличающихся от явно оговоренных в настоящей Лицензии.
|
||||
Любая попытка распространения или внесения изменений на иных условиях является
|
||||
ничтожной и автоматически прекращает Ваши права, полученные по настоящей
|
||||
Лицензии (включая лицензию на любые патенты, предоставленные согласно третьему
|
||||
пункту раздела 11).
|
||||
|
||||
Тем не менее если Вы прекращаете нарушение настоящей Лицензии, Ваши права,
|
||||
полученные от конкретного правообладателя, восстанавливаются (а) временно, до
|
||||
тех пор пока правообладатель явно и окончательно не прекратит действие Ваших
|
||||
прав, и (б) навсегда, если правообладатель не уведомит Вас о нарушении с помощью
|
||||
надлежащих средств в течение 60 дней после прекращения нарушений.
|
||||
|
||||
Кроме того, Ваши права, полученные от конкретного правообладателя,
|
||||
восстанавливаются навсегда, если правообладатель впервые любым подходящим
|
||||
способом уведомляет Вас о нарушении настоящей Лицензии на свое произведение (для
|
||||
любого произведения) и Вы устраняете нарушение в течение 30 дней после получения
|
||||
уведомления.
|
||||
|
||||
Прекращение Ваших прав, описанное в настоящем разделе, не прекращает действие
|
||||
лицензий лиц, которые получили от Вас копии произведения или права,
|
||||
предоставляемые настоящей Лицензией. Если Ваши права были прекращены навсегда и
|
||||
не восстановлены, Вы не можете вновь получить право на тот же материал на
|
||||
условиях, описанных в разделе 10.
|
||||
|
||||
9. Акцепт не требуется для получения копий.
|
||||
|
||||
Вы не обязаны принимать условия настоящей Лицензии для того, чтобы получить или
|
||||
запустить копию Программы. Случайное распространение Лицензионного произведения,
|
||||
происходящее вследствие использования одноранговой (пиринговой) сети для
|
||||
получения его копии, также не требует принятия этих условий. Тем не менее только
|
||||
настоящая Лицензия дает Вам право распространять или изменять любое Лицензионное
|
||||
произведение. Если Вы не приняли условия настоящей Лицензии, такие действия
|
||||
будут нарушением авторского права. Поэтому изменяя или распространяя
|
||||
Лицензионное произведение, Вы выражаете согласие с условиями настоящей Лицензии.
|
||||
|
||||
10. Автоматическое получение прав последующими получателями.
|
||||
|
||||
Каждый раз, когда Вы передаете Лицензионное произведение, получатель
|
||||
автоматически получает от его лицензиара право запускать, изменять и
|
||||
распространять это произведение при условии соблюдения настоящей Лицензии. Вы не
|
||||
несете ответственности за соблюдение третьими лицами условий настоящей Лицензии.
|
||||
|
||||
"Реорганизацией" называются действия, в результате которых передается управление
|
||||
организацией или значительная часть её активов, а также происходит разделение
|
||||
или слияние организаций. Если распространение Лицензионного произведения
|
||||
является результатом реорганизации, каждая из сторон сделки, получающая копию
|
||||
произведения, также получает все права на произведение, которые предшествующее
|
||||
юридическое лицо имело или могло предоставить согласно предыдущему абзацу, а
|
||||
также право на владение Полным исходным текстом произведения от предшественника,
|
||||
осуществляемое в его интересах, если предшественник владеет им или может
|
||||
получить его при разумных усилиях.
|
||||
|
||||
Вы не можете налагать каких-либо дополнительных ограничений на осуществление
|
||||
прав, предоставленных или подтвержденных в соответствии с настоящей Лицензией.
|
||||
Например, Вы не можете ставить осуществление прав, предоставленных по настоящей
|
||||
Лицензии, в зависимость от оплаты отчислений, роялти или других сборов; также Вы
|
||||
не можете инициировать судебный процесс (включая встречный иск или заявление
|
||||
встречного требования в судебном процессе) о нарушении любых патентных прав при
|
||||
создании, использовании, продаже, предложении продажи, импорте Программы или
|
||||
любой её части.
|
||||
|
||||
11. Патенты.
|
||||
|
||||
"Инвестором" называется правообладатель, разрешающий использование Программы
|
||||
либо произведения, на котором основана Программа, на условиях настоящей
|
||||
Лицензии. Произведение, лицензированное таким образом, называется "версией со
|
||||
вкладом" инвестора.
|
||||
|
||||
"Неотъемлемые патентные претензии" инвестора -- все патентные права,
|
||||
принадлежащие инвестору или контролируемые им в настоящее время либо
|
||||
приобретенные в будущем, которые могут быть нарушены созданием, использованием
|
||||
или продажей версии со вкладом, допускаемыми настоящей Лицензией; они не
|
||||
включают в себя права, которые будут нарушены исключительно вследствие будущих
|
||||
изменений версии со вкладом. Для целей данного определения под "контролем"
|
||||
понимается право выдавать патентные сублицензии способами, не нарушающими
|
||||
требований настоящей Лицензии.
|
||||
|
||||
Каждый инвестор предоставляет Вам неисключительную безвозмездную лицензию на
|
||||
патент, действующую во всем мире, соответствующую неотъемлемым патентным
|
||||
претензиям инвестора, на создание, использование, продажу, предложение для
|
||||
продажи, импорт, а также запуск, внесение изменений и распространение всего, что
|
||||
входит в состав версии со вкладом.
|
||||
|
||||
В следующих трех абзацах "лицензией на патент" называется любое явно выраженное
|
||||
вовне согласие или обязательство не применять патент (например, выдача
|
||||
разрешения на использование запатентованного объекта или обещание не подавать в
|
||||
суд за нарушение патента). "Выдать" кому-то такую лицензию на патент означает
|
||||
заключить такое соглашение или обязаться не применять патент против него.
|
||||
|
||||
Если Вы передаете Лицензионное произведение, сознательно основываясь на лицензии
|
||||
на патент, в то время как Полный исходный текст произведения невозможно
|
||||
бесплатно скопировать с общедоступного сервера или другим не вызывающим
|
||||
затруднений способом, Вы должны либо (1) обеспечить возможность такого доступа к
|
||||
Полному исходному тексту, либо (2) отказаться от прав, предоставленных по
|
||||
лицензии на патент для данного произведения, либо (3) принять меры по передаче
|
||||
лицензии на патент последующим получателям произведения, в соответствии с
|
||||
требованиями настоящей Лицензии. "Сознательно основываясь" означает, что Вы
|
||||
знаете, что при отсутствии лицензии на патент передача Вами Лицензионного
|
||||
произведения в определенной стране или использование получателем переданного ему
|
||||
Вами Лицензионного произведения в этой стране нарушит один или несколько
|
||||
определенных патентов этой страны, срок действия которых не истек.
|
||||
|
||||
Если в соответствии или в связи с единичной сделкой либо соглашением Вы
|
||||
передаете или делаете заказ на распространение Лицензионного произведения, и
|
||||
предоставляете определенным лицам, получающим Лицензионное произведение,
|
||||
лицензию на патент, разрешающую им использовать, распространять, вносить
|
||||
изменения или передавать конкретные экземпляры Лицензионного произведения,
|
||||
права, которые Вы предоставляете по лицензии на патент, автоматически переходят
|
||||
ко всем получателям Лицензионного произведения и произведений, созданных на его
|
||||
основе.
|
||||
|
||||
Патентная лицензия называется "дискриминирующей", если она не покрывает,
|
||||
запрещает осуществление или содержит в качестве условия отказ от применения
|
||||
одного или нескольких прав, предоставленных настоящей Лицензией. Вы не можете
|
||||
передавать Лицензионное произведение, если Вы являетесь участником договора с
|
||||
третьим лицом, осуществляющим распространение программного обеспечения, в
|
||||
соответствии с которым Вы делаете в пользу третьего лица выплаты, размер которых
|
||||
зависит от масштабов Вашей деятельности по передаче произведения, и в
|
||||
соответствии с которым любое третье лицо, получающее от Вас Лицензионное
|
||||
произведение, делает это на условиях дискриминирующей патентной лицензии (а)
|
||||
которая зависит от количества копий Лицензионного произведения, переданных Вами
|
||||
(или копий, сделанных с этих копий), или (b) которая используется
|
||||
преимущественно в конкретных товарах или подборках, содержащих Лицензионное
|
||||
произведение, или в связи с ними, в том случае, если Вы заключили данный договор
|
||||
или получили лицензию на патент после 28 марта 2007 года.
|
||||
|
||||
Ничто в настоящей Лицензии не должно толковаться как исключение или ограничение
|
||||
любого предполагаемого права или других способов противодействия нарушениям,
|
||||
которые во всем остальном могут быть доступны для Вас в соответствии с
|
||||
применимым патентным правом.
|
||||
|
||||
12. Запрет отказывать в свободе другим.
|
||||
|
||||
Если на Вас наложены обязанности (будь то по решению суда, договору или иным
|
||||
способом), которые противоречат условиям настоящей Лицензии, это не освобождает
|
||||
Вас от соблюдения её условий. Если Вы не можете передать Лицензионное
|
||||
произведение так, чтобы одновременно выполнять Ваши обязательства по настоящей
|
||||
Лицензии и любые другие относящиеся к делу обязательства, то Вы не можете
|
||||
передавать его вообще. Например, если Вы согласны с условием, обязывающими Вас
|
||||
производить сбор отчислений за дальнейшую передачу от тех, кому Вы передаете
|
||||
Программу, то для того, чтобы соблюсти это условие и выполнить требования
|
||||
настоящей Лицензии, Вы должны полностью воздержаться от передачи Программы.
|
||||
|
||||
13. Удаленное сетевое взаимодействие.
|
||||
|
||||
Под "Прокси-программой" понимается отдельная программа, специально
|
||||
разработанная для использования совместно с Лицензионным произведением,
|
||||
и взаимодействующая с ним прямо или косвенно через любой вид программного
|
||||
интерфейса, компьютерную сеть, имитацию такой сети, или, в свою очередь,
|
||||
через другую Прокси-программу.
|
||||
|
||||
Независимо от любых других положений настоящей Лицензии, если вы
|
||||
предоставляете любому пользователю возможность взаимодействовать с Лицензионным
|
||||
произведением через компьютерную сеть, имитацию такой сети, или через любое
|
||||
количество "Прокси-программ", вы должны в явной форме предложить этому
|
||||
пользователю возможность получить Полный исходный текст Лицензионного
|
||||
произведения и всех Прокси-программ путём предоставления доступа к нему
|
||||
с сетевого сервера без взимания платы, посредством стандартных или
|
||||
традиционных способов, используемых для копирования программного обеспечения.
|
||||
Полный исходный текст Лицензионного произведения должен предоставляться
|
||||
пользователю на условиях настоящей Лицензии, а Полный исходный текст
|
||||
Прокси-программ должен предоставляться пользователю либо на условиях настоящей
|
||||
Лицензии, либо на условиях одной из свободных лицензий, совместимых с
|
||||
Генеральной публичной Лицензией GNU, перечисленных Фондом Свободного
|
||||
Программного Обеспечения в списке под названием "Лицензии свободных программ,
|
||||
совместимые с GPL".
|
||||
|
||||
14. Пересмотренные редакции настоящей Лицензии.
|
||||
|
||||
Автор настоящей Лицензии время от времени может публиковать пересмотренные
|
||||
и (или) новые редакции Сетевой Публичной Лицензии Vitastor. Они будут аналогичны
|
||||
по смыслу настоящей редакции, но могут отличаться от нее в деталях, направленных
|
||||
на решение новых проблем или регулирование новых отношений.
|
||||
|
||||
Каждой редакции присваивается собственный номер. Если для Программы указано,
|
||||
что к ней применима определенная редакция Сетевой Публичной Лицензии Vitastor
|
||||
"или любая более поздняя редакция", у Вас есть возможность использовать термины
|
||||
и условия, содержащиеся в редакции с указанным номером или любой более поздней
|
||||
редакции, опубликованной автором настоящей Лицензии. Если для Программы не
|
||||
указан номер редакции Сетевой Публичной Лицензии Vitastor, Вы можете выбрать
|
||||
любую редакцию, опубликованную автором настоящей Лицензии.
|
||||
|
||||
Более поздние редакции Лицензии могут дать Вам дополнительные или принципиально
|
||||
иные права. Тем не менее в результате Вашего выбора более поздней редакции на
|
||||
автора или правообладателя не возлагается никаких дополнительных обязанностей.
|
||||
|
||||
15. Отказ от гарантий.
|
||||
|
||||
НА ПРОГРАММУ НЕ ПРЕДОСТАВЛЯЕТСЯ НИКАКИХ ГАРАНТИЙ ЗА ИСКЛЮЧЕНИЕМ ПРЕДУСМОТРЕННЫХ
|
||||
ДЕЙСТВУЮЩИМ ЗАКОНОДАТЕЛЬСТВОМ. ЕСЛИ ИНОЕ НЕ УКАЗАНО В ПИСЬМЕННОЙ ФОРМЕ,
|
||||
ПРАВООБЛАДАТЕЛИ И (ИЛИ) ТРЕТЬИ ЛИЦА ПРЕДОСТАВЛЯЮТ ПРОГРАММУ "КАК ЕСТЬ", БЕЗ
|
||||
КАКИХ-ЛИБО ЯВНЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ ГАРАНТИЙ, ВКЛЮЧАЯ ГАРАНТИИ ПРИГОДНОСТИ ДЛЯ
|
||||
КОНКРЕТНЫХ ЦЕЛЕЙ, НО НЕ ОГРАНИЧИВАЯСЬ ИМИ. ВЕСЬ РИСК, СВЯЗАННЫЙ С КАЧЕСТВОМ И
|
||||
ПРОИЗВОДИТЕЛЬНОСТЬЮ ПРОГРАММЫ, ВОЗЛАГАЕТСЯ НА ВАС. ЕСЛИ В ПРОГРАММЕ БУДУТ
|
||||
ВЫЯВЛЕНЫ НЕДОСТАТКИ, ВЫ ПРИНИМАЕТЕ НА СЕБЯ СТОИМОСТЬ ВСЕГО НЕОБХОДИМОГО
|
||||
ОБСЛУЖИВАНИЯ, РЕМОНТА ИЛИ ИСПРАВЛЕНИЯ.
|
||||
|
||||
16. Ограничение ответственности.
|
||||
|
||||
ЕСЛИ ИНОЕ НЕ ПРЕДУСМОТРЕНО ДЕЙСТВУЮЩИМ ЗАКОНОДАТЕЛЬСТВОМ ИЛИ СОГЛАШЕНИЕМ СТОРОН,
|
||||
ЗАКЛЮЧЕННЫМ В ПИСЬМЕННОЙ ФОРМЕ, ПРАВООБЛАДАТЕЛЬ ИЛИ ИНОЕ ЛИЦО, КОТОРОЕ ВНОСИТ
|
||||
ИЗМЕНЕНИЯ В ПРОГРАММУ И (ИЛИ) ПЕРЕДАЕТ ЕЁ НА УСЛОВИЯХ, СФОРМУЛИРОВАННЫХ ВЫШЕ, НЕ
|
||||
МОЖЕТ НЕСТИ ОТВЕТСТВЕННОСТЬ ПЕРЕД ВАМИ ЗА ПРИЧИНЕННЫЙ УЩЕРБ, ВКЛЮЧАЯ УЩЕРБ
|
||||
ОБЩЕГО ЛИБО КОНКРЕТНОГО ХАРАКТЕРА, ПРИЧИНЕННЫЙ СЛУЧАЙНО ИЛИ ЯВЛЯЮЩИЙСЯ
|
||||
СЛЕДСТВИЕМ ИСПОЛЬЗОВАНИЯ ПРОГРАММЫ ЛИБО НЕВОЗМОЖНОСТИ ЕЁ ИСПОЛЬЗОВАНИЯ (В ТОМ
|
||||
ЧИСЛЕ ЗА УНИЧТОЖЕНИЕ ИЛИ МОДИФИКАЦИЮ ИНФОРМАЦИИ, ЛИБО УБЫТКИ, ПОНЕСЕННЫЕ ВАМИ
|
||||
ИЛИ ТРЕТЬИМИ ЛИЦАМИ, ЛИБО СБОИ ПРОГРАММЫ ПРИ ВЗАИМОДЕЙСТВИИ С ДРУГИМ ПРОГРАММНЫМ
|
||||
ОБЕСПЕЧЕНИЕМ), В ТОМ ЧИСЛЕ И В СЛУЧАЯХ, КОГДА ПРАВООБЛАДАТЕЛЬ ИЛИ ТРЕТЬЕ ЛИЦО
|
||||
ПРЕДУПРЕЖДЕНЫ О ВОЗМОЖНОСТИ ПРИЧИНЕНИЯ ТАКИХ УБЫТКОВ.
|
||||
|
||||
17. Толкование разделов 15 и 16.
|
||||
|
||||
Если отказ от гарантии и ограничение ответственности, представленные выше, по
|
||||
закону не могут быть применены в соответствии с их условиями, суды,
|
||||
рассматривающие спор, должны применить действующий закон, который в наибольшей
|
||||
степени предусматривает абсолютный отказ от всей гражданской ответственности в
|
||||
связи с Программой, за исключением случаев, когда гарантия или принятие на себя
|
||||
ответственности за копию программы предоставляется за плату.
|
||||
|
||||
КОНЕЦ ОПРЕДЕЛЕНИЙ И УСЛОВИЙ
|
||||
|
||||
Порядок применения условий Лицензии к Вашим программам
|
||||
|
||||
Если Вы разрабатываете новую программу и хотите, чтобы её использование принесло
|
||||
максимальную пользу обществу, наилучший способ достичь этого -- сделать её
|
||||
свободной, чтобы все могли распространять и изменять её на условиях настоящей
|
||||
Лицензии.
|
||||
|
||||
Для этого сделайте так, чтобы программа содержала в себе описанные ниже
|
||||
уведомления. Самым надежным способом это сделать является включение их в начало
|
||||
каждого файла исходного текста, чтобы наиболее эффективным образом сообщить об
|
||||
отсутствии гарантий; каждый файл должен иметь по меньшей мере одну строку с
|
||||
оповещением об авторских правах и указанием на то, где находится полный текст
|
||||
уведомлений.
|
||||
|
||||
<Строка с названием Программы и информацией о её назначении.>
|
||||
Copyright © <год выпуска программы в свет> <имя автора>
|
||||
|
||||
Эта программа является свободным программным обеспечением: Вы можете
|
||||
распространять её и (или) изменять, соблюдая условия Сетевой Публичной
|
||||
Лицензии Vitastor, опубликованной автором Vitastor, либо редакции 1.1
|
||||
Лицензии, либо (на Ваше усмотрение) любой редакции, выпущенной позже.
|
||||
|
||||
Эта программа распространяется в расчете на то, что она окажется полезной,
|
||||
но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, включая подразумеваемую гарантию КАЧЕСТВА либо
|
||||
ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Ознакомьтесь с Сетевой Публичной
|
||||
Лицензией Vitastor для получения более подробной информации.
|
||||
|
||||
Также добавьте информацию о том, как связаться с Вами посредством электронной
|
||||
или обычной почты.
|
||||
|
||||
Если ваша программа взаимодействует с пользователями удаленно через
|
||||
компьютерную сеть, Вы также должны убедиться, что обеспечили её пользователям
|
||||
возможность получить её исходные тексты. Например, если Ваша программа является
|
||||
веб-приложением, её интерфейс может отображать ссылку "Исходные коды", которая
|
||||
указывает на архив с текстом. Существует много способов, которыми Вы можете
|
||||
распространять исходные тексты, для разных программ подходят разные решения;
|
||||
ознакомьтесь с разделом 13 для того, чтобы узнать конкретные требования.
|
|
@ -61,7 +61,7 @@ modification follow.
|
|||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 1.1 of the Vitastor Network Public License.
|
||||
"This License" refers to version 1 of the Vitastor Network Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
@ -629,7 +629,7 @@ the "copyright" line and a pointer to where the full notice is found.
|
|||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the Vitastor Network Public License as published by
|
||||
the Vitastor Author, either version 1.1 of the License, or
|
||||
the Vitastor Author, either version 1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
VERSION ?= v0.7.1
|
||||
VERSION ?= v0.6.17
|
||||
|
||||
all: build push
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ spec:
|
|||
capabilities:
|
||||
add: ["SYS_ADMIN"]
|
||||
allowPrivilegeEscalation: true
|
||||
image: vitalif/vitastor-csi:v0.7.1
|
||||
image: vitalif/vitastor-csi:v0.6.17
|
||||
args:
|
||||
- "--node=$(NODE_ID)"
|
||||
- "--endpoint=$(CSI_ENDPOINT)"
|
||||
|
|
|
@ -116,7 +116,7 @@ spec:
|
|||
privileged: true
|
||||
capabilities:
|
||||
add: ["SYS_ADMIN"]
|
||||
image: vitalif/vitastor-csi:v0.7.1
|
||||
image: vitalif/vitastor-csi:v0.6.17
|
||||
args:
|
||||
- "--node=$(NODE_ID)"
|
||||
- "--endpoint=$(CSI_ENDPOINT)"
|
||||
|
|
|
@ -5,7 +5,7 @@ package vitastor
|
|||
|
||||
const (
|
||||
vitastorCSIDriverName = "csi.vitastor.io"
|
||||
vitastorCSIDriverVersion = "0.7.1"
|
||||
vitastorCSIDriverVersion = "0.6.17"
|
||||
)
|
||||
|
||||
// Config struct fills the parameters of request or user input
|
||||
|
|
|
@ -1,18 +1,4 @@
|
|||
vitastor (0.7.1-1) unstable; urgency=medium
|
||||
|
||||
* Bugfixes
|
||||
|
||||
-- Vitaliy Filippov <vitalif@yourcmc.ru> Fri, 03 Jun 2022 02:09:44 +0300
|
||||
|
||||
vitastor (0.7.1-1) unstable; urgency=medium
|
||||
|
||||
* Implement NFS proxy
|
||||
* Add documentation
|
||||
* Bugfixes
|
||||
|
||||
-- Vitaliy Filippov <vitalif@yourcmc.ru> Sun, 29 May 2022 23:39:13 +0300
|
||||
|
||||
vitastor (0.6.3-1) unstable; urgency=medium
|
||||
vitastor (0.6.17-1) unstable; urgency=medium
|
||||
|
||||
* RDMA support
|
||||
* Bugfixes
|
||||
|
|
|
@ -2,7 +2,7 @@ Source: vitastor
|
|||
Section: admin
|
||||
Priority: optional
|
||||
Maintainer: Vitaliy Filippov <vitalif@yourcmc.ru>
|
||||
Build-Depends: debhelper, liburing-dev (>= 0.6), g++ (>= 8), libstdc++6 (>= 8), linux-libc-dev, libgoogle-perftools-dev, libjerasure-dev, libgf-complete-dev, libibverbs-dev, libisal-dev
|
||||
Build-Depends: debhelper, liburing-dev (>= 0.6), g++ (>= 8), libstdc++6 (>= 8), linux-libc-dev, libgoogle-perftools-dev, libjerasure-dev, libgf-complete-dev, libibverbs-dev
|
||||
Standards-Version: 4.5.0
|
||||
Homepage: https://vitastor.io/
|
||||
Rules-Requires-Root: no
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
prefix=/usr
|
||||
exec_prefix=${prefix}
|
||||
libdir=${prefix}/lib/x86_64-linux-gnu
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: libisal
|
||||
Description: Library for storage systems
|
||||
Version: 2.30.0
|
||||
Libs: -L${libdir} -lisal
|
||||
Libs.private:
|
||||
Cflags: -I${includedir}
|
|
@ -1,3 +1,2 @@
|
|||
usr/bin/vitastor-osd
|
||||
usr/bin/vitastor-dump-journal
|
||||
usr/bin/vitastor-dump-meta
|
||||
|
|
|
@ -22,11 +22,10 @@ RUN apt-get update
|
|||
RUN apt-get -y install fio liburing1 liburing-dev libgoogle-perftools-dev devscripts
|
||||
RUN apt-get -y build-dep fio
|
||||
RUN apt-get --download-only source fio
|
||||
RUN apt-get update && apt-get -y install libjerasure-dev cmake libibverbs-dev libisal-dev
|
||||
RUN apt-get update && apt-get -y install libjerasure-dev cmake libibverbs-dev
|
||||
|
||||
ADD . /root/vitastor
|
||||
RUN set -e -x; \
|
||||
[ -e /usr/lib/x86_64-linux-gnu/pkgconfig/libisal.pc ] || cp /root/vitastor/debian/libisal.pc /usr/lib/x86_64-linux-gnu/pkgconfig; \
|
||||
mkdir -p /root/fio-build/; \
|
||||
cd /root/fio-build/; \
|
||||
rm -rf /root/fio-build/*; \
|
||||
|
@ -34,8 +33,8 @@ RUN set -e -x; \
|
|||
mkdir -p /root/packages/vitastor-$REL; \
|
||||
rm -rf /root/packages/vitastor-$REL/*; \
|
||||
cd /root/packages/vitastor-$REL; \
|
||||
cp -r /root/vitastor vitastor-0.7.1; \
|
||||
cd vitastor-0.7.1; \
|
||||
cp -r /root/vitastor vitastor-0.6.17; \
|
||||
cd vitastor-0.6.17; \
|
||||
ln -s /root/fio-build/fio-*/ ./fio; \
|
||||
FIO=$(head -n1 fio/debian/changelog | perl -pe 's/^.*\((.*?)\).*$/$1/'); \
|
||||
ls /usr/include/linux/raw.h || cp ./debian/raw.h /usr/include/linux/raw.h; \
|
||||
|
@ -48,8 +47,8 @@ RUN set -e -x; \
|
|||
rm -rf a b; \
|
||||
echo "dep:fio=$FIO" > debian/fio_version; \
|
||||
cd /root/packages/vitastor-$REL; \
|
||||
tar --sort=name --mtime='2020-01-01' --owner=0 --group=0 --exclude=debian -cJf vitastor_0.7.1.orig.tar.xz vitastor-0.7.1; \
|
||||
cd vitastor-0.7.1; \
|
||||
tar --sort=name --mtime='2020-01-01' --owner=0 --group=0 --exclude=debian -cJf vitastor_0.6.17.orig.tar.xz vitastor-0.6.17; \
|
||||
cd vitastor-0.6.17; \
|
||||
V=$(head -n1 debian/changelog | perl -pe 's/^.*\((.*?)\).*$/$1/'); \
|
||||
DEBFULLNAME="Vitaliy Filippov <vitalif@yourcmc.ru>" dch -D $REL -v "$V""$REL" "Rebuild for $REL"; \
|
||||
DEB_BUILD_OPTIONS=nocheck dpkg-buildpackage --jobs=auto -sa; \
|
||||
|
|
|
@ -23,7 +23,6 @@ initialization and can be changed with an OSD restart.
|
|||
- [no_rebalance](#no_rebalance)
|
||||
- [print_stats_interval](#print_stats_interval)
|
||||
- [slow_log_interval](#slow_log_interval)
|
||||
- [inode_vanish_time](#inode_vanish_time)
|
||||
- [max_write_iodepth](#max_write_iodepth)
|
||||
- [min_flusher_count](#min_flusher_count)
|
||||
- [max_flusher_count](#max_flusher_count)
|
||||
|
@ -164,13 +163,6 @@ Time interval at which OSDs dump slow or stuck operations on stdout, if
|
|||
they're any. Also it's the time after which an operation is considered
|
||||
"slow".
|
||||
|
||||
## inode_vanish_time
|
||||
|
||||
- Type: seconds
|
||||
- Default: 60
|
||||
|
||||
Number of seconds after which a deleted inode is removed from OSD statistics.
|
||||
|
||||
## max_write_iodepth
|
||||
|
||||
- Type: integer
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
- [no_rebalance](#no_rebalance)
|
||||
- [print_stats_interval](#print_stats_interval)
|
||||
- [slow_log_interval](#slow_log_interval)
|
||||
- [inode_vanish_time](#inode_vanish_time)
|
||||
- [max_write_iodepth](#max_write_iodepth)
|
||||
- [min_flusher_count](#min_flusher_count)
|
||||
- [max_flusher_count](#max_flusher_count)
|
||||
|
@ -170,13 +169,6 @@ OSD.
|
|||
медленных или зависших операций, если таковые имеются. Также время, при
|
||||
превышении которого операция считается "медленной".
|
||||
|
||||
## inode_vanish_time
|
||||
|
||||
- Тип: секунды
|
||||
- Значение по умолчанию: 60
|
||||
|
||||
Число секунд, через которое удалённые инод удаляется и из статистики OSD.
|
||||
|
||||
## max_write_iodepth
|
||||
|
||||
- Тип: целое число
|
||||
|
|
|
@ -106,12 +106,9 @@ Pool name.
|
|||
|
||||
- Type: string
|
||||
- Required
|
||||
- One of: "replicated", "xor", "ec" or "jerasure"
|
||||
- One of: "replicated", "xor" or "jerasure"
|
||||
|
||||
Redundancy scheme used for data in this pool. "jerasure" is an alias for "ec",
|
||||
both use Reed-Solomon-Vandermonde codes based on ISA-L or jerasure libraries.
|
||||
Fast ISA-L based implementation is used automatically when it's available,
|
||||
slower jerasure version is used otherwise.
|
||||
Redundancy scheme used for data in this pool.
|
||||
|
||||
## pg_size
|
||||
|
||||
|
@ -246,7 +243,7 @@ of the OSDs containing a data chunk for a PG.
|
|||
{
|
||||
"2": {
|
||||
"name":"ecpool",
|
||||
"scheme":"ec",
|
||||
"scheme":"jerasure",
|
||||
"pg_size":3,
|
||||
"parity_chunks":1,
|
||||
"pg_minsize":2,
|
||||
|
|
|
@ -106,13 +106,9 @@
|
|||
|
||||
- Тип: строка
|
||||
- Обязательный
|
||||
- Возможные значения: "replicated", "xor", "ec" или "jerasure"
|
||||
- Возможные значения: "replicated", "xor" или "jerasure"
|
||||
|
||||
Схема избыточности, используемая в данном пуле. "jerasure" - синоним для "ec",
|
||||
в обеих схемах используются коды Рида-Соломона-Вандермонда, реализованные на
|
||||
основе библиотек ISA-L или jerasure. Быстрая реализация на основе ISA-L
|
||||
используется автоматически, когда доступна, в противном случае используется
|
||||
более медленная jerasure-версия.
|
||||
Схема избыточности, используемая в данном пуле.
|
||||
|
||||
## pg_size
|
||||
|
||||
|
@ -246,7 +242,7 @@ PG в Vitastor эферемерны, то есть вы можете менят
|
|||
{
|
||||
"2": {
|
||||
"name":"ecpool",
|
||||
"scheme":"ec",
|
||||
"scheme":"jerasure",
|
||||
"pg_size":3,
|
||||
"parity_chunks":1,
|
||||
"pg_minsize":2,
|
||||
|
|
|
@ -158,13 +158,6 @@
|
|||
Временной интервал, с которым OSD выводят в стандартный вывод список
|
||||
медленных или зависших операций, если таковые имеются. Также время, при
|
||||
превышении которого операция считается "медленной".
|
||||
- name: inode_vanish_time
|
||||
type: sec
|
||||
default: 60
|
||||
info: |
|
||||
Number of seconds after which a deleted inode is removed from OSD statistics.
|
||||
info_ru: |
|
||||
Число секунд, через которое удалённые инод удаляется и из статистики OSD.
|
||||
- name: max_write_iodepth
|
||||
type: int
|
||||
default: 128
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
- gcc and g++ 8 or newer, clang 10 or newer, or other compiler with C++11 plus
|
||||
designated initializers support from C++20
|
||||
- CMake
|
||||
- liburing, jerasure headers and libraries
|
||||
- ISA-L, libibverbs headers and libraries (optional)
|
||||
- liburing, jerasure headers
|
||||
- tcmalloc (google-perftools-dev)
|
||||
|
||||
## Basic instructions
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
- gcc и g++ >= 8, либо clang >= 10, либо другой компилятор с поддержкой C++11 плюс
|
||||
назначенных инициализаторов (designated initializers) из C++20
|
||||
- CMake
|
||||
- Заголовки и библиотеки liburing, jerasure
|
||||
- Опционально - заголовки и библиотеки ISA-L, libibverbs
|
||||
- Заголовки liburing, jerasure
|
||||
- tcmalloc (google-perftools-dev)
|
||||
|
||||
## Базовая инструкция
|
||||
|
|
|
@ -33,5 +33,5 @@ Vitastor Network Public License 1.1, основанная на GNU GPL 3.0 с д
|
|||
и также на условиях GNU GPL 2.0 или более поздней версии. Так сделано в целях
|
||||
совместимости с таким ПО, как QEMU и fio.
|
||||
|
||||
Вы можете найти полный текст VNPL 1.1 на английском языке в файле [VNPL-1.1.txt](../../VNPL-1.1.txt),
|
||||
VNPL 1.1 на русском языке в файле [VNPL-1.1-RU.txt](../../VNPL-1.1-RU.txt), а GPL 2.0 в файле [GPL-2.0.txt](../../GPL-2.0.txt).
|
||||
Вы можете найти полный текст VNPL 1.1 в файле [VNPL-1.1.txt](../../VNPL-1.1.txt),
|
||||
а GPL 2.0 в файле [GPL-2.0.txt](../../GPL-2.0.txt).
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
- Basic part: highly-available block storage with symmetric clustering and no SPOF
|
||||
- [Performance](../performance/comparison1.en.md) ;-D
|
||||
- [Multiple redundancy schemes](../config/pool.en.md#scheme): Replication, XOR n+1, Reed-Solomon erasure codes
|
||||
based on jerasure and ISA-L libraries with any number of data and parity drives in a group
|
||||
based on jerasure library with any number of data and parity drives in a group
|
||||
- Configuration via simple JSON data structures in etcd (parameters, pools and images)
|
||||
- Automatic data distribution over OSDs, with support for:
|
||||
- Mathematical optimization for better uniformity and less data movement
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
- Базовая часть - надёжное кластерное блочное хранилище без единой точки отказа
|
||||
- [Производительность](../comparison1.ru.md) ;-D
|
||||
- [Несколько схем отказоустойчивости](../config/pool.ru.md#scheme): репликация, XOR n+1 (1 диск чётности), коды коррекции ошибок
|
||||
Рида-Соломона на основе библиотек jerasure и ISA-L с любым числом дисков данных и чётности в группе
|
||||
Рида-Соломона на основе библиотеки jerasure с любым числом дисков данных и чётности в группе
|
||||
- Конфигурация через простые человекочитаемые JSON-структуры в etcd
|
||||
- Автоматическое распределение данных по OSD, с поддержкой:
|
||||
- Математической оптимизации для лучшей равномерности распределения и минимизации перемещений данных
|
||||
|
|
|
@ -63,11 +63,11 @@ etcdctl --endpoints=... put /vitastor/config/pools '{"1":{"name":"testpool",
|
|||
"scheme":"replicated","pg_size":2,"pg_minsize":1,"pg_count":256,"failure_domain":"host"}}'
|
||||
```
|
||||
|
||||
For EC pools the configuration should look like the following:
|
||||
For jerasure pools the configuration should look like the following:
|
||||
|
||||
```
|
||||
etcdctl --endpoints=... put /vitastor/config/pools '{"2":{"name":"ecpool",
|
||||
"scheme":"ec","pg_size":4,"parity_chunks":2,"pg_minsize":2,"pg_count":256,"failure_domain":"host"}`
|
||||
"scheme":"jerasure","pg_size":4,"parity_chunks":2,"pg_minsize":2,"pg_count":256,"failure_domain":"host"}`
|
||||
```
|
||||
|
||||
After you do this, one of the monitors will configure PGs and OSDs will start them.
|
||||
|
|
|
@ -75,7 +75,7 @@ etcdctl --endpoints=... put /vitastor/config/pools '{"1":{"name":"testpool",
|
|||
|
||||
```
|
||||
etcdctl --endpoints=... put /vitastor/config/pools '{"2":{"name":"ecpool",
|
||||
"scheme":"ec","pg_size":4,"parity_chunks":2,"pg_minsize":2,"pg_count":256,"failure_domain":"host"}`
|
||||
"scheme":"jerasure","pg_size":4,"parity_chunks":2,"pg_minsize":2,"pg_count":256,"failure_domain":"host"}`
|
||||
```
|
||||
|
||||
После этого один из мониторов должен сконфигурировать PG, а OSD должны запустить их.
|
||||
|
|
|
@ -10,18 +10,25 @@ function add_pg_history(new_pg_history, new_pg, prev_pgs, prev_pg_history, old_p
|
|||
if (!new_pg_history[new_pg])
|
||||
{
|
||||
new_pg_history[new_pg] = {
|
||||
osd_sets: {},
|
||||
osd_set_epochs: {},
|
||||
all_peers: {},
|
||||
epoch: 0,
|
||||
};
|
||||
}
|
||||
const nh = new_pg_history[new_pg], oh = prev_pg_history[old_pg];
|
||||
nh.osd_sets[prev_pgs[old_pg].join(' ')] = prev_pgs[old_pg];
|
||||
nh.osd_set_epochs[prev_pgs[old_pg].join(' ')] = { osd_set: prev_pgs[old_pg] };
|
||||
if (oh && oh.osd_sets && oh.osd_sets.length)
|
||||
{
|
||||
for (const pg of oh.osd_sets)
|
||||
{
|
||||
nh.osd_sets[pg.join(' ')] = pg;
|
||||
nh.osd_set_epochs[pg.join(' ')] = { osd_set: pg };
|
||||
}
|
||||
}
|
||||
if (oh && oh.osd_set_epochs && oh.osd_set_epochs.length)
|
||||
{
|
||||
for (const pg of oh.osd_set_epochs)
|
||||
{
|
||||
nh.osd_set_epochs[pg.osd_set.join(' ')] = { osd_set: pg.osd_set };
|
||||
}
|
||||
}
|
||||
if (oh && oh.all_peers && oh.all_peers.length)
|
||||
|
@ -39,7 +46,7 @@ function add_pg_history(new_pg_history, new_pg, prev_pgs, prev_pg_history, old_p
|
|||
|
||||
function finish_pg_history(merged_history)
|
||||
{
|
||||
merged_history.osd_sets = Object.values(merged_history.osd_sets);
|
||||
merged_history.osd_set_epochs = Object.values(merged_history.osd_set_epochs);
|
||||
merged_history.all_peers = Object.values(merged_history.all_peers);
|
||||
}
|
||||
|
||||
|
|
40
mon/mon.js
40
mon/mon.js
|
@ -105,7 +105,6 @@ const etcd_tree = {
|
|||
no_rebalance: false,
|
||||
print_stats_interval: 3,
|
||||
slow_log_interval: 10,
|
||||
inode_vanish_time: 60,
|
||||
osd_memlock: false,
|
||||
// blockstore - fixed in superblock
|
||||
block_size,
|
||||
|
@ -148,11 +147,11 @@ const etcd_tree = {
|
|||
/* pools: {
|
||||
<id>: {
|
||||
name: 'testpool',
|
||||
// 'ec' uses Reed-Solomon-Vandermonde codes, 'jerasure' is an alias for 'ec'
|
||||
scheme: 'replicated' | 'xor' | 'ec' | 'jerasure',
|
||||
// jerasure uses Reed-Solomon-Vandermonde codes
|
||||
scheme: 'replicated' | 'xor' | 'jerasure',
|
||||
pg_size: 3,
|
||||
pg_minsize: 2,
|
||||
// number of parity chunks, required for EC
|
||||
// number of parity chunks, required for jerasure
|
||||
parity_chunks?: 1,
|
||||
pg_count: 100,
|
||||
failure_domain: 'host',
|
||||
|
@ -277,7 +276,12 @@ const etcd_tree = {
|
|||
history: {
|
||||
/* <pool_id>: {
|
||||
<pg_id>: {
|
||||
osd_sets: osd_num_t[][],
|
||||
osd_set_epochs: {
|
||||
osd_set: osd_num_t[],
|
||||
min_epoch: uint64_t,
|
||||
max_epoch: uint64_t,
|
||||
}[],
|
||||
osd_sets: osd_num_t[][], // outdated
|
||||
all_peers: osd_num_t[],
|
||||
epoch: uint64_t,
|
||||
},
|
||||
|
@ -948,18 +952,6 @@ class Mon
|
|||
osd_set,
|
||||
primary: this.pick_primary(pool_id, osd_set, up_osds, aff_osds),
|
||||
};
|
||||
if (prev_pgs[i] && prev_pgs[i].join(' ') != osd_set.join(' ') &&
|
||||
prev_pgs[i].filter(osd_num => osd_num).length > 0)
|
||||
{
|
||||
pg_history[i] = pg_history[i] || {};
|
||||
pg_history[i].osd_sets = pg_history[i].osd_sets || [];
|
||||
pg_history[i].osd_sets.push(prev_pgs[i]);
|
||||
}
|
||||
if (pg_history[i] && pg_history[i].osd_sets)
|
||||
{
|
||||
pg_history[i].osd_sets = Object.values(pg_history[i].osd_sets
|
||||
.reduce((a, c) => { a[c.join(' ')] = c; return a; }, {}));
|
||||
}
|
||||
});
|
||||
for (let i = 0; i < new_pgs.length || i < prev_pgs.length; i++)
|
||||
{
|
||||
|
@ -1014,15 +1006,14 @@ class Mon
|
|||
console.log('Pool ID '+pool_id+' is invalid');
|
||||
return false;
|
||||
}
|
||||
if (pool_cfg.scheme !== 'xor' && pool_cfg.scheme !== 'replicated' &&
|
||||
pool_cfg.scheme !== 'ec' && pool_cfg.scheme !== 'jerasure')
|
||||
if (pool_cfg.scheme !== 'xor' && pool_cfg.scheme !== 'replicated' && pool_cfg.scheme !== 'jerasure')
|
||||
{
|
||||
if (warn)
|
||||
console.log('Pool '+pool_id+' has invalid coding scheme (one of "xor", "replicated", "ec" and "jerasure" required)');
|
||||
console.log('Pool '+pool_id+' has invalid coding scheme (one of "xor", "replicated" and "jerasure" required)');
|
||||
return false;
|
||||
}
|
||||
if (!pool_cfg.pg_size || pool_cfg.pg_size < 1 || pool_cfg.pg_size > 256 ||
|
||||
pool_cfg.scheme !== 'replicated' && pool_cfg.pg_size < 3)
|
||||
(pool_cfg.scheme === 'xor' || pool_cfg.scheme == 'jerasure') && pool_cfg.pg_size < 3)
|
||||
{
|
||||
if (warn)
|
||||
console.log('Pool '+pool_id+' has invalid pg_size');
|
||||
|
@ -1041,8 +1032,7 @@ class Mon
|
|||
console.log('Pool '+pool_id+' has invalid parity_chunks (must be 1)');
|
||||
return false;
|
||||
}
|
||||
if ((pool_cfg.scheme === 'ec' || pool_cfg.scheme === 'jerasure') &&
|
||||
(pool_cfg.parity_chunks < 1 || pool_cfg.parity_chunks > pool_cfg.pg_size-2))
|
||||
if (pool_cfg.scheme === 'jerasure' && (pool_cfg.parity_chunks < 1 || pool_cfg.parity_chunks > pool_cfg.pg_size-2))
|
||||
{
|
||||
if (warn)
|
||||
console.log('Pool '+pool_id+' has invalid parity_chunks (must be between 1 and pg_size-2)');
|
||||
|
@ -1156,10 +1146,6 @@ class Mon
|
|||
{
|
||||
prev_pgs[pg-1] = this.state.config.pgs.items[pool_id][pg].osd_set;
|
||||
}
|
||||
// Also delete pool statistics
|
||||
etcd_request.success.push({ requestDeleteRange: {
|
||||
key: b64(this.etcd_prefix+'/pool/stats/'+pool_id),
|
||||
} });
|
||||
this.save_new_pgs_txn(etcd_request, pool_id, up_osds, osd_tree, prev_pgs, [], []);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ from cinder.volume import configuration
|
|||
from cinder.volume import driver
|
||||
from cinder.volume import volume_utils
|
||||
|
||||
VERSION = '0.7.1'
|
||||
VERSION = '0.6.17'
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
@ -464,7 +464,7 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||
vol_name = utils.convert_str(volume.name)
|
||||
snap_name = utils.convert_str(snapshot.name)
|
||||
|
||||
snap = self._get_image('volume-'+snapshot.volume_id+'@'+snap_name)
|
||||
snap = self._get_image(vol_name+'@'+snap_name)
|
||||
if not snap:
|
||||
raise exception.SnapshotNotFound(snapshot_id = snap_name)
|
||||
snap_inode_id = int(resp['responses'][0]['kvs'][0]['value']['id'])
|
||||
|
|
|
@ -25,4 +25,4 @@ rm fio
|
|||
mv fio-copy fio
|
||||
FIO=`rpm -qi fio | perl -e 'while(<>) { /^Epoch[\s:]+(\S+)/ && print "$1:"; /^Version[\s:]+(\S+)/ && print $1; /^Release[\s:]+(\S+)/ && print "-$1"; }'`
|
||||
perl -i -pe 's/(Requires:\s*fio)([^\n]+)?/$1 = '$FIO'/' $VITASTOR/rpm/vitastor-el$EL.spec
|
||||
tar --transform 's#^#vitastor-0.7.1/#' --exclude 'rpm/*.rpm' -czf $VITASTOR/../vitastor-0.7.1$(rpm --eval '%dist').tar.gz *
|
||||
tar --transform 's#^#vitastor-0.6.17/#' --exclude 'rpm/*.rpm' -czf $VITASTOR/../vitastor-0.6.17$(rpm --eval '%dist').tar.gz *
|
||||
|
|
|
@ -9,8 +9,7 @@ WORKDIR /root
|
|||
RUN rm -f /etc/yum.repos.d/CentOS-Media.repo
|
||||
RUN yum -y --enablerepo=extras install centos-release-scl epel-release yum-utils rpm-build
|
||||
RUN yum -y install https://vitastor.io/rpms/centos/7/vitastor-release-1.0-1.el7.noarch.rpm
|
||||
RUN yum -y install devtoolset-9-gcc-c++ devtoolset-9-libatomic-devel gcc make cmake gperftools-devel \
|
||||
fio rh-nodejs12 jerasure-devel libisa-l-devel gf-complete-devel rdma-core-devel
|
||||
RUN yum -y install devtoolset-9-gcc-c++ devtoolset-9-libatomic-devel gcc make cmake gperftools-devel fio rh-nodejs12 jerasure-devel gf-complete-devel rdma-core-devel
|
||||
RUN yumdownloader --disablerepo=centos-sclo-rh --source fio
|
||||
RUN rpm --nomd5 -i fio*.src.rpm
|
||||
RUN rm -f /etc/yum.repos.d/CentOS-Media.repo
|
||||
|
@ -35,7 +34,7 @@ ADD . /root/vitastor
|
|||
RUN set -e; \
|
||||
cd /root/vitastor/rpm; \
|
||||
sh build-tarball.sh; \
|
||||
cp /root/vitastor-0.7.1.el7.tar.gz ~/rpmbuild/SOURCES; \
|
||||
cp /root/vitastor-0.6.17.el7.tar.gz ~/rpmbuild/SOURCES; \
|
||||
cp vitastor-el7.spec ~/rpmbuild/SPECS/vitastor.spec; \
|
||||
cd ~/rpmbuild/SPECS/; \
|
||||
rpmbuild -ba vitastor.spec; \
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
Name: vitastor
|
||||
Version: 0.7.1
|
||||
Version: 0.6.17
|
||||
Release: 1%{?dist}
|
||||
Summary: Vitastor, a fast software-defined clustered block storage
|
||||
|
||||
License: Vitastor Network Public License 1.1
|
||||
URL: https://vitastor.io/
|
||||
Source0: vitastor-0.7.1.el7.tar.gz
|
||||
Source0: vitastor-0.6.17.el7.tar.gz
|
||||
|
||||
BuildRequires: liburing-devel >= 0.6
|
||||
BuildRequires: gperftools-devel
|
||||
|
@ -13,7 +13,6 @@ BuildRequires: devtoolset-9-gcc-c++
|
|||
BuildRequires: rh-nodejs12
|
||||
BuildRequires: rh-nodejs12-npm
|
||||
BuildRequires: jerasure-devel
|
||||
BuildRequires: libisa-l-devel
|
||||
BuildRequires: gf-complete-devel
|
||||
BuildRequires: libibverbs-devel
|
||||
BuildRequires: cmake
|
||||
|
@ -33,7 +32,6 @@ size with configurable redundancy (replication or erasure codes/XOR).
|
|||
%package -n vitastor-osd
|
||||
Summary: Vitastor - OSD
|
||||
Requires: libJerasure2
|
||||
Requires: libisa-l
|
||||
Requires: liburing >= 0.6
|
||||
Requires: vitastor-client = %{version}-%{release}
|
||||
|
||||
|
@ -113,7 +111,6 @@ cp -r mon %buildroot/usr/lib/vitastor
|
|||
%files -n vitastor-osd
|
||||
%_bindir/vitastor-osd
|
||||
%_bindir/vitastor-dump-journal
|
||||
%_bindir/vitastor-dump-meta
|
||||
|
||||
|
||||
%files -n vitastor-mon
|
||||
|
|
|
@ -6,12 +6,10 @@ FROM centos:8
|
|||
WORKDIR /root
|
||||
|
||||
RUN rm -f /etc/yum.repos.d/CentOS-Media.repo
|
||||
RUN sed -i 's/^mirrorlist=/#mirrorlist=/; s!#baseurl=http://mirror.centos.org/!baseurl=http://vault.centos.org/!' /etc/yum.repos.d/*.repo
|
||||
RUN dnf -y install centos-release-advanced-virtualization epel-release dnf-plugins-core
|
||||
RUN sed -i 's/^mirrorlist=/#mirrorlist=/; s!#baseurl=.*!baseurl=http://vault.centos.org/centos/8.4.2105/virt/$basearch/$avdir/!; s!^baseurl=.*Source/.*!baseurl=http://vault.centos.org/centos/8.4.2105/virt/Source/advanced-virtualization/!' /etc/yum.repos.d/CentOS-Advanced-Virtualization.repo
|
||||
RUN yum -y install https://vitastor.io/rpms/centos/8/vitastor-release-1.0-1.el8.noarch.rpm
|
||||
RUN dnf -y install gcc-toolset-9 gcc-toolset-9-gcc-c++ gperftools-devel \
|
||||
fio nodejs rpm-build jerasure-devel libisa-l-devel gf-complete-devel libibverbs-devel libarchive cmake
|
||||
fio nodejs rpm-build jerasure-devel gf-complete-devel libibverbs-devel libarchive cmake
|
||||
RUN dnf download --source fio
|
||||
RUN rpm --nomd5 -i fio*.src.rpm
|
||||
RUN cd ~/rpmbuild/SPECS && dnf builddep -y --enablerepo=powertools --spec fio.spec
|
||||
|
@ -35,7 +33,7 @@ ADD . /root/vitastor
|
|||
RUN set -e; \
|
||||
cd /root/vitastor/rpm; \
|
||||
sh build-tarball.sh; \
|
||||
cp /root/vitastor-0.7.1.el8.tar.gz ~/rpmbuild/SOURCES; \
|
||||
cp /root/vitastor-0.6.17.el8.tar.gz ~/rpmbuild/SOURCES; \
|
||||
cp vitastor-el8.spec ~/rpmbuild/SPECS/vitastor.spec; \
|
||||
cd ~/rpmbuild/SPECS/; \
|
||||
rpmbuild -ba vitastor.spec; \
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
Name: vitastor
|
||||
Version: 0.7.1
|
||||
Version: 0.6.17
|
||||
Release: 1%{?dist}
|
||||
Summary: Vitastor, a fast software-defined clustered block storage
|
||||
|
||||
License: Vitastor Network Public License 1.1
|
||||
URL: https://vitastor.io/
|
||||
Source0: vitastor-0.7.1.el8.tar.gz
|
||||
Source0: vitastor-0.6.17.el8.tar.gz
|
||||
|
||||
BuildRequires: liburing-devel >= 0.6
|
||||
BuildRequires: gperftools-devel
|
||||
BuildRequires: gcc-toolset-9-gcc-c++
|
||||
BuildRequires: nodejs >= 10
|
||||
BuildRequires: jerasure-devel
|
||||
BuildRequires: libisa-l-devel
|
||||
BuildRequires: gf-complete-devel
|
||||
BuildRequires: libibverbs-devel
|
||||
BuildRequires: cmake
|
||||
|
@ -32,7 +31,6 @@ size with configurable redundancy (replication or erasure codes/XOR).
|
|||
%package -n vitastor-osd
|
||||
Summary: Vitastor - OSD
|
||||
Requires: libJerasure2
|
||||
Requires: libisa-l
|
||||
Requires: liburing >= 0.6
|
||||
Requires: vitastor-client = %{version}-%{release}
|
||||
|
||||
|
@ -110,7 +108,6 @@ cp -r mon %buildroot/usr/lib/vitastor
|
|||
%files -n vitastor-osd
|
||||
%_bindir/vitastor-osd
|
||||
%_bindir/vitastor-dump-journal
|
||||
%_bindir/vitastor-dump-meta
|
||||
|
||||
|
||||
%files -n vitastor-mon
|
||||
|
|
|
@ -15,7 +15,7 @@ if("${CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/local/?$")
|
|||
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
|
||||
endif()
|
||||
|
||||
add_definitions(-DVERSION="0.7.1")
|
||||
add_definitions(-DVERSION="0.6.17")
|
||||
add_definitions(-Wall -Wno-sign-compare -Wno-comment -Wno-parentheses -Wno-pointer-arith -fdiagnostics-color=always -I ${CMAKE_SOURCE_DIR}/src)
|
||||
if (${WITH_ASAN})
|
||||
add_definitions(-fsanitize=address -fno-omit-frame-pointer)
|
||||
|
@ -50,10 +50,6 @@ pkg_check_modules(IBVERBS libibverbs)
|
|||
if (IBVERBS_LIBRARIES)
|
||||
add_definitions(-DWITH_RDMA)
|
||||
endif (IBVERBS_LIBRARIES)
|
||||
pkg_check_modules(ISAL libisal)
|
||||
if (ISAL_LIBRARIES)
|
||||
add_definitions(-DWITH_ISAL)
|
||||
endif (ISAL_LIBRARIES)
|
||||
|
||||
include_directories(
|
||||
../
|
||||
|
@ -108,7 +104,6 @@ target_link_libraries(vitastor-osd
|
|||
vitastor_common
|
||||
vitastor_blk
|
||||
Jerasure
|
||||
${ISAL_LIBRARIES}
|
||||
${IBVERBS_LIBRARIES}
|
||||
)
|
||||
|
||||
|
@ -198,11 +193,6 @@ add_executable(vitastor-dump-journal
|
|||
dump_journal.cpp crc32c.c
|
||||
)
|
||||
|
||||
# vitastor-dump-meta
|
||||
add_executable(vitastor-dump-meta
|
||||
dump_meta.cpp rw_blocking.cpp
|
||||
)
|
||||
|
||||
if (${WITH_QEMU})
|
||||
# qemu_driver.so
|
||||
add_library(qemu_vitastor SHARED
|
||||
|
@ -235,7 +225,7 @@ target_link_libraries(osd_test tcmalloc_minimal)
|
|||
|
||||
# osd_rmw_test
|
||||
add_executable(osd_rmw_test osd_rmw_test.cpp allocator.cpp)
|
||||
target_link_libraries(osd_rmw_test Jerasure ${ISAL_LIBRARIES} tcmalloc_minimal)
|
||||
target_link_libraries(osd_rmw_test Jerasure tcmalloc_minimal)
|
||||
|
||||
# stub_uring_osd
|
||||
add_executable(stub_uring_osd
|
||||
|
@ -280,7 +270,7 @@ target_include_directories(test_cluster_client PUBLIC ${CMAKE_SOURCE_DIR}/src/mo
|
|||
|
||||
### Install
|
||||
|
||||
install(TARGETS vitastor-osd vitastor-dump-journal vitastor-dump-meta vitastor-nbd vitastor-nfs vitastor-cli RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install(TARGETS vitastor-osd vitastor-dump-journal vitastor-nbd vitastor-nfs vitastor-cli RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install_symlink(vitastor-cli ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/vitastor-rm)
|
||||
install_symlink(vitastor-cli ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/vita)
|
||||
install(
|
||||
|
|
|
@ -19,11 +19,7 @@
|
|||
#include "timerfd_manager.h"
|
||||
|
||||
// Memory alignment for direct I/O (usually 512 bytes)
|
||||
#ifndef DIRECT_IO_ALIGNMENT
|
||||
#define DIRECT_IO_ALIGNMENT 512
|
||||
#endif
|
||||
|
||||
// Memory allocation alignment (page size is usually optimal)
|
||||
// All other alignments must be a multiple of this one
|
||||
#ifndef MEM_ALIGNMENT
|
||||
#define MEM_ALIGNMENT 4096
|
||||
#endif
|
||||
|
|
|
@ -90,13 +90,13 @@
|
|||
#include "blockstore_journal.h"
|
||||
|
||||
// "VITAstor"
|
||||
#define BLOCKSTORE_META_MAGIC_V1 0x726F747341544956l
|
||||
#define BLOCKSTORE_META_VERSION_V1 1
|
||||
#define BLOCKSTORE_META_MAGIC 0x726F747341544956l
|
||||
#define BLOCKSTORE_META_VERSION 1
|
||||
|
||||
// metadata header (superblock)
|
||||
// FIXME: After adding the OSD superblock, add a key to metadata
|
||||
// and journal headers to check if they belong to the same OSD
|
||||
struct __attribute__((__packed__)) blockstore_meta_header_v1_t
|
||||
struct __attribute__((__packed__)) blockstore_meta_header_t
|
||||
{
|
||||
uint64_t zero;
|
||||
uint64_t magic;
|
||||
|
|
|
@ -71,10 +71,10 @@ resume_1:
|
|||
if (iszero((uint64_t*)metadata_buffer, bs->meta_block_size / sizeof(uint64_t)))
|
||||
{
|
||||
{
|
||||
blockstore_meta_header_v1_t *hdr = (blockstore_meta_header_v1_t *)metadata_buffer;
|
||||
blockstore_meta_header_t *hdr = (blockstore_meta_header_t *)metadata_buffer;
|
||||
hdr->zero = 0;
|
||||
hdr->magic = BLOCKSTORE_META_MAGIC_V1;
|
||||
hdr->version = BLOCKSTORE_META_VERSION_V1;
|
||||
hdr->magic = BLOCKSTORE_META_MAGIC;
|
||||
hdr->version = BLOCKSTORE_META_VERSION;
|
||||
hdr->meta_block_size = bs->meta_block_size;
|
||||
hdr->data_block_size = bs->block_size;
|
||||
hdr->bitmap_granularity = bs->bitmap_granularity;
|
||||
|
@ -103,10 +103,10 @@ resume_1:
|
|||
}
|
||||
else
|
||||
{
|
||||
blockstore_meta_header_v1_t *hdr = (blockstore_meta_header_v1_t *)metadata_buffer;
|
||||
blockstore_meta_header_t *hdr = (blockstore_meta_header_t *)metadata_buffer;
|
||||
if (hdr->zero != 0 ||
|
||||
hdr->magic != BLOCKSTORE_META_MAGIC_V1 ||
|
||||
hdr->version != BLOCKSTORE_META_VERSION_V1)
|
||||
hdr->magic != BLOCKSTORE_META_MAGIC ||
|
||||
hdr->version != BLOCKSTORE_META_VERSION)
|
||||
{
|
||||
printf(
|
||||
"Metadata is corrupt or old version.\n"
|
||||
|
@ -912,11 +912,7 @@ void blockstore_init_journal::erase_dirty_object(blockstore_dirty_db_t::iterator
|
|||
? clean_it->second.location : UINT64_MAX;
|
||||
if (exists && clean_loc == UINT64_MAX)
|
||||
{
|
||||
auto & sp = bs->inode_space_stats[oid.inode];
|
||||
if (sp > bs->block_size)
|
||||
sp -= bs->block_size;
|
||||
else
|
||||
bs->inode_space_stats.erase(oid.inode);
|
||||
bs->inode_space_stats[oid.inode] -= bs->block_size;
|
||||
}
|
||||
bs->erase_dirty(dirty_it, dirty_end, clean_loc);
|
||||
// Remove it from the flusher's queue, too
|
||||
|
|
|
@ -109,25 +109,25 @@ void blockstore_impl_t::parse_config(blockstore_config_t & config)
|
|||
{
|
||||
disk_alignment = 4096;
|
||||
}
|
||||
else if (disk_alignment % DIRECT_IO_ALIGNMENT)
|
||||
else if (disk_alignment % MEM_ALIGNMENT)
|
||||
{
|
||||
throw std::runtime_error("disk_alignment must be a multiple of "+std::to_string(DIRECT_IO_ALIGNMENT));
|
||||
throw std::runtime_error("disk_alignment must be a multiple of "+std::to_string(MEM_ALIGNMENT));
|
||||
}
|
||||
if (!journal_block_size)
|
||||
{
|
||||
journal_block_size = 4096;
|
||||
}
|
||||
else if (journal_block_size % DIRECT_IO_ALIGNMENT)
|
||||
else if (journal_block_size % MEM_ALIGNMENT)
|
||||
{
|
||||
throw std::runtime_error("journal_block_size must be a multiple of "+std::to_string(DIRECT_IO_ALIGNMENT));
|
||||
throw std::runtime_error("journal_block_size must be a multiple of "+std::to_string(MEM_ALIGNMENT));
|
||||
}
|
||||
if (!meta_block_size)
|
||||
{
|
||||
meta_block_size = 4096;
|
||||
}
|
||||
else if (meta_block_size % DIRECT_IO_ALIGNMENT)
|
||||
else if (meta_block_size % MEM_ALIGNMENT)
|
||||
{
|
||||
throw std::runtime_error("meta_block_size must be a multiple of "+std::to_string(DIRECT_IO_ALIGNMENT));
|
||||
throw std::runtime_error("meta_block_size must be a multiple of "+std::to_string(MEM_ALIGNMENT));
|
||||
}
|
||||
if (data_offset % disk_alignment)
|
||||
{
|
||||
|
|
|
@ -200,11 +200,7 @@ void blockstore_impl_t::mark_stable(const obj_ver_id & v, bool forget_dirty)
|
|||
}
|
||||
else if (IS_DELETE(dirty_it->second.state))
|
||||
{
|
||||
auto & sp = inode_space_stats[dirty_it->first.oid.inode];
|
||||
if (sp > block_size)
|
||||
sp -= block_size;
|
||||
else
|
||||
inode_space_stats.erase(dirty_it->first.oid.inode);
|
||||
inode_space_stats[dirty_it->first.oid.inode] -= block_size;
|
||||
}
|
||||
}
|
||||
if (forget_dirty && (IS_BIG_WRITE(dirty_it->second.state) ||
|
||||
|
|
|
@ -39,7 +39,6 @@ public:
|
|||
ring_loop_t *ringloop = NULL;
|
||||
epoll_manager_t *epmgr = NULL;
|
||||
cluster_client_t *cli = NULL;
|
||||
bool no_recovery = false, no_rebalance = false, readonly = false;
|
||||
|
||||
int waiting = 0;
|
||||
cli_result_t etcd_err;
|
||||
|
|
|
@ -276,8 +276,7 @@ resume_4:
|
|||
new_id = 1+INODE_NO_POOL(kv.value.uint64_value());
|
||||
max_id_mod_rev = kv.mod_revision;
|
||||
}
|
||||
// Also check existing inodes - for the case when some inodes are created without changing /index/maxid
|
||||
auto ino_it = parent->cli->st_cli.inode_config.lower_bound(INODE_WITH_POOL(new_pool_id+1, 0));
|
||||
auto ino_it = parent->cli->st_cli.inode_config.lower_bound(INODE_WITH_POOL(new_pool_id, 0));
|
||||
if (ino_it != parent->cli->st_cli.inode_config.begin())
|
||||
{
|
||||
ino_it--;
|
||||
|
|
|
@ -127,7 +127,7 @@ resume_1:
|
|||
pool_stats[pool_cfg.id] = json11::Json::object {
|
||||
{ "name", pool_cfg.name },
|
||||
{ "pg_count", pool_cfg.pg_count },
|
||||
{ "scheme", pool_cfg.scheme == POOL_SCHEME_REPLICATED ? "replicated" : "ec" },
|
||||
{ "scheme", pool_cfg.scheme == POOL_SCHEME_REPLICATED ? "replicated" : "jerasure" },
|
||||
{ "scheme_name", pool_cfg.scheme == POOL_SCHEME_REPLICATED
|
||||
? std::to_string(pool_cfg.pg_size)+"/"+std::to_string(pool_cfg.pg_minsize)
|
||||
: "EC "+std::to_string(pool_cfg.pg_size-pool_cfg.parity_chunks)+"+"+std::to_string(pool_cfg.parity_chunks) },
|
||||
|
|
|
@ -64,9 +64,8 @@ struct rm_inode_t
|
|||
}
|
||||
rm->obj_pos = rm->objects.begin();
|
||||
lists.push_back(rm);
|
||||
if (parent->list_first && !(status & INODE_LIST_DONE))
|
||||
if (parent->list_first)
|
||||
{
|
||||
// The listing object is dead when DONE => don't call next()
|
||||
parent->cli->list_inode_next(lister, 1);
|
||||
}
|
||||
if (status & INODE_LIST_DONE)
|
||||
|
|
|
@ -14,11 +14,6 @@
|
|||
std::function<bool(cli_result_t &)> cli_tool_t::simple_offsets(json11::Json cfg)
|
||||
{
|
||||
std::string device = cfg["device"].string_value();
|
||||
if (device == "")
|
||||
{
|
||||
fprintf(stderr, "Device path is missing\n");
|
||||
exit(1);
|
||||
}
|
||||
uint64_t object_size = parse_size(cfg["object_size"].string_value());
|
||||
uint64_t bitmap_granularity = parse_size(cfg["bitmap_granularity"].string_value());
|
||||
uint64_t journal_size = parse_size(cfg["journal_size"].string_value());
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#include "cluster_client.h"
|
||||
#include "base64.h"
|
||||
#include "pg_states.h"
|
||||
#include "http_client.h"
|
||||
|
||||
// Print cluster status:
|
||||
// etcd, mon, osd states
|
||||
|
@ -208,9 +207,6 @@ resume_2:
|
|||
obj_n = agg_stats["object_counts"]["incomplete"].uint64_value();
|
||||
if (obj_n > 0)
|
||||
more_states += ", "+format_size(obj_n*object_size)+" incomplete";
|
||||
bool readonly = json_is_true(parent->cli->merged_config["readonly"]);
|
||||
bool no_recovery = json_is_true(parent->cli->merged_config["no_recovery"]);
|
||||
bool no_rebalance = json_is_true(parent->cli->merged_config["no_rebalance"]);
|
||||
std::string recovery_io;
|
||||
{
|
||||
uint64_t deg_bps = agg_stats["recovery_stats"]["degraded"]["bps"].uint64_value();
|
||||
|
@ -218,19 +214,9 @@ resume_2:
|
|||
uint64_t misp_bps = agg_stats["recovery_stats"]["misplaced"]["bps"].uint64_value();
|
||||
uint64_t misp_iops = agg_stats["recovery_stats"]["misplaced"]["iops"].uint64_value();
|
||||
if (deg_iops > 0 || deg_bps > 0)
|
||||
{
|
||||
recovery_io += " recovery: "+std::string(no_recovery ? "disabled, " : "")+
|
||||
format_size(deg_bps)+"/s, "+format_size(deg_iops, true)+" op/s\n";
|
||||
}
|
||||
else if (no_recovery)
|
||||
recovery_io += " recovery: disabled\n";
|
||||
recovery_io += " recovery: "+format_size(deg_bps)+"/s, "+format_size(deg_iops, true)+" op/s\n";
|
||||
if (misp_iops > 0 || misp_bps > 0)
|
||||
{
|
||||
recovery_io += " rebalance: "+std::string(no_rebalance ? "disabled, " : "")+
|
||||
format_size(misp_bps)+"/s, "+format_size(misp_iops, true)+" op/s\n";
|
||||
}
|
||||
else if (no_rebalance)
|
||||
recovery_io += " rebalance: disabled\n";
|
||||
recovery_io += " rebalance: "+format_size(misp_bps)+"/s, "+format_size(misp_iops, true)+" op/s\n";
|
||||
}
|
||||
if (parent->json_output)
|
||||
{
|
||||
|
@ -247,9 +233,6 @@ resume_2:
|
|||
{ "free_raw", free_raw },
|
||||
{ "down_raw", down_raw },
|
||||
{ "free_down_raw", free_down_raw },
|
||||
{ "readonly", readonly },
|
||||
{ "no_recovery", no_recovery },
|
||||
{ "no_rebalance", no_rebalance },
|
||||
{ "clean_data", agg_stats["object_counts"]["clean"].uint64_value() * object_size },
|
||||
{ "misplaced_data", agg_stats["object_counts"]["misplaced"].uint64_value() * object_size },
|
||||
{ "degraded_data", agg_stats["object_counts"]["degraded"].uint64_value() * object_size },
|
||||
|
@ -276,7 +259,7 @@ resume_2:
|
|||
" pools: %d / %d active\n"
|
||||
" pgs: %s\n"
|
||||
" \n"
|
||||
" io%s:\n"
|
||||
" io:\n"
|
||||
" client:%s %s/s rd, %s op/s rd, %s/s wr, %s op/s wr\n"
|
||||
"%s",
|
||||
etcd_alive, etcd_states.size(), format_size(etcd_db_size).c_str(),
|
||||
|
@ -289,7 +272,6 @@ resume_2:
|
|||
format_size(agg_stats["object_counts"]["clean"].uint64_value() * object_size).c_str(), more_states.c_str(),
|
||||
pools_active, pool_count,
|
||||
pgs_by_state_str.c_str(),
|
||||
readonly ? " (read-only mode)" : "",
|
||||
recovery_io.size() > 0 ? " " : "",
|
||||
format_size(agg_stats["op_stats"]["primary_read"]["bps"].uint64_value()).c_str(),
|
||||
format_size(agg_stats["op_stats"]["primary_read"]["iops"].uint64_value(), true).c_str(),
|
||||
|
|
|
@ -279,11 +279,6 @@ static uint32_t is_power_of_two(uint64_t value)
|
|||
|
||||
void cluster_client_t::on_load_config_hook(json11::Json::object & config)
|
||||
{
|
||||
this->merged_config = config;
|
||||
for (auto & kv: this->config.object_items())
|
||||
{
|
||||
this->merged_config[kv.first] = kv.second;
|
||||
}
|
||||
bs_block_size = config["block_size"].uint64_value();
|
||||
bs_bitmap_granularity = config["bitmap_granularity"].uint64_value();
|
||||
if (!bs_block_size)
|
||||
|
|
|
@ -111,7 +111,6 @@ public:
|
|||
etcd_state_client_t st_cli;
|
||||
osd_messenger_t msgr;
|
||||
json11::Json config;
|
||||
json11::Json::object merged_config;
|
||||
|
||||
cluster_client_t(ring_loop_t *ringloop, timerfd_manager_t *tfd, json11::Json & config);
|
||||
~cluster_client_t();
|
||||
|
|
|
@ -95,7 +95,7 @@ inode_list_t* cluster_client_t::list_inode_start(inode_t inode,
|
|||
}
|
||||
for (auto & hist_item: pg.target_history)
|
||||
{
|
||||
for (auto pg_osd: hist_item)
|
||||
for (auto pg_osd: hist_item.osd_set)
|
||||
{
|
||||
if (pg_osd != 0)
|
||||
{
|
||||
|
@ -105,11 +105,14 @@ inode_list_t* cluster_client_t::list_inode_start(inode_t inode,
|
|||
}
|
||||
for (osd_num_t peer_osd: all_peers)
|
||||
{
|
||||
r->list_osds.push_back((inode_list_osd_t){
|
||||
.pg = r,
|
||||
.osd_num = peer_osd,
|
||||
.sent = false,
|
||||
});
|
||||
if (st_cli.peer_states.find(peer_osd) != st_cli.peer_states.end())
|
||||
{
|
||||
r->list_osds.push_back((inode_list_osd_t){
|
||||
.pg = r,
|
||||
.osd_num = peer_osd,
|
||||
.sent = false,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -153,6 +156,16 @@ void cluster_client_t::continue_listing(inode_list_t *lst)
|
|||
{
|
||||
if (lst->done_pgs >= lst->pgs.size())
|
||||
{
|
||||
// All done
|
||||
for (int i = 0; i < lists.size(); i++)
|
||||
{
|
||||
if (lists[i] == lst)
|
||||
{
|
||||
lists.erase(lists.begin()+i, lists.begin()+i+1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete lst;
|
||||
return;
|
||||
}
|
||||
if (lst->want <= 0)
|
||||
|
@ -168,7 +181,7 @@ void cluster_client_t::continue_listing(inode_list_t *lst)
|
|||
send_list(&lst->pgs[i]->list_osds[j]);
|
||||
if (lst->want <= 0)
|
||||
{
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -258,24 +271,6 @@ void cluster_client_t::send_list(inode_list_osd_t *cur_list)
|
|||
lst->callback(lst, std::move(pg->objects), pg->pg_num, pg->cur_primary, status);
|
||||
lst->pgs[pg->pos] = NULL;
|
||||
delete pg;
|
||||
if (lst->done_pgs >= lst->pgs.size())
|
||||
{
|
||||
// All done
|
||||
for (int i = 0; i < lists.size(); i++)
|
||||
{
|
||||
if (lists[i] == lst)
|
||||
{
|
||||
lists.erase(lists.begin()+i, lists.begin()+i+1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete lst;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lst->want++;
|
||||
}
|
||||
continue_listing(lst);
|
||||
};
|
||||
|
|
|
@ -52,7 +52,7 @@ int main(int argc, char *argv[])
|
|||
self.journal_block = strtoul(argv[b+1], NULL, 10);
|
||||
self.journal_offset = strtoull(argv[b+2], NULL, 10);
|
||||
self.journal_len = strtoull(argv[b+3], NULL, 10);
|
||||
if (self.journal_block < DIRECT_IO_ALIGNMENT || (self.journal_block % DIRECT_IO_ALIGNMENT) ||
|
||||
if (self.journal_block < MEM_ALIGNMENT || (self.journal_block % MEM_ALIGNMENT) ||
|
||||
self.journal_block > 128*1024)
|
||||
{
|
||||
printf("Invalid journal block size\n");
|
||||
|
|
|
@ -1,169 +0,0 @@
|
|||
// Copyright (c) Vitaliy Filippov, 2019+
|
||||
// License: VNPL-1.1 (see README.md for details)
|
||||
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "blockstore_impl.h"
|
||||
#include "osd_id.h"
|
||||
#include "rw_blocking.h"
|
||||
|
||||
struct meta_dumper_t
|
||||
{
|
||||
char *meta_device;
|
||||
uint32_t meta_block_size;
|
||||
uint64_t meta_offset;
|
||||
uint64_t meta_len;
|
||||
uint64_t meta_pos;
|
||||
int fd;
|
||||
|
||||
int dump();
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
meta_dumper_t self = { 0 };
|
||||
int b = 1;
|
||||
if (argc < b+4)
|
||||
{
|
||||
printf("USAGE: %s <meta_file> <meta_block_size> <offset> <size>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
self.meta_device = argv[b];
|
||||
self.meta_block_size = strtoul(argv[b+1], NULL, 10);
|
||||
self.meta_offset = strtoull(argv[b+2], NULL, 10);
|
||||
self.meta_len = strtoull(argv[b+3], NULL, 10);
|
||||
return self.dump();
|
||||
}
|
||||
|
||||
int meta_dumper_t::dump()
|
||||
{
|
||||
if (this->meta_block_size % DIRECT_IO_ALIGNMENT)
|
||||
{
|
||||
printf("Invalid metadata block size\n");
|
||||
return 1;
|
||||
}
|
||||
this->fd = open(this->meta_device, O_DIRECT|O_RDONLY);
|
||||
if (this->fd == -1)
|
||||
{
|
||||
printf("Failed to open metadata device\n");
|
||||
return 1;
|
||||
}
|
||||
int buf_size = 1024*1024;
|
||||
if (buf_size % this->meta_block_size)
|
||||
buf_size = 8*this->meta_block_size;
|
||||
if (buf_size > this->meta_len)
|
||||
buf_size = this->meta_len;
|
||||
void *data = memalign_or_die(MEM_ALIGNMENT, buf_size);
|
||||
lseek64(this->fd, this->meta_offset, 0);
|
||||
read_blocking(this->fd, data, buf_size);
|
||||
// Check superblock
|
||||
blockstore_meta_header_v1_t *hdr = (blockstore_meta_header_v1_t *)data;
|
||||
if (hdr->zero == 0 &&
|
||||
hdr->magic == BLOCKSTORE_META_MAGIC_V1 &&
|
||||
hdr->version == BLOCKSTORE_META_VERSION_V1)
|
||||
{
|
||||
// Vitastor 0.6-0.7 - static array of clean_disk_entry with bitmaps
|
||||
if (hdr->meta_block_size != this->meta_block_size)
|
||||
{
|
||||
printf("Using block size of %u bytes based on information from the superblock\n", hdr->meta_block_size);
|
||||
this->meta_block_size = hdr->meta_block_size;
|
||||
if (buf_size % this->meta_block_size)
|
||||
{
|
||||
buf_size = 8*this->meta_block_size;
|
||||
free(data);
|
||||
data = memalign_or_die(MEM_ALIGNMENT, buf_size);
|
||||
}
|
||||
}
|
||||
this->meta_offset += this->meta_block_size;
|
||||
this->meta_len -= this->meta_block_size;
|
||||
uint64_t clean_entry_bitmap_size = hdr->data_block_size / hdr->bitmap_granularity / 8;
|
||||
uint64_t clean_entry_size = sizeof(clean_disk_entry) + 2*clean_entry_bitmap_size;
|
||||
uint64_t block_num = 0;
|
||||
printf(
|
||||
"{\"version\":\"0.6\",\"meta_block_size\":%u,\"data_block_size\":%u,\"bitmap_granularity\":%u,\"entries\":[\n",
|
||||
hdr->meta_block_size, hdr->data_block_size, hdr->bitmap_granularity
|
||||
);
|
||||
bool first = true;
|
||||
lseek64(this->fd, this->meta_offset, 0);
|
||||
while (this->meta_pos < this->meta_len)
|
||||
{
|
||||
uint64_t read_len = buf_size < this->meta_len-this->meta_pos ? buf_size : this->meta_len-this->meta_pos;
|
||||
read_blocking(this->fd, data, read_len);
|
||||
this->meta_pos += read_len;
|
||||
for (uint64_t blk = 0; blk < read_len; blk += this->meta_block_size)
|
||||
{
|
||||
for (uint64_t ioff = 0; ioff < this->meta_block_size-clean_entry_size; ioff += clean_entry_size, block_num++)
|
||||
{
|
||||
clean_disk_entry *entry = (clean_disk_entry*)(data + blk + ioff);
|
||||
if (entry->oid.inode)
|
||||
{
|
||||
printf(
|
||||
#define ENTRY_FMT "{\"block\":%lu,\"pool\":%u,\"inode\":%lu,\"stripe\":%lu,\"version\":%lu,\"bitmap\":\""
|
||||
(first ? ENTRY_FMT : (",\n" ENTRY_FMT)),
|
||||
#undef ENTRY_FMT
|
||||
block_num, INODE_POOL(entry->oid.inode), INODE_NO_POOL(entry->oid.inode),
|
||||
entry->oid.stripe, entry->version
|
||||
);
|
||||
first = false;
|
||||
for (uint64_t i = 0; i < clean_entry_bitmap_size; i++)
|
||||
{
|
||||
printf("%02x", entry->bitmap[i]);
|
||||
}
|
||||
printf("\",\"ext_bitmap\":\"");
|
||||
for (uint64_t i = 0; i < clean_entry_bitmap_size; i++)
|
||||
{
|
||||
printf("%02x", entry->bitmap[clean_entry_bitmap_size + i]);
|
||||
}
|
||||
printf("\"}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\n]}\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Vitastor 0.4-0.5 - static array of clean_disk_entry
|
||||
uint64_t clean_entry_size = sizeof(clean_disk_entry);
|
||||
uint64_t block_num = 0;
|
||||
printf("{\"version\":\"0.5\",\"meta_block_size\":%u,\"entries\":[\n", this->meta_block_size);
|
||||
bool first = true;
|
||||
while (this->meta_pos < this->meta_len)
|
||||
{
|
||||
uint64_t read_len = buf_size < this->meta_len-this->meta_pos ? buf_size : this->meta_len-this->meta_pos;
|
||||
read_blocking(this->fd, data, read_len);
|
||||
this->meta_pos += read_len;
|
||||
for (uint64_t blk = 0; blk < read_len; blk += this->meta_block_size)
|
||||
{
|
||||
for (uint64_t ioff = 0; ioff < this->meta_block_size-clean_entry_size; ioff += clean_entry_size, block_num++)
|
||||
{
|
||||
clean_disk_entry *entry = (clean_disk_entry*)(data + blk + ioff);
|
||||
if (entry->oid.inode)
|
||||
{
|
||||
printf(
|
||||
#define ENTRY_FMT "{\"block\":%lu,\"pool\":%u,\"inode\":%lu,\"stripe\":%lu,\"version\":%lu}"
|
||||
(first ? ENTRY_FMT : (",\n" ENTRY_FMT)),
|
||||
#undef ENTRY_FMT
|
||||
block_num, INODE_POOL(entry->oid.inode), INODE_NO_POOL(entry->oid.inode),
|
||||
entry->oid.stripe, entry->version
|
||||
);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\n]}\n");
|
||||
}
|
||||
free(data);
|
||||
close(this->fd);
|
||||
return 0;
|
||||
}
|
|
@ -673,18 +673,18 @@ void etcd_state_client_t::parse_state(const etcd_kv_t & kv)
|
|||
pc.scheme = POOL_SCHEME_REPLICATED;
|
||||
else if (pool_item.second["scheme"] == "xor")
|
||||
pc.scheme = POOL_SCHEME_XOR;
|
||||
else if (pool_item.second["scheme"] == "ec" || pool_item.second["scheme"] == "jerasure")
|
||||
pc.scheme = POOL_SCHEME_EC;
|
||||
else if (pool_item.second["scheme"] == "jerasure")
|
||||
pc.scheme = POOL_SCHEME_JERASURE;
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Pool %u has invalid coding scheme (one of \"xor\", \"replicated\", \"ec\" or \"jerasure\" required), skipping pool\n", pool_id);
|
||||
fprintf(stderr, "Pool %u has invalid coding scheme (one of \"xor\", \"replicated\" or \"jerasure\" required), skipping pool\n", pool_id);
|
||||
continue;
|
||||
}
|
||||
// PG Size
|
||||
pc.pg_size = pool_item.second["pg_size"].uint64_value();
|
||||
if (pc.pg_size < 1 ||
|
||||
pool_item.second["pg_size"].uint64_value() < 3 &&
|
||||
(pc.scheme == POOL_SCHEME_XOR || pc.scheme == POOL_SCHEME_EC) ||
|
||||
(pc.scheme == POOL_SCHEME_XOR || pc.scheme == POOL_SCHEME_JERASURE) ||
|
||||
pool_item.second["pg_size"].uint64_value() > 256)
|
||||
{
|
||||
fprintf(stderr, "Pool %u has invalid pg_size, skipping pool\n", pool_id);
|
||||
|
@ -701,7 +701,7 @@ void etcd_state_client_t::parse_state(const etcd_kv_t & kv)
|
|||
}
|
||||
pc.parity_chunks = 1;
|
||||
}
|
||||
if (pc.scheme == POOL_SCHEME_EC &&
|
||||
if (pc.scheme == POOL_SCHEME_JERASURE &&
|
||||
(pc.parity_chunks < 1 || pc.parity_chunks > pc.pg_size-2))
|
||||
{
|
||||
fprintf(stderr, "Pool %u has invalid parity_chunks (must be between 1 and pg_size-2), skipping pool\n", pool_id);
|
||||
|
@ -710,7 +710,7 @@ void etcd_state_client_t::parse_state(const etcd_kv_t & kv)
|
|||
// PG MinSize
|
||||
pc.pg_minsize = pool_item.second["pg_minsize"].uint64_value();
|
||||
if (pc.pg_minsize < 1 || pc.pg_minsize > pc.pg_size ||
|
||||
(pc.scheme == POOL_SCHEME_XOR || pc.scheme == POOL_SCHEME_EC) &&
|
||||
(pc.scheme == POOL_SCHEME_XOR || pc.scheme == POOL_SCHEME_JERASURE) &&
|
||||
pc.pg_minsize < (pc.pg_size-pc.parity_chunks))
|
||||
{
|
||||
fprintf(stderr, "Pool %u has invalid pg_minsize, skipping pool\n", pool_id);
|
||||
|
@ -845,7 +845,27 @@ void etcd_state_client_t::parse_state(const etcd_kv_t & kv)
|
|||
{
|
||||
history_set.push_back(pg_osd.uint64_value());
|
||||
}
|
||||
pg_cfg.target_history.push_back(history_set);
|
||||
pg_cfg.target_history.push_back((pg_history_set_t){ .osd_set = history_set });
|
||||
}
|
||||
// Newer format with epochs
|
||||
for (auto hist_item: value["osd_set_epochs"].array_items())
|
||||
{
|
||||
pg_history_set_t history_set;
|
||||
history_set.min_epoch = hist_item["min_epoch"].uint64_value();
|
||||
history_set.max_epoch = hist_item["max_epoch"].uint64_value();
|
||||
if (history_set.max_epoch < history_set.min_epoch)
|
||||
{
|
||||
history_set.max_epoch = 0;
|
||||
history_set.min_epoch = 0;
|
||||
}
|
||||
for (auto pg_osd: hist_item["osd_set"].array_items())
|
||||
{
|
||||
history_set.osd_set.push_back(pg_osd.uint64_value());
|
||||
}
|
||||
if (history_set.max_epoch || history_set.osd_set.size())
|
||||
{
|
||||
pg_cfg.target_history.push_back(history_set);
|
||||
}
|
||||
}
|
||||
// Include these additional OSDs when peering the PG
|
||||
for (auto pg_osd: value["all_peers"].array_items())
|
||||
|
|
|
@ -26,7 +26,7 @@ struct pg_config_t
|
|||
bool exists;
|
||||
osd_num_t primary;
|
||||
std::vector<osd_num_t> target_set;
|
||||
std::vector<std::vector<osd_num_t>> target_history;
|
||||
std::vector<pg_history_set_t> target_history;
|
||||
std::vector<osd_num_t> all_peers;
|
||||
bool pause;
|
||||
osd_num_t cur_primary;
|
||||
|
|
|
@ -758,21 +758,3 @@ static std::string trim(const std::string & in)
|
|||
int end = in.find_last_not_of(" \n\r\t");
|
||||
return in.substr(begin, end+1-begin);
|
||||
}
|
||||
|
||||
bool json_is_true(const json11::Json & val)
|
||||
{
|
||||
if (val.is_string())
|
||||
return val == "true" || val == "yes" || val == "1";
|
||||
return val.bool_value();
|
||||
}
|
||||
|
||||
bool json_is_false(const json11::Json & val)
|
||||
{
|
||||
if (val.is_string())
|
||||
return val.string_value() == "false" || val.string_value() == "no" || val.string_value() == "0";
|
||||
if (val.is_number())
|
||||
return val.number_value() == 0;
|
||||
if (val.is_bool())
|
||||
return !val.bool_value();
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -52,6 +52,3 @@ void http_close(http_co_t *co);
|
|||
// Utils
|
||||
uint64_t stoull_full(const std::string & str, int base = 10);
|
||||
std::string strtolower(const std::string & in);
|
||||
// FIXME: move to json11
|
||||
bool json_is_true(const json11::Json & val);
|
||||
bool json_is_false(const json11::Json & val);
|
||||
|
|
|
@ -92,7 +92,10 @@ void nfs_proxy_t::run(json11::Json cfg)
|
|||
if (bind_address == "")
|
||||
bind_address = "0.0.0.0";
|
||||
default_pool = cfg["pool"].as_string();
|
||||
portmap_enabled = !json_is_false(cfg["portmap"]);
|
||||
portmap_enabled = cfg.object_items().find("portmap") == cfg.object_items().end() ||
|
||||
cfg["portmap"].uint64_value() ||
|
||||
cfg["portmap"].string_value() == "yes" ||
|
||||
cfg["portmap"].string_value() == "true";
|
||||
nfs_port = cfg["port"].uint64_value() & 0xffff;
|
||||
if (!nfs_port)
|
||||
nfs_port = 2049;
|
||||
|
|
15
src/osd.cpp
15
src/osd.cpp
|
@ -54,7 +54,7 @@ osd_t::osd_t(const json11::Json & config, ring_loop_t *ringloop)
|
|||
autosync_writes = max_autosync;
|
||||
}
|
||||
|
||||
if (json_is_true(this->config["osd_memlock"]))
|
||||
if (this->config["osd_memlock"] == "true" || this->config["osd_memlock"] == "1" || this->config["osd_memlock"] == "yes")
|
||||
{
|
||||
// Lock all OSD memory if requested
|
||||
if (mlockall(MCL_CURRENT|MCL_FUTURE
|
||||
|
@ -127,11 +127,11 @@ void osd_t::parse_config(const json11::Json & config)
|
|||
etcd_report_interval = config["etcd_report_interval"].uint64_value();
|
||||
if (etcd_report_interval <= 0)
|
||||
etcd_report_interval = 5;
|
||||
readonly = json_is_true(config["readonly"]);
|
||||
run_primary = !json_is_false(config["run_primary"]);
|
||||
no_rebalance = json_is_true(config["no_rebalance"]);
|
||||
no_recovery = json_is_true(config["no_recovery"]);
|
||||
allow_test_ops = json_is_true(config["allow_test_ops"]);
|
||||
readonly = config["readonly"] == "true" || config["readonly"] == "1" || config["readonly"] == "yes";
|
||||
run_primary = config["run_primary"] != "false" && config["run_primary"] != "0" && config["run_primary"] != "no";
|
||||
no_rebalance = config["no_rebalance"] == "true" || config["no_rebalance"] == "1" || config["no_rebalance"] == "yes";
|
||||
no_recovery = config["no_recovery"] == "true" || config["no_recovery"] == "1" || config["no_recovery"] == "yes";
|
||||
allow_test_ops = config["allow_test_ops"] == "true" || config["allow_test_ops"] == "1" || config["allow_test_ops"] == "yes";
|
||||
if (config["immediate_commit"] == "all")
|
||||
immediate_commit = IMMEDIATE_ALL;
|
||||
else if (config["immediate_commit"] == "small")
|
||||
|
@ -168,9 +168,6 @@ void osd_t::parse_config(const json11::Json & config)
|
|||
slow_log_interval = config["slow_log_interval"].uint64_value();
|
||||
if (!slow_log_interval)
|
||||
slow_log_interval = 10;
|
||||
inode_vanish_time = config["inode_vanish_time"].uint64_value();
|
||||
if (!inode_vanish_time)
|
||||
inode_vanish_time = 60;
|
||||
}
|
||||
|
||||
void osd_t::bind_socket()
|
||||
|
|
|
@ -113,7 +113,6 @@ class osd_t
|
|||
int autosync_writes = DEFAULT_AUTOSYNC_WRITES;
|
||||
int recovery_queue_depth = DEFAULT_RECOVERY_QUEUE;
|
||||
int recovery_sync_batch = DEFAULT_RECOVERY_BATCH;
|
||||
int inode_vanish_time = 60;
|
||||
int log_level = 0;
|
||||
|
||||
// cluster state
|
||||
|
@ -166,7 +165,6 @@ class osd_t
|
|||
// op statistics
|
||||
osd_op_stats_t prev_stats;
|
||||
std::map<uint64_t, inode_stats_t> inode_stats;
|
||||
std::map<uint64_t, timespec> vanishing_inodes;
|
||||
const char* recovery_stat_names[2] = { "degraded", "misplaced" };
|
||||
uint64_t recovery_stat_count[2][2] = {};
|
||||
uint64_t recovery_stat_bytes[2][2] = {};
|
||||
|
|
|
@ -186,8 +186,7 @@ void osd_t::report_statistics()
|
|||
json11::Json::object inode_space;
|
||||
json11::Json::object last_stat;
|
||||
pool_id_t last_pool = 0;
|
||||
auto & bs_inode_space = bs->get_inode_space_stats();
|
||||
for (auto kv: bs_inode_space)
|
||||
for (auto kv: bs->get_inode_space_stats())
|
||||
{
|
||||
pool_id_t pool_id = INODE_POOL(kv.first);
|
||||
uint64_t only_inode_num = INODE_NO_POOL(kv.first);
|
||||
|
@ -205,26 +204,8 @@ void osd_t::report_statistics()
|
|||
last_stat = json11::Json::object();
|
||||
last_pool = 0;
|
||||
json11::Json::object inode_ops;
|
||||
timespec tv_now;
|
||||
for (auto st_it = inode_stats.begin(); st_it != inode_stats.end(); )
|
||||
for (auto kv: inode_stats)
|
||||
{
|
||||
auto & kv = *st_it;
|
||||
if (!bs_inode_space[kv.first])
|
||||
{
|
||||
// Is it an empty inode?
|
||||
if (!tv_now.tv_sec)
|
||||
clock_gettime(CLOCK_REALTIME, &tv_now);
|
||||
auto & tv_van = vanishing_inodes[kv.first];
|
||||
if (!tv_van.tv_sec)
|
||||
tv_van = tv_now;
|
||||
else if (tv_van.tv_sec < tv_now.tv_sec-inode_vanish_time)
|
||||
{
|
||||
// Inode vanished <inode_vanish_time> seconds ago, remove it from stats
|
||||
vanishing_inodes.erase(kv.first);
|
||||
inode_stats.erase(st_it++);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
pool_id_t pool_id = INODE_POOL(kv.first);
|
||||
uint64_t only_inode_num = (kv.first & (((uint64_t)1 << (64-POOL_ID_BITS)) - 1));
|
||||
if (!last_pool || pool_id != last_pool)
|
||||
|
@ -251,7 +232,6 @@ void osd_t::report_statistics()
|
|||
{ "bytes", kv.second.op_bytes[INODE_STATS_DELETE] },
|
||||
} },
|
||||
};
|
||||
st_it++;
|
||||
}
|
||||
if (last_pool)
|
||||
inode_ops[std::to_string(last_pool)] = last_stat;
|
||||
|
@ -353,7 +333,10 @@ void osd_t::on_change_pg_history_hook(pool_id_t pool_id, pg_num_t pg_num)
|
|||
{
|
||||
oid = op.first;
|
||||
first = false;
|
||||
continue_primary_write(op.second);
|
||||
if (op.second->req.hdr.opcode == OSD_OP_DELETE)
|
||||
continue_primary_del(op.second);
|
||||
else
|
||||
continue_primary_write(op.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -390,11 +373,7 @@ void osd_t::acquire_lease()
|
|||
etcd_lease_id = data["ID"].string_value();
|
||||
create_osd_state();
|
||||
});
|
||||
printf(
|
||||
"[OSD %lu] reporting to etcd at %s every %d seconds\n", this->osd_num,
|
||||
(config["etcd_address"].is_string() ? config["etcd_address"].string_value() : config["etcd_address"].dump()).c_str(),
|
||||
etcd_report_interval
|
||||
);
|
||||
printf("[OSD %lu] reporting to etcd at %s every %d seconds\n", this->osd_num, config["etcd_address"].string_value().c_str(), etcd_report_interval);
|
||||
tfd->set_timer(etcd_report_interval*1000, true, [this](int timer_id)
|
||||
{
|
||||
renew_lease();
|
||||
|
@ -632,7 +611,7 @@ void osd_t::apply_pg_config()
|
|||
}
|
||||
for (auto & hist_item: pg_cfg.target_history)
|
||||
{
|
||||
for (auto pg_osd: hist_item)
|
||||
for (auto pg_osd: hist_item.osd_set)
|
||||
{
|
||||
if (pg_osd != 0)
|
||||
{
|
||||
|
@ -700,9 +679,9 @@ void osd_t::apply_pg_config()
|
|||
.all_peers = std::vector<osd_num_t>(all_peers.begin(), all_peers.end()),
|
||||
.target_set = pg_cfg.target_set,
|
||||
};
|
||||
if (pg.scheme == POOL_SCHEME_EC)
|
||||
if (pg.scheme == POOL_SCHEME_JERASURE)
|
||||
{
|
||||
use_ec(pg.pg_size, pg.pg_data_size, true);
|
||||
use_jerasure(pg.pg_size, pg.pg_data_size, true);
|
||||
}
|
||||
this->pg_state_dirty.insert({ .pool_id = pool_id, .pg_num = pg_num });
|
||||
pg.print_state();
|
||||
|
@ -823,11 +802,40 @@ void osd_t::report_pg_states()
|
|||
// Prevent race conditions (for the case when the monitor is updating this key at the same time)
|
||||
pg.history_changed = false;
|
||||
std::string history_key = base64_encode(st_cli.etcd_prefix+"/pg/history/"+std::to_string(pg.pool_id)+"/"+std::to_string(pg.pg_num));
|
||||
json11::Json::array target_history;
|
||||
for (auto & pgh: pg.target_history)
|
||||
{
|
||||
target_history.push_back(json11::Json::object {
|
||||
{ "osd_set", pgh.osd_set },
|
||||
{ "min_epoch", pgh.min_epoch },
|
||||
{ "max_epoch", pgh.max_epoch },
|
||||
});
|
||||
}
|
||||
std::vector<osd_num_t> all_peers;
|
||||
for (auto peer_osd: pg.all_peers)
|
||||
{
|
||||
bool found = false;
|
||||
for (auto target_peer: pg.target_set)
|
||||
{
|
||||
if (target_peer == peer_osd)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
all_peers.push_back(peer_osd);
|
||||
}
|
||||
}
|
||||
json11::Json::object history_value = {
|
||||
{ "epoch", pg.epoch },
|
||||
{ "all_peers", pg.all_peers },
|
||||
{ "osd_sets", pg.target_history },
|
||||
{ "osd_set_epochs", target_history },
|
||||
};
|
||||
if (all_peers.size())
|
||||
{
|
||||
history_value["all_peers"] = all_peers;
|
||||
}
|
||||
checks.push_back(json11::Json::object {
|
||||
{ "target", "MOD" },
|
||||
{ "key", history_key },
|
||||
|
@ -914,9 +922,9 @@ void osd_t::report_pg_states()
|
|||
{
|
||||
// Forget offline PGs after reporting their state
|
||||
// (if the state wasn't changed again)
|
||||
if (pg_it->second.scheme == POOL_SCHEME_EC)
|
||||
if (pg_it->second.scheme == POOL_SCHEME_JERASURE)
|
||||
{
|
||||
use_ec(pg_it->second.pg_size, pg_it->second.pg_data_size, false);
|
||||
use_jerasure(pg_it->second.pg_size, pg_it->second.pg_data_size, false);
|
||||
}
|
||||
this->pgs.erase(pg_it);
|
||||
}
|
||||
|
|
|
@ -268,6 +268,25 @@ bool osd_t::pick_next_recovery(osd_recovery_op_t &op)
|
|||
|
||||
void osd_t::submit_recovery_op(osd_recovery_op_t *op)
|
||||
{
|
||||
// Check if the object is deleted
|
||||
bool is_deleted = false;
|
||||
pool_id_t pool_id = INODE_POOL(op->oid.inode);
|
||||
auto pool_cfg_it = st_cli.pool_config.find(pool_id);
|
||||
if (pool_cfg_it != st_cli.pool_config.end())
|
||||
{
|
||||
pg_num_t pg_num = (op->oid.stripe/pool_cfg_it->second.pg_stripe_size) % pg_counts[pool_id] + 1; // like map_to_pg()
|
||||
auto pg_it = pgs.find({ .pool_id = pool_id, .pg_num = pg_num });
|
||||
if (pg_it != pgs.end())
|
||||
{
|
||||
pg_osd_set_state_t *object_state;
|
||||
get_object_osd_set(pg_it->second, op->oid, pg_it->second.cur_set.data(), &object_state);
|
||||
if (object_state && (object_state->state & OBJ_DELETED))
|
||||
{
|
||||
// Object is deleted, but not from all OSDs - delete remaining copies
|
||||
is_deleted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
op->osd_op = new osd_op_t();
|
||||
op->osd_op->op_type = OSD_OP_OUT;
|
||||
op->osd_op->req = (osd_any_op_t){
|
||||
|
@ -275,7 +294,7 @@ void osd_t::submit_recovery_op(osd_recovery_op_t *op)
|
|||
.header = {
|
||||
.magic = SECONDARY_OSD_OP_MAGIC,
|
||||
.id = 1,
|
||||
.opcode = OSD_OP_WRITE,
|
||||
.opcode = (uint64_t)(is_deleted ? OSD_OP_DELETE : OSD_OP_WRITE),
|
||||
},
|
||||
.inode = op->oid.inode,
|
||||
.offset = op->oid.stripe,
|
||||
|
|
10
src/osd_id.h
10
src/osd_id.h
|
@ -3,9 +3,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#define POOL_SCHEME_REPLICATED 1
|
||||
#define POOL_SCHEME_XOR 2
|
||||
#define POOL_SCHEME_EC 3
|
||||
#define POOL_SCHEME_JERASURE 3
|
||||
#define POOL_ID_MAX 0x10000
|
||||
#define POOL_ID_BITS 16
|
||||
#define INODE_POOL(inode) (pool_id_t)((inode) >> (64 - POOL_ID_BITS))
|
||||
|
@ -28,3 +30,9 @@ inline bool operator < (const pool_pg_num_t & a, const pool_pg_num_t & b)
|
|||
{
|
||||
return a.pool_id < b.pool_id || a.pool_id == b.pool_id && a.pg_num < b.pg_num;
|
||||
}
|
||||
|
||||
struct pg_history_set_t
|
||||
{
|
||||
std::vector<osd_num_t> osd_set;
|
||||
uint64_t min_epoch, max_epoch;
|
||||
};
|
||||
|
|
|
@ -30,19 +30,13 @@
|
|||
#define OSD_OP_PING 15
|
||||
#define OSD_OP_SEC_READ_BMP 16
|
||||
#define OSD_OP_MAX 16
|
||||
// Alignment & limit for read/write operations
|
||||
#ifndef MEM_ALIGNMENT
|
||||
#define MEM_ALIGNMENT 512
|
||||
#endif
|
||||
#define OSD_RW_MAX 64*1024*1024
|
||||
#define OSD_PROTOCOL_VERSION 1
|
||||
|
||||
// Memory alignment for direct I/O (usually 512 bytes)
|
||||
#ifndef DIRECT_IO_ALIGNMENT
|
||||
#define DIRECT_IO_ALIGNMENT 512
|
||||
#endif
|
||||
|
||||
// Memory allocation alignment (page size is usually optimal)
|
||||
#ifndef MEM_ALIGNMENT
|
||||
#define MEM_ALIGNMENT 4096
|
||||
#endif
|
||||
|
||||
// common request and reply headers
|
||||
struct __attribute__((__packed__)) osd_op_header_t
|
||||
{
|
||||
|
|
|
@ -228,7 +228,7 @@ void osd_t::start_pg_peering(pg_t & pg)
|
|||
for (auto & history_set: pg.target_history)
|
||||
{
|
||||
bool found = true;
|
||||
for (auto history_osd: history_set)
|
||||
for (auto history_osd: history_set.osd_set)
|
||||
{
|
||||
if (history_osd != 0)
|
||||
{
|
||||
|
@ -539,47 +539,114 @@ void osd_t::finish_stop_pg(pg_t & pg)
|
|||
report_pg_state(pg);
|
||||
}
|
||||
|
||||
static int count_nonzero_osds(const std::vector<osd_num_t> & v)
|
||||
{
|
||||
int n = 0;
|
||||
for (auto & osd_num: v)
|
||||
{
|
||||
if (osd_num != 0)
|
||||
{
|
||||
n++;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void osd_t::report_pg_state(pg_t & pg)
|
||||
{
|
||||
pg.print_state();
|
||||
this->pg_state_dirty.insert({ .pool_id = pg.pool_id, .pg_num = pg.pg_num });
|
||||
if (pg.state == PG_ACTIVE && (pg.target_history.size() > 0 || pg.all_peers.size() > pg.target_set.size()))
|
||||
if ((pg.state == PG_ACTIVE || pg.state == (PG_ACTIVE|PG_LEFT_ON_DEAD)) &&
|
||||
(pg.target_history.size() != 1 ||
|
||||
pg.target_history[0].osd_set != pg.target_set ||
|
||||
pg.target_history[0].min_epoch != 0 ||
|
||||
pg.target_history[0].max_epoch != pg.epoch ||
|
||||
pg.all_peers.size() > count_nonzero_osds(pg.target_set)))
|
||||
{
|
||||
// Clear history of active+clean PGs
|
||||
pg.history_changed = true;
|
||||
pg.target_history.clear();
|
||||
pg.all_peers = pg.target_set;
|
||||
pg.cur_peers = pg.target_set;
|
||||
}
|
||||
else if (pg.state == (PG_ACTIVE|PG_LEFT_ON_DEAD))
|
||||
{
|
||||
// Clear history of active+left_on_dead PGs, but leave dead OSDs in all_peers
|
||||
pg.history_changed = true;
|
||||
pg.target_history.clear();
|
||||
std::set<osd_num_t> dead_peers;
|
||||
for (auto pg_osd: pg.all_peers)
|
||||
pg.target_history.push_back((pg_history_set_t){
|
||||
.osd_set = pg.cur_set,
|
||||
.min_epoch = 0,
|
||||
.max_epoch = pg.epoch,
|
||||
});
|
||||
if (pg.state == PG_ACTIVE)
|
||||
{
|
||||
dead_peers.insert(pg_osd);
|
||||
}
|
||||
for (auto pg_osd: pg.cur_peers)
|
||||
{
|
||||
dead_peers.erase(pg_osd);
|
||||
}
|
||||
for (auto pg_osd: pg.target_set)
|
||||
{
|
||||
if (pg_osd)
|
||||
pg.all_peers.clear();
|
||||
for (auto pg_osd: pg.target_set)
|
||||
{
|
||||
dead_peers.insert(pg_osd);
|
||||
if (pg_osd)
|
||||
pg.all_peers.push_back(pg_osd);
|
||||
}
|
||||
}
|
||||
pg.all_peers.clear();
|
||||
pg.all_peers.insert(pg.all_peers.begin(), dead_peers.begin(), dead_peers.end());
|
||||
else
|
||||
{
|
||||
// Clear history of active+left_on_dead PGs, but leave dead OSDs in all_peers
|
||||
std::set<osd_num_t> dead_peers(pg.all_peers.begin(), pg.all_peers.end());
|
||||
for (auto pg_osd: pg.cur_peers)
|
||||
{
|
||||
dead_peers.erase(pg_osd);
|
||||
}
|
||||
for (auto pg_osd: pg.target_set)
|
||||
{
|
||||
if (pg_osd)
|
||||
dead_peers.insert(pg_osd);
|
||||
}
|
||||
pg.all_peers.clear();
|
||||
pg.all_peers.insert(pg.all_peers.begin(), dead_peers.begin(), dead_peers.end());
|
||||
}
|
||||
pg.cur_peers.clear();
|
||||
for (auto pg_osd: pg.target_set)
|
||||
{
|
||||
if (pg_osd)
|
||||
{
|
||||
pg.cur_peers.push_back(pg_osd);
|
||||
}
|
||||
}
|
||||
if (pg.history_changed)
|
||||
{
|
||||
bool epoch_already_reported = false;
|
||||
int max_epoch_pos = -1;
|
||||
for (int i = pg.target_history.size()-1; i >= 0; i--)
|
||||
{
|
||||
if (pg.target_history[i].min_epoch > pg.epoch)
|
||||
{
|
||||
printf("[PG %u/%u] Invalid PG history: there is an entry with min_epoch (%lu) > current epoch (%lu)\n",
|
||||
pg.pool_id, pg.pg_num, pg.target_history[i].min_epoch, pg.epoch);
|
||||
force_stop(1);
|
||||
return;
|
||||
}
|
||||
if (max_epoch_pos < 0 || pg.target_history[i].max_epoch > pg.target_history[max_epoch_pos].max_epoch)
|
||||
{
|
||||
max_epoch_pos = i;
|
||||
}
|
||||
if (pg.target_history[i].min_epoch <= pg.epoch &&
|
||||
pg.target_history[i].max_epoch >= pg.epoch)
|
||||
{
|
||||
if (pg.target_history[i].osd_set != pg.cur_set)
|
||||
{
|
||||
printf("[PG %u/%u] Invalid target_history: epoch %lu has another OSD set already registered\n", pg.pool_id, pg.pg_num, pg.epoch);
|
||||
force_stop(1);
|
||||
return;
|
||||
}
|
||||
// Already reported
|
||||
epoch_already_reported = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!epoch_already_reported)
|
||||
{
|
||||
if (max_epoch_pos >= 0 && pg.target_history[max_epoch_pos].osd_set == pg.cur_set)
|
||||
{
|
||||
pg.target_history[max_epoch_pos].max_epoch = pg.epoch;
|
||||
}
|
||||
else
|
||||
{
|
||||
pg.target_history.push_back((pg_history_set_t){
|
||||
.osd_set = pg.cur_set,
|
||||
.min_epoch = pg.epoch,
|
||||
.max_epoch = pg.epoch,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ struct pg_obj_state_check_t
|
|||
|
||||
void walk();
|
||||
void start_object();
|
||||
void recheck_version_osd_set();
|
||||
void handle_version();
|
||||
void finish_object();
|
||||
};
|
||||
|
@ -84,27 +85,19 @@ void pg_obj_state_check_t::walk()
|
|||
pg->state = PG_INCOMPLETE | PG_HAS_INVALID;
|
||||
return;
|
||||
}
|
||||
// Activate PG
|
||||
if (pg->pg_cursize < pg->pg_size)
|
||||
{
|
||||
// Report PG history and activate
|
||||
// History will be reported on first write
|
||||
pg->state |= PG_DEGRADED | PG_PEERED;
|
||||
std::vector<osd_num_t> history_set;
|
||||
for (auto peer_osd: pg->cur_set)
|
||||
{
|
||||
if (peer_osd != 0)
|
||||
{
|
||||
history_set.push_back(peer_osd);
|
||||
}
|
||||
}
|
||||
pg->target_history.push_back(history_set);
|
||||
pg->history_changed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just activate
|
||||
pg->state |= PG_ACTIVE;
|
||||
// Clear history
|
||||
pg->history_changed = true;
|
||||
}
|
||||
if (pg->state == PG_ACTIVE && pg->cur_peers.size() < pg->all_peers.size())
|
||||
if (pg->cur_peers.size() < pg->all_peers.size())
|
||||
{
|
||||
pg->state |= PG_LEFT_ON_DEAD;
|
||||
}
|
||||
|
@ -121,13 +114,82 @@ void pg_obj_state_check_t::start_object()
|
|||
n_unstable = n_invalid = 0;
|
||||
}
|
||||
|
||||
void pg_obj_state_check_t::recheck_version_osd_set()
|
||||
{
|
||||
uint64_t epoch = (last_ver >> (64-PG_EPOCH_BITS));
|
||||
if (!pg->epoch_sizes_differ && n_copies >= pg->pg_size)
|
||||
{
|
||||
// Enough copies
|
||||
return;
|
||||
}
|
||||
auto epoch_it = pg->target_by_epoch.lower_bound(epoch);
|
||||
if (epoch_it == pg->target_by_epoch.end() || epoch_it->second.min_epoch > epoch)
|
||||
{
|
||||
// Epoch info not found
|
||||
return;
|
||||
}
|
||||
if (pg->epoch_sizes_differ && n_copies >= epoch_it->second.osd_set.size())
|
||||
{
|
||||
// For the (unlikely) case of PG size change - enough copies
|
||||
return;
|
||||
}
|
||||
// Recheck version against the OSD set corresponding to epoch if it's known
|
||||
if (epoch_it != pg->target_by_epoch.end() && epoch_it->second.min_epoch <= epoch)
|
||||
{
|
||||
for (int j = 0; j < epoch_it->second.osd_set.size(); j++)
|
||||
{
|
||||
osd_num_t cur_osd = epoch_it->second.osd_set[j];
|
||||
bool found = false;
|
||||
for (int i = ver_start; i < ver_end; i++)
|
||||
{
|
||||
if (cur_osd == list[i].osd_num)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
// Check if a newer version is present on the same OSD and masks the older one
|
||||
// It happens for overwritten replicas in the following case:
|
||||
// Version 1 is present on OSD 1,2,3
|
||||
// Client tries to write Version 2
|
||||
// OSD 3 succeeds to write Version 2, others don't. OSD 3 crashes, then starts again
|
||||
// OSD 1 sees: version 1 on OSD 1,2 and version 2 on OSD 3
|
||||
// (version 1 on OSD 3 is already masked/removed)
|
||||
// Version 1 is not present on a full set, but it must not be removed
|
||||
if (replicated)
|
||||
{
|
||||
for (int i = obj_start; i < ver_start; i++)
|
||||
{
|
||||
if (cur_osd == list[i].osd_num)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
// Object is missing from one of the OSDs of that set.
|
||||
// This means it's deleted or moved and we can safely drop this version.
|
||||
target_ver = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pg_obj_state_check_t::handle_version()
|
||||
{
|
||||
if (!target_ver && last_ver != list[list_pos].version && (n_stable > 0 || n_roles >= pg->pg_data_size))
|
||||
{
|
||||
// Version is either stable or recoverable
|
||||
target_ver = last_ver;
|
||||
ver_end = list_pos;
|
||||
target_ver = last_ver;
|
||||
// Skip versions that are not present on any of OSDs for the corresponding PG epoch
|
||||
recheck_version_osd_set();
|
||||
}
|
||||
if (!target_ver)
|
||||
{
|
||||
|
@ -191,6 +253,8 @@ void pg_obj_state_check_t::finish_object()
|
|||
// Version is either stable or recoverable
|
||||
target_ver = last_ver;
|
||||
ver_end = list_pos;
|
||||
// Skip versions that are not present on any of OSDs for the corresponding PG epoch
|
||||
recheck_version_osd_set();
|
||||
}
|
||||
obj_end = list_pos;
|
||||
// Remember the decision
|
||||
|
@ -244,11 +308,23 @@ void pg_obj_state_check_t::finish_object()
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!target_ver)
|
||||
if (!target_ver && (n_unstable >= obj_end-obj_start))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!replicated && n_roles < pg->pg_data_size)
|
||||
if (!target_ver)
|
||||
{
|
||||
// Object is present, but should not be :) i.e. it's a deleted object that reappeared
|
||||
if (log_level > 1)
|
||||
{
|
||||
printf("Object is deleted: %lx:%lx version=%lu/%lu\n", oid.inode, oid.stripe, target_ver, max_ver);
|
||||
}
|
||||
state = OBJ_DELETED;
|
||||
pg->state = pg->state | PG_HAS_MISPLACED;
|
||||
// To record all versions as outdated:
|
||||
ver_end = obj_start;
|
||||
}
|
||||
else if (!replicated && n_roles < pg->pg_data_size)
|
||||
{
|
||||
if (log_level > 1)
|
||||
{
|
||||
|
@ -276,7 +352,7 @@ void pg_obj_state_check_t::finish_object()
|
|||
pg->state = pg->state | PG_HAS_MISPLACED;
|
||||
}
|
||||
if (log_level > 1 && (state & (OBJ_INCOMPLETE | OBJ_DEGRADED)) ||
|
||||
log_level > 2 && (state & OBJ_MISPLACED))
|
||||
log_level > 2 && (state & (OBJ_MISPLACED | OBJ_DELETED)))
|
||||
{
|
||||
for (int i = obj_start; i < obj_end; i++)
|
||||
{
|
||||
|
@ -285,9 +361,9 @@ void pg_obj_state_check_t::finish_object()
|
|||
}
|
||||
}
|
||||
pg->total_count++;
|
||||
if (state != 0 || ver_end < obj_end)
|
||||
osd_set.clear();
|
||||
if (target_ver != 0 && (state != 0 || ver_end < obj_end))
|
||||
{
|
||||
osd_set.clear();
|
||||
for (int i = ver_start; i < ver_end; i++)
|
||||
{
|
||||
osd_set.push_back((pg_obj_loc_t){
|
||||
|
@ -310,7 +386,8 @@ void pg_obj_state_check_t::finish_object()
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (j >= osd_set.size() && pg->cur_set[list[i].oid.stripe & STRIPE_MASK] != list[i].osd_num)
|
||||
if (j >= osd_set.size() && ((state & OBJ_DELETED) ||
|
||||
pg->cur_set[list[i].oid.stripe & STRIPE_MASK] != list[i].osd_num))
|
||||
{
|
||||
osd_set.push_back((pg_obj_loc_t){
|
||||
.role = (list[i].oid.stripe & STRIPE_MASK),
|
||||
|
@ -325,7 +402,11 @@ void pg_obj_state_check_t::finish_object()
|
|||
}
|
||||
}
|
||||
}
|
||||
if (target_ver < max_ver)
|
||||
if (state & OBJ_DELETED)
|
||||
{
|
||||
pg->ver_override[oid] = max_ver;
|
||||
}
|
||||
else if (target_ver < max_ver)
|
||||
{
|
||||
pg->ver_override[oid] = target_ver;
|
||||
}
|
||||
|
@ -379,6 +460,7 @@ void pg_obj_state_check_t::finish_object()
|
|||
}
|
||||
else
|
||||
{
|
||||
assert(it->second.state == state);
|
||||
it->second.object_count++;
|
||||
}
|
||||
if (state & OBJ_INCOMPLETE)
|
||||
|
@ -399,6 +481,34 @@ void pg_obj_state_check_t::finish_object()
|
|||
// FIXME: Write at least some tests for this function
|
||||
void pg_t::calc_object_states(int log_level)
|
||||
{
|
||||
// Calculate intersections of target_history with cur_peers
|
||||
for (auto & history_item: target_history)
|
||||
{
|
||||
if (history_item.max_epoch)
|
||||
{
|
||||
pg_history_set_t & set_copy = target_by_epoch[history_item.max_epoch];
|
||||
set_copy.min_epoch = history_item.min_epoch;
|
||||
set_copy.max_epoch = history_item.max_epoch;
|
||||
for (int i = 0; i < history_item.osd_set.size(); i++)
|
||||
{
|
||||
if (history_item.osd_set[i] != 0)
|
||||
{
|
||||
for (int j = 0; j < cur_set.size(); j++)
|
||||
{
|
||||
if (cur_set[j] == history_item.osd_set[i])
|
||||
{
|
||||
set_copy.osd_set.push_back(history_item.osd_set[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (set_copy.osd_set.size() != pg_size)
|
||||
{
|
||||
epoch_sizes_differ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Copy all object lists into one array
|
||||
pg_obj_state_check_t st;
|
||||
st.log_level = log_level;
|
||||
|
@ -435,10 +545,18 @@ void pg_t::calc_object_states(int log_level)
|
|||
std::sort(st.list.begin(), st.list.end());
|
||||
// Walk over it and check object states
|
||||
st.walk();
|
||||
if (this->state & (PG_DEGRADED|PG_LEFT_ON_DEAD))
|
||||
target_by_epoch.clear();
|
||||
if (this->state != PG_ACTIVE)
|
||||
{
|
||||
assert(epoch != (((uint64_t)1 << PG_EPOCH_BITS)-1));
|
||||
epoch++;
|
||||
for (auto & pgh: target_history)
|
||||
{
|
||||
if (epoch <= pgh.max_epoch)
|
||||
{
|
||||
epoch = pgh.max_epoch+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -89,7 +89,9 @@ struct pg_t
|
|||
// epoch number - should increase with each non-clean activation of the PG
|
||||
uint64_t epoch = 0, reported_epoch = 0;
|
||||
// target history and all potential peers
|
||||
std::vector<std::vector<osd_num_t>> target_history;
|
||||
std::vector<pg_history_set_t> target_history;
|
||||
std::map<uint64_t, pg_history_set_t> target_by_epoch;
|
||||
bool epoch_sizes_differ = false;
|
||||
std::vector<osd_num_t> all_peers;
|
||||
bool history_changed = false;
|
||||
// peer list from the last peering event
|
||||
|
|
|
@ -199,6 +199,21 @@ void osd_t::continue_primary_read(osd_op_t *cur_op)
|
|||
{
|
||||
// PG may be degraded or have misplaced objects
|
||||
op_data->prev_set = get_object_osd_set(pg, op_data->oid, pg.cur_set.data(), &op_data->object_state);
|
||||
if (op_data->object_state && (op_data->object_state->state & OBJ_DELETED))
|
||||
{
|
||||
// Object is deleted, just return zeroes
|
||||
cur_op->reply.rw.version = 0;
|
||||
cur_op->reply.rw.bitmap_len = op_data->pg_data_size * clean_entry_bitmap_size;
|
||||
uint64_t zero_len = cur_op->reply.rw.bitmap_len + cur_op->req.rw.len;
|
||||
while (zero_len >= 0)
|
||||
{
|
||||
uint64_t cur_zero_len = zero_buffer_size > zero_len ? zero_len : zero_buffer_size;
|
||||
cur_op->iov.push_back(zero_buffer, cur_zero_len);
|
||||
zero_len -= cur_zero_len;
|
||||
}
|
||||
finish_op(cur_op, cur_op->req.rw.len);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (pg.state == PG_ACTIVE || op_data->scheme == POOL_SCHEME_REPLICATED)
|
||||
{
|
||||
|
@ -241,9 +256,9 @@ resume_2:
|
|||
{
|
||||
reconstruct_stripes_xor(stripes, op_data->pg_size, clean_entry_bitmap_size);
|
||||
}
|
||||
else if (op_data->scheme == POOL_SCHEME_EC)
|
||||
else if (op_data->scheme == POOL_SCHEME_JERASURE)
|
||||
{
|
||||
reconstruct_stripes_ec(stripes, op_data->pg_size, op_data->pg_data_size, clean_entry_bitmap_size);
|
||||
reconstruct_stripes_jerasure(stripes, op_data->pg_size, op_data->pg_data_size, clean_entry_bitmap_size);
|
||||
}
|
||||
cur_op->iov.push_back(op_data->stripes[0].bmp_buf, cur_op->reply.rw.bitmap_len);
|
||||
for (int role = 0; role < op_data->pg_size; role++)
|
||||
|
@ -290,7 +305,7 @@ void osd_t::remove_object_from_state(object_id & oid, pg_osd_set_state_t *object
|
|||
report_pg_state(pg);
|
||||
}
|
||||
}
|
||||
else if (object_state->state & OBJ_MISPLACED)
|
||||
else if (object_state->state & (OBJ_MISPLACED | OBJ_DELETED))
|
||||
{
|
||||
this->misplaced_objects--;
|
||||
pg.misplaced_objects.erase(oid);
|
||||
|
@ -329,12 +344,6 @@ void osd_t::continue_primary_del(osd_op_t *cur_op)
|
|||
else if (op_data->st == 4) goto resume_4;
|
||||
else if (op_data->st == 5) goto resume_5;
|
||||
assert(op_data->st == 0);
|
||||
// Delete is forbidden even in active PGs if they're also degraded or have previous dead OSDs
|
||||
if (pg.state & (PG_DEGRADED | PG_LEFT_ON_DEAD))
|
||||
{
|
||||
finish_op(cur_op, -EBUSY);
|
||||
return;
|
||||
}
|
||||
if (!check_write_queue(cur_op, pg))
|
||||
{
|
||||
return;
|
||||
|
@ -342,11 +351,18 @@ void osd_t::continue_primary_del(osd_op_t *cur_op)
|
|||
resume_1:
|
||||
// Determine which OSDs contain this object and delete it
|
||||
op_data->prev_set = get_object_osd_set(pg, op_data->oid, pg.cur_set.data(), &op_data->object_state);
|
||||
// Submit 1 read to determine the actual version number
|
||||
submit_primary_subops(SUBMIT_RMW_READ, UINT64_MAX, op_data->prev_set, cur_op);
|
||||
if (op_data->object_state && (op_data->object_state->state & OBJ_DELETED))
|
||||
{
|
||||
op_data->fact_ver = pg.ver_override[op_data->oid];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Submit 1 read to determine the actual version number
|
||||
submit_primary_subops(SUBMIT_RMW_READ, UINT64_MAX, op_data->prev_set, cur_op);
|
||||
resume_2:
|
||||
op_data->st = 2;
|
||||
return;
|
||||
op_data->st = 2;
|
||||
return;
|
||||
}
|
||||
resume_3:
|
||||
if (op_data->errors > 0)
|
||||
{
|
||||
|
|
|
@ -110,9 +110,9 @@ resume_1:
|
|||
{
|
||||
reconstruct_stripes_xor(local_stripes, pg.pg_size, clean_entry_bitmap_size);
|
||||
}
|
||||
else if (pg.scheme == POOL_SCHEME_EC)
|
||||
else if (pg.scheme == POOL_SCHEME_JERASURE)
|
||||
{
|
||||
reconstruct_stripes_ec(local_stripes, pg.pg_size, pg.pg_data_size, clean_entry_bitmap_size);
|
||||
reconstruct_stripes_jerasure(local_stripes, pg.pg_size, pg.pg_data_size, clean_entry_bitmap_size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -133,6 +133,12 @@ int osd_t::collect_bitmap_requests(osd_op_t *cur_op, pg_t & pg, std::vector<bitm
|
|||
uint64_t target_version = vo_it != pg.ver_override.end() ? vo_it->second : UINT64_MAX;
|
||||
pg_osd_set_state_t *object_state;
|
||||
uint64_t* cur_set = get_object_osd_set(pg, cur_oid, pg.cur_set.data(), &object_state);
|
||||
if (object_state && (object_state->state & OBJ_DELETED))
|
||||
{
|
||||
// Object is deleted, zero out the bitmap
|
||||
memset((uint8_t*)op_data->snapshot_bitmaps + chain_num*clean_entry_bitmap_size, 0, clean_entry_bitmap_size);
|
||||
continue;
|
||||
}
|
||||
if (pg.scheme == POOL_SCHEME_REPLICATED)
|
||||
{
|
||||
osd_num_t read_target = 0;
|
||||
|
@ -506,9 +512,9 @@ void osd_t::send_chained_read_results(pg_t & pg, osd_op_t *cur_op)
|
|||
{
|
||||
reconstruct_stripes_xor(stripes, pg.pg_size, clean_entry_bitmap_size);
|
||||
}
|
||||
else if (op_data->scheme == POOL_SCHEME_EC)
|
||||
else if (op_data->scheme == POOL_SCHEME_JERASURE)
|
||||
{
|
||||
reconstruct_stripes_ec(stripes, pg.pg_size, pg.pg_data_size, clean_entry_bitmap_size);
|
||||
reconstruct_stripes_jerasure(stripes, pg.pg_size, pg.pg_data_size, clean_entry_bitmap_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -116,17 +116,19 @@ void osd_t::submit_primary_subops(int submit_type, uint64_t op_version, const ui
|
|||
if (osd_set[role] != 0 && (wr || !rep && stripes[role].read_end != 0))
|
||||
n_subops++;
|
||||
}
|
||||
if (!n_subops && (submit_type == SUBMIT_RMW_READ || rep))
|
||||
if (!n_subops && (submit_type == SUBMIT_RMW_READ || rep) && zero_read >= 0)
|
||||
n_subops = 1;
|
||||
else
|
||||
zero_read = -1;
|
||||
osd_op_t *subops = new osd_op_t[n_subops];
|
||||
op_data->fact_ver = 0;
|
||||
op_data->done = op_data->errors = 0;
|
||||
op_data->n_subops = n_subops;
|
||||
op_data->subops = subops;
|
||||
int sent = submit_primary_subop_batch(submit_type, op_data->oid.inode, op_version, op_data->stripes, osd_set, cur_op, 0, zero_read);
|
||||
assert(sent == n_subops);
|
||||
if (n_subops > 0)
|
||||
{
|
||||
op_data->subops = new osd_op_t[n_subops];
|
||||
int sent = submit_primary_subop_batch(submit_type, op_data->oid.inode, op_version, op_data->stripes, osd_set, cur_op, 0, zero_read);
|
||||
assert(sent == n_subops);
|
||||
}
|
||||
}
|
||||
|
||||
int osd_t::submit_primary_subop_batch(int submit_type, inode_t inode, uint64_t op_version,
|
||||
|
|
|
@ -132,9 +132,9 @@ resume_3:
|
|||
{
|
||||
calc_rmw_parity_xor(op_data->stripes, pg.pg_size, op_data->prev_set, pg.cur_set.data(), bs_block_size, clean_entry_bitmap_size);
|
||||
}
|
||||
else if (pg.scheme == POOL_SCHEME_EC)
|
||||
else if (pg.scheme == POOL_SCHEME_JERASURE)
|
||||
{
|
||||
calc_rmw_parity_ec(op_data->stripes, pg.pg_size, op_data->pg_data_size, op_data->prev_set, pg.cur_set.data(), bs_block_size, clean_entry_bitmap_size);
|
||||
calc_rmw_parity_jerasure(op_data->stripes, pg.pg_size, op_data->pg_data_size, op_data->prev_set, pg.cur_set.data(), bs_block_size, clean_entry_bitmap_size);
|
||||
}
|
||||
}
|
||||
// Send writes
|
||||
|
@ -154,10 +154,9 @@ resume_3:
|
|||
if (pg.epoch > pg.reported_epoch)
|
||||
{
|
||||
// Report newer epoch before writing
|
||||
// FIXME: We may report only one PG state here...
|
||||
this->pg_state_dirty.insert({ .pool_id = pg.pool_id, .pg_num = pg.pg_num });
|
||||
// FIXME: We don't have to report all changed PG states here
|
||||
pg.history_changed = true;
|
||||
report_pg_states();
|
||||
report_pg_state(pg);
|
||||
resume_10:
|
||||
if (pg.epoch > pg.reported_epoch)
|
||||
{
|
||||
|
|
171
src/osd_rmw.cpp
171
src/osd_rmw.cpp
|
@ -4,13 +4,8 @@
|
|||
#include <stdexcept>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
extern "C" {
|
||||
#include <reed_sol.h>
|
||||
#include <jerasure/reed_sol.h>
|
||||
#include <jerasure.h>
|
||||
#ifdef WITH_ISAL
|
||||
#include <isa-l/erasure_code.h>
|
||||
#endif
|
||||
}
|
||||
#include <map>
|
||||
#include "allocator.h"
|
||||
#include "xor.h"
|
||||
|
@ -152,14 +147,13 @@ inline bool operator < (const reed_sol_erased_t &a, const reed_sol_erased_t &b)
|
|||
struct reed_sol_matrix_t
|
||||
{
|
||||
int refs = 0;
|
||||
int *je_data;
|
||||
uint8_t *isal_data;
|
||||
std::map<reed_sol_erased_t, void*> decodings;
|
||||
int *data;
|
||||
std::map<reed_sol_erased_t, int*> decodings;
|
||||
};
|
||||
|
||||
static std::map<uint64_t, reed_sol_matrix_t> matrices;
|
||||
std::map<uint64_t, reed_sol_matrix_t> matrices;
|
||||
|
||||
void use_ec(int pg_size, int pg_minsize, bool use)
|
||||
void use_jerasure(int pg_size, int pg_minsize, bool use)
|
||||
{
|
||||
uint64_t key = (uint64_t)pg_size | ((uint64_t)pg_minsize) << 32;
|
||||
auto rs_it = matrices.find(key);
|
||||
|
@ -170,33 +164,19 @@ void use_ec(int pg_size, int pg_minsize, bool use)
|
|||
return;
|
||||
}
|
||||
int *matrix = reed_sol_vandermonde_coding_matrix(pg_minsize, pg_size-pg_minsize, OSD_JERASURE_W);
|
||||
uint8_t *isal_table = NULL;
|
||||
#ifdef WITH_ISAL
|
||||
uint8_t *isal_matrix = (uint8_t*)malloc_or_die(pg_minsize*(pg_size-pg_minsize));
|
||||
for (int i = 0; i < pg_minsize*(pg_size-pg_minsize); i++)
|
||||
{
|
||||
isal_matrix[i] = matrix[i];
|
||||
}
|
||||
isal_table = (uint8_t*)malloc_or_die(pg_minsize*(pg_size-pg_minsize)*32);
|
||||
ec_init_tables(pg_minsize, pg_size-pg_minsize, isal_matrix, isal_table);
|
||||
free(isal_matrix);
|
||||
#endif
|
||||
matrices[key] = (reed_sol_matrix_t){
|
||||
.refs = 0,
|
||||
.je_data = matrix,
|
||||
.isal_data = isal_table,
|
||||
.data = matrix,
|
||||
};
|
||||
rs_it = matrices.find(key);
|
||||
}
|
||||
rs_it->second.refs += (!use ? -1 : 1);
|
||||
if (rs_it->second.refs <= 0)
|
||||
{
|
||||
free(rs_it->second.je_data);
|
||||
if (rs_it->second.isal_data)
|
||||
free(rs_it->second.isal_data);
|
||||
free(rs_it->second.data);
|
||||
for (auto dec_it = rs_it->second.decodings.begin(); dec_it != rs_it->second.decodings.end();)
|
||||
{
|
||||
void *data = dec_it->second;
|
||||
int *data = dec_it->second;
|
||||
rs_it->second.decodings.erase(dec_it++);
|
||||
free(data);
|
||||
}
|
||||
|
@ -204,7 +184,7 @@ void use_ec(int pg_size, int pg_minsize, bool use)
|
|||
}
|
||||
}
|
||||
|
||||
static reed_sol_matrix_t* get_ec_matrix(int pg_size, int pg_minsize)
|
||||
reed_sol_matrix_t* get_jerasure_matrix(int pg_size, int pg_minsize)
|
||||
{
|
||||
uint64_t key = (uint64_t)pg_size | ((uint64_t)pg_minsize) << 32;
|
||||
auto rs_it = matrices.find(key);
|
||||
|
@ -219,7 +199,7 @@ static reed_sol_matrix_t* get_ec_matrix(int pg_size, int pg_minsize)
|
|||
// we don't need it. also it makes an extra allocation of int *erased on every call and doesn't cache
|
||||
// the decoding matrix.
|
||||
// all these flaws are fixed in this function:
|
||||
static void* get_jerasure_decoding_matrix(osd_rmw_stripe_t *stripes, int pg_size, int pg_minsize)
|
||||
int* get_jerasure_decoding_matrix(osd_rmw_stripe_t *stripes, int pg_size, int pg_minsize)
|
||||
{
|
||||
int edd = 0;
|
||||
int erased[pg_size];
|
||||
|
@ -230,57 +210,16 @@ static void* get_jerasure_decoding_matrix(osd_rmw_stripe_t *stripes, int pg_size
|
|||
edd++;
|
||||
if (edd == 0)
|
||||
return NULL;
|
||||
reed_sol_matrix_t *matrix = get_ec_matrix(pg_size, pg_minsize);
|
||||
reed_sol_matrix_t *matrix = get_jerasure_matrix(pg_size, pg_minsize);
|
||||
auto dec_it = matrix->decodings.find((reed_sol_erased_t){ .data = erased, .size = pg_size });
|
||||
if (dec_it == matrix->decodings.end())
|
||||
{
|
||||
#ifdef WITH_ISAL
|
||||
int smrow = 0;
|
||||
uint8_t *submatrix = (uint8_t*)malloc_or_die(pg_minsize*pg_minsize*2);
|
||||
for (int i = 0; i < pg_size; i++)
|
||||
{
|
||||
if (!erased[i])
|
||||
{
|
||||
if (i < pg_minsize)
|
||||
{
|
||||
for (int j = 0; j < pg_minsize; j++)
|
||||
submatrix[smrow*pg_minsize + j] = j == i;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int j = 0; j < pg_minsize; j++)
|
||||
submatrix[smrow*pg_minsize + j] = (uint8_t)matrix->je_data[(i-pg_minsize)*pg_minsize + j];
|
||||
}
|
||||
smrow++;
|
||||
}
|
||||
}
|
||||
if (smrow < pg_minsize)
|
||||
{
|
||||
free(submatrix);
|
||||
throw std::runtime_error("failed to make an invertible submatrix");
|
||||
}
|
||||
gf_invert_matrix(submatrix, submatrix + pg_minsize*pg_minsize, pg_minsize);
|
||||
smrow = 0;
|
||||
for (int i = 0; i < pg_minsize; i++)
|
||||
{
|
||||
if (erased[i])
|
||||
{
|
||||
memcpy(submatrix + pg_minsize*smrow, submatrix + (pg_minsize+i)*pg_minsize, pg_minsize);
|
||||
smrow++;
|
||||
}
|
||||
}
|
||||
uint8_t *rectable = (uint8_t*)malloc_or_die(32*smrow*pg_minsize + pg_size*sizeof(int));
|
||||
ec_init_tables(pg_minsize, smrow, submatrix, rectable);
|
||||
free(submatrix);
|
||||
int *erased_copy = (int*)(rectable + 32*smrow*pg_minsize);
|
||||
memcpy(erased_copy, erased, pg_size*sizeof(int));
|
||||
matrix->decodings.emplace((reed_sol_erased_t){ .data = erased_copy, .size = pg_size }, rectable);
|
||||
return rectable;
|
||||
#else
|
||||
int *dm_ids = (int*)malloc_or_die(sizeof(int)*(pg_minsize + pg_minsize*pg_minsize + pg_size));
|
||||
int *decoding_matrix = dm_ids + pg_minsize;
|
||||
if (!dm_ids)
|
||||
throw std::bad_alloc();
|
||||
// we always use row_k_ones=1 and w=8 (OSD_JERASURE_W)
|
||||
if (jerasure_make_decoding_matrix(pg_minsize, pg_size-pg_minsize, OSD_JERASURE_W, matrix->je_data, erased, decoding_matrix, dm_ids) < 0)
|
||||
if (jerasure_make_decoding_matrix(pg_minsize, pg_size-pg_minsize, OSD_JERASURE_W, matrix->data, erased, decoding_matrix, dm_ids) < 0)
|
||||
{
|
||||
free(dm_ids);
|
||||
throw std::runtime_error("jerasure_make_decoding_matrix() failed");
|
||||
|
@ -289,64 +228,13 @@ static void* get_jerasure_decoding_matrix(osd_rmw_stripe_t *stripes, int pg_size
|
|||
memcpy(erased_copy, erased, pg_size*sizeof(int));
|
||||
matrix->decodings.emplace((reed_sol_erased_t){ .data = erased_copy, .size = pg_size }, dm_ids);
|
||||
return dm_ids;
|
||||
#endif
|
||||
}
|
||||
return dec_it->second;
|
||||
}
|
||||
|
||||
#ifdef WITH_ISAL
|
||||
void reconstruct_stripes_ec(osd_rmw_stripe_t *stripes, int pg_size, int pg_minsize, uint32_t bitmap_size)
|
||||
void reconstruct_stripes_jerasure(osd_rmw_stripe_t *stripes, int pg_size, int pg_minsize, uint32_t bitmap_size)
|
||||
{
|
||||
uint8_t *dectable = (uint8_t*)get_jerasure_decoding_matrix(stripes, pg_size, pg_minsize);
|
||||
if (!dectable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
uint8_t *data_ptrs[pg_size];
|
||||
int wanted_base = 0, wanted = 0;
|
||||
uint64_t read_start = 0, read_end = 0;
|
||||
auto recover_seq = [&]()
|
||||
{
|
||||
int orig = 0;
|
||||
for (int other = 0; other < pg_size; other++)
|
||||
{
|
||||
if (stripes[other].read_end != 0 && !stripes[other].missing)
|
||||
{
|
||||
assert(stripes[other].read_start <= read_start);
|
||||
assert(stripes[other].read_end >= read_end);
|
||||
data_ptrs[orig++] = (uint8_t*)stripes[other].read_buf + (read_start - stripes[other].read_start);
|
||||
}
|
||||
}
|
||||
ec_encode_data(
|
||||
read_end-read_start, pg_minsize, wanted, dectable + wanted_base*32*pg_minsize,
|
||||
data_ptrs, data_ptrs + pg_minsize
|
||||
);
|
||||
wanted_base += wanted;
|
||||
wanted = 0;
|
||||
};
|
||||
for (int role = 0; role < pg_minsize; role++)
|
||||
{
|
||||
if (stripes[role].read_end != 0 && stripes[role].missing)
|
||||
{
|
||||
if (read_end && (stripes[role].read_start != read_start ||
|
||||
stripes[role].read_end != read_end))
|
||||
{
|
||||
recover_seq();
|
||||
}
|
||||
read_start = stripes[role].read_start;
|
||||
read_end = stripes[role].read_end;
|
||||
data_ptrs[pg_minsize + (wanted++)] = (uint8_t*)stripes[role].read_buf;
|
||||
}
|
||||
}
|
||||
if (wanted > 0)
|
||||
{
|
||||
recover_seq();
|
||||
}
|
||||
}
|
||||
#else
|
||||
void reconstruct_stripes_ec(osd_rmw_stripe_t *stripes, int pg_size, int pg_minsize, uint32_t bitmap_size)
|
||||
{
|
||||
int *dm_ids = (int*)get_jerasure_decoding_matrix(stripes, pg_size, pg_minsize);
|
||||
int *dm_ids = get_jerasure_decoding_matrix(stripes, pg_size, pg_minsize);
|
||||
if (!dm_ids)
|
||||
{
|
||||
return;
|
||||
|
@ -354,9 +242,7 @@ void reconstruct_stripes_ec(osd_rmw_stripe_t *stripes, int pg_size, int pg_minsi
|
|||
int *decoding_matrix = dm_ids + pg_minsize;
|
||||
char *data_ptrs[pg_size];
|
||||
for (int role = 0; role < pg_size; role++)
|
||||
{
|
||||
data_ptrs[role] = NULL;
|
||||
}
|
||||
for (int role = 0; role < pg_minsize; role++)
|
||||
{
|
||||
if (stripes[role].read_end != 0 && stripes[role].missing)
|
||||
|
@ -393,7 +279,6 @@ void reconstruct_stripes_ec(osd_rmw_stripe_t *stripes, int pg_size, int pg_minsi
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int extend_missing_stripes(osd_rmw_stripe_t *stripes, osd_num_t *osd_set, int pg_minsize, int pg_size)
|
||||
{
|
||||
|
@ -794,12 +679,12 @@ void calc_rmw_parity_xor(osd_rmw_stripe_t *stripes, int pg_size, uint64_t *read_
|
|||
calc_rmw_parity_copy_parity(stripes, pg_size, pg_minsize, read_osd_set, write_osd_set, chunk_size, start, end);
|
||||
}
|
||||
|
||||
void calc_rmw_parity_ec(osd_rmw_stripe_t *stripes, int pg_size, int pg_minsize,
|
||||
void calc_rmw_parity_jerasure(osd_rmw_stripe_t *stripes, int pg_size, int pg_minsize,
|
||||
uint64_t *read_osd_set, uint64_t *write_osd_set, uint32_t chunk_size, uint32_t bitmap_size)
|
||||
{
|
||||
uint32_t bitmap_granularity = bitmap_size > 0 ? chunk_size / bitmap_size / 8 : 0;
|
||||
reed_sol_matrix_t *matrix = get_ec_matrix(pg_size, pg_minsize);
|
||||
reconstruct_stripes_ec(stripes, pg_size, pg_minsize, bitmap_size);
|
||||
reed_sol_matrix_t *matrix = get_jerasure_matrix(pg_size, pg_minsize);
|
||||
reconstruct_stripes_jerasure(stripes, pg_size, pg_minsize, bitmap_size);
|
||||
uint32_t start = 0, end = 0;
|
||||
calc_rmw_parity_copy_mod(stripes, pg_size, pg_minsize, read_osd_set, write_osd_set, chunk_size, bitmap_granularity, start, end);
|
||||
if (end != 0)
|
||||
|
@ -856,34 +741,20 @@ void calc_rmw_parity_ec(osd_rmw_stripe_t *stripes, int pg_size, int pg_minsize,
|
|||
curbuf[i]++;
|
||||
}
|
||||
}
|
||||
#ifdef WITH_ISAL
|
||||
ec_encode_data(
|
||||
next_end-pos, pg_minsize, pg_size-pg_minsize, matrix->isal_data,
|
||||
(uint8_t**)data_ptrs, (uint8_t**)data_ptrs+pg_minsize
|
||||
);
|
||||
#else
|
||||
jerasure_matrix_encode(
|
||||
pg_minsize, pg_size-pg_minsize, OSD_JERASURE_W, matrix->je_data,
|
||||
pg_minsize, pg_size-pg_minsize, OSD_JERASURE_W, matrix->data,
|
||||
(char**)data_ptrs, (char**)data_ptrs+pg_minsize, next_end-pos
|
||||
);
|
||||
#endif
|
||||
pos = next_end;
|
||||
}
|
||||
for (int i = 0; i < pg_size; i++)
|
||||
{
|
||||
data_ptrs[i] = stripes[i].bmp_buf;
|
||||
}
|
||||
#ifdef WITH_ISAL
|
||||
ec_encode_data(
|
||||
bitmap_size, pg_minsize, pg_size-pg_minsize, matrix->isal_data,
|
||||
(uint8_t**)data_ptrs, (uint8_t**)data_ptrs+pg_minsize
|
||||
);
|
||||
#else
|
||||
jerasure_matrix_encode(
|
||||
pg_minsize, pg_size-pg_minsize, OSD_JERASURE_W, matrix->je_data,
|
||||
pg_minsize, pg_size-pg_minsize, OSD_JERASURE_W, matrix->data,
|
||||
(char**)data_ptrs, (char**)data_ptrs+pg_minsize, bitmap_size
|
||||
);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
calc_rmw_parity_copy_parity(stripes, pg_size, pg_minsize, read_osd_set, write_osd_set, chunk_size, start, end);
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "object_id.h"
|
||||
#include "osd_id.h"
|
||||
|
||||
// Memory allocation alignment (page size is usually optimal)
|
||||
#ifndef MEM_ALIGNMENT
|
||||
#define MEM_ALIGNMENT 4096
|
||||
#endif
|
||||
|
@ -45,9 +44,9 @@ void* calc_rmw(void *request_buf, osd_rmw_stripe_t *stripes, uint64_t *read_osd_
|
|||
void calc_rmw_parity_xor(osd_rmw_stripe_t *stripes, int pg_size, uint64_t *read_osd_set, uint64_t *write_osd_set,
|
||||
uint32_t chunk_size, uint32_t bitmap_size);
|
||||
|
||||
void use_ec(int pg_size, int pg_minsize, bool use);
|
||||
void use_jerasure(int pg_size, int pg_minsize, bool use);
|
||||
|
||||
void reconstruct_stripes_ec(osd_rmw_stripe_t *stripes, int pg_size, int pg_minsize, uint32_t bitmap_size);
|
||||
void reconstruct_stripes_jerasure(osd_rmw_stripe_t *stripes, int pg_size, int pg_minsize, uint32_t bitmap_size);
|
||||
|
||||
void calc_rmw_parity_ec(osd_rmw_stripe_t *stripes, int pg_size, int pg_minsize,
|
||||
void calc_rmw_parity_jerasure(osd_rmw_stripe_t *stripes, int pg_size, int pg_minsize,
|
||||
uint64_t *read_osd_set, uint64_t *write_osd_set, uint32_t chunk_size, uint32_t bitmap_size);
|
||||
|
|
|
@ -587,14 +587,14 @@ void test12()
|
|||
input buffer: [ write0, write1 ],
|
||||
rmw buffer: [ write2, write3, read0, read1 ],
|
||||
}
|
||||
then, after calc_rmw_parity_ec(): all the same
|
||||
then, after calc_rmw_parity_jerasure(): all the same
|
||||
then simulate read with read_osd_set=[0,0,3,4] and check read0,read1 buffers
|
||||
|
||||
***/
|
||||
|
||||
void test13()
|
||||
{
|
||||
use_ec(4, 2, true);
|
||||
use_jerasure(4, 2, true);
|
||||
osd_num_t osd_set[4] = { 1, 2, 0, 0 };
|
||||
osd_num_t write_osd_set[4] = { 1, 2, 3, 4 };
|
||||
osd_rmw_stripe_t stripes[4] = {};
|
||||
|
@ -628,7 +628,7 @@ void test13()
|
|||
set_pattern(write_buf, 8192, PATTERN3);
|
||||
set_pattern(stripes[0].read_buf, 128*1024-4096, PATTERN1);
|
||||
set_pattern(stripes[1].read_buf, 128*1024-4096, PATTERN2);
|
||||
calc_rmw_parity_ec(stripes, 4, 2, osd_set, write_osd_set, 128*1024, 0);
|
||||
calc_rmw_parity_jerasure(stripes, 4, 2, osd_set, write_osd_set, 128*1024, 0);
|
||||
assert(stripes[0].write_start == 128*1024-4096 && stripes[0].write_end == 128*1024);
|
||||
assert(stripes[1].write_start == 0 && stripes[1].write_end == 4096);
|
||||
assert(stripes[2].write_start == 0 && stripes[2].write_end == 128*1024);
|
||||
|
@ -663,7 +663,7 @@ void test13()
|
|||
assert(stripes[3].read_buf == (uint8_t*)read_buf+3*128*1024);
|
||||
memcpy((uint8_t*)read_buf+2*128*1024, rmw_buf, 128*1024);
|
||||
memcpy((uint8_t*)read_buf+3*128*1024, (uint8_t*)rmw_buf+128*1024, 128*1024);
|
||||
reconstruct_stripes_ec(stripes, 4, 2, 0);
|
||||
reconstruct_stripes_jerasure(stripes, 4, 2, 0);
|
||||
check_pattern(stripes[0].read_buf, 128*1024-4096, PATTERN1);
|
||||
check_pattern(stripes[0].read_buf+128*1024-4096, 4096, PATTERN3);
|
||||
check_pattern(stripes[1].read_buf, 4096, PATTERN3);
|
||||
|
@ -694,14 +694,14 @@ void test13()
|
|||
assert(stripes[3].read_buf == (uint8_t*)read_buf+2*128*1024);
|
||||
memcpy((uint8_t*)read_buf+128*1024, rmw_buf, 128*1024);
|
||||
memcpy((uint8_t*)read_buf+2*128*1024, (uint8_t*)rmw_buf+128*1024, 128*1024);
|
||||
reconstruct_stripes_ec(stripes, 4, 2, 0);
|
||||
reconstruct_stripes_jerasure(stripes, 4, 2, 0);
|
||||
check_pattern(stripes[0].read_buf, 128*1024-4096, PATTERN1);
|
||||
check_pattern(stripes[0].read_buf+128*1024-4096, 4096, PATTERN3);
|
||||
free(read_buf);
|
||||
// Huh done
|
||||
free(rmw_buf);
|
||||
free(write_buf);
|
||||
use_ec(4, 2, false);
|
||||
use_jerasure(4, 2, false);
|
||||
}
|
||||
|
||||
/***
|
||||
|
@ -714,7 +714,7 @@ void test13()
|
|||
input buffer: [ write0, write1 ],
|
||||
rmw buffer: [ write2, read0, read1 ],
|
||||
}
|
||||
then, after calc_rmw_parity_ec(): all the same
|
||||
then, after calc_rmw_parity_jerasure(): all the same
|
||||
then simulate read with read_osd_set=[0,2,3] and check read0 buffer
|
||||
|
||||
***/
|
||||
|
@ -722,7 +722,7 @@ void test13()
|
|||
void test14()
|
||||
{
|
||||
const int bmp = 4;
|
||||
use_ec(3, 2, true);
|
||||
use_jerasure(3, 2, true);
|
||||
osd_num_t osd_set[3] = { 1, 2, 0 };
|
||||
osd_num_t write_osd_set[3] = { 1, 2, 3 };
|
||||
osd_rmw_stripe_t stripes[3] = {};
|
||||
|
@ -757,7 +757,7 @@ void test14()
|
|||
memset(stripes[0].bmp_buf, 0, bmp);
|
||||
memset(stripes[1].bmp_buf, 0, bmp);
|
||||
memset(stripes[2].bmp_buf, 0, bmp);
|
||||
calc_rmw_parity_ec(stripes, 3, 2, osd_set, write_osd_set, 128*1024, bmp);
|
||||
calc_rmw_parity_jerasure(stripes, 3, 2, osd_set, write_osd_set, 128*1024, bmp);
|
||||
assert(*(uint32_t*)stripes[0].bmp_buf == 0x80000000);
|
||||
assert(*(uint32_t*)stripes[1].bmp_buf == 0x00000001);
|
||||
assert(*(uint32_t*)stripes[2].bmp_buf == 0x80000001); // jerasure 2+1 is still just XOR
|
||||
|
@ -793,12 +793,12 @@ void test14()
|
|||
set_pattern(stripes[1].read_buf, 4096, PATTERN3);
|
||||
set_pattern(stripes[1].read_buf+4096, 128*1024-4096, PATTERN2);
|
||||
memcpy(stripes[2].read_buf, rmw_buf, 128*1024);
|
||||
reconstruct_stripes_ec(stripes, 3, 2, bmp);
|
||||
reconstruct_stripes_jerasure(stripes, 3, 2, bmp);
|
||||
check_pattern(stripes[0].read_buf, 128*1024-4096, PATTERN1);
|
||||
check_pattern(stripes[0].read_buf+128*1024-4096, 4096, PATTERN3);
|
||||
free(read_buf);
|
||||
// Huh done
|
||||
free(rmw_buf);
|
||||
free(write_buf);
|
||||
use_ec(3, 2, false);
|
||||
use_jerasure(3, 2, false);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#define OBJ_DEGRADED 0x02
|
||||
#define OBJ_INCOMPLETE 0x04
|
||||
#define OBJ_MISPLACED 0x08
|
||||
#define OBJ_DELETED 0x10
|
||||
#define OBJ_NEEDS_STABLE 0x10000
|
||||
#define OBJ_NEEDS_ROLLBACK 0x20000
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
|
|||
|
||||
Name: Vitastor
|
||||
Description: Vitastor client library
|
||||
Version: 0.7.1
|
||||
Version: 0.6.17
|
||||
Libs: -L${libdir} -lvitastor_client
|
||||
Cflags: -I${includedir}
|
||||
|
||||
|
|
|
@ -1,39 +1,18 @@
|
|||
#!/bin/bash
|
||||
#!/bin/bash -ex
|
||||
|
||||
. `dirname $0`/common.sh
|
||||
|
||||
OSD_SIZE=${OSD_SIZE:-1024}
|
||||
PG_COUNT=${PG_COUNT:-1}
|
||||
# OSD_COUNT
|
||||
SCHEME=${SCHEME:-replicated}
|
||||
# OSD_ARGS
|
||||
# PG_SIZE
|
||||
# PG_MINSIZE
|
||||
|
||||
if [ "$SCHEME" = "ec" ]; then
|
||||
OSD_COUNT=${OSD_COUNT:-5}
|
||||
else
|
||||
OSD_COUNT=${OSD_COUNT:-3}
|
||||
fi
|
||||
|
||||
if [ "$IMMEDIATE_COMMIT" != "" ]; then
|
||||
NO_SAME="--journal_no_same_sector_overwrites true --journal_sector_buffer_count 1024 --disable_data_fsync 1 --immediate_commit all --log_level 1"
|
||||
$ETCDCTL put /vitastor/config/global '{"recovery_queue_depth":1,"osd_out_time":1,"immediate_commit":"all"}'
|
||||
else
|
||||
NO_SAME="--journal_sector_buffer_count 1024 --log_level 1"
|
||||
$ETCDCTL put /vitastor/config/global '{"recovery_queue_depth":1,"osd_out_time":1}'
|
||||
fi
|
||||
|
||||
start_osd()
|
||||
{
|
||||
local i=$1
|
||||
build/src/vitastor-osd --osd_num $i --bind_address 127.0.0.1 $NO_SAME $OSD_ARGS --etcd_address $ETCD_URL $(build/src/vitastor-cli simple-offsets --format options ./testdata/test_osd$i.bin 2>/dev/null) &>./testdata/osd$i.log &
|
||||
eval OSD${i}_PID=$!
|
||||
}
|
||||
PG_SIZE=${PG_SIZE:-3}
|
||||
PG_MINSIZE=${PG_MINSIZE:-2}
|
||||
OSD_COUNT=${OSD_COUNT:-3}
|
||||
SCHEME=${SCHEME:-ec}
|
||||
|
||||
for i in $(seq 1 $OSD_COUNT); do
|
||||
dd if=/dev/zero of=./testdata/test_osd$i.bin bs=1024 count=1 seek=$((OSD_SIZE*1024-1))
|
||||
start_osd $i
|
||||
build/src/vitastor-osd --osd_num $i --bind_address 127.0.0.1 $OSD_ARGS --etcd_address $ETCD_URL $(build/src/vitastor-cli simple-offsets --format options ./testdata/test_osd$i.bin 2>/dev/null) &>./testdata/osd$i.log &
|
||||
eval OSD${i}_PID=$!
|
||||
done
|
||||
|
||||
cd mon
|
||||
|
@ -42,62 +21,43 @@ cd ..
|
|||
node mon/mon-main.js --etcd_url $ETCD_URL --etcd_prefix "/vitastor" --verbose 1 &>./testdata/mon.log &
|
||||
MON_PID=$!
|
||||
|
||||
if [ "$SCHEME" = "ec" ]; then
|
||||
PG_SIZE=${PG_SIZE:-5}
|
||||
PG_MINSIZE=${PG_MINSIZE:-3}
|
||||
PG_DATA_SIZE=$PG_MINSIZE
|
||||
POOLCFG='"scheme":"ec","parity_chunks":'$((PG_SIZE-PG_MINSIZE))
|
||||
elif [ "$SCHEME" = "xor" ]; then
|
||||
PG_SIZE=${PG_SIZE:-3}
|
||||
PG_MINSIZE=${PG_MINSIZE:-2}
|
||||
PG_DATA_SIZE=$PG_MINSIZE
|
||||
POOLCFG='"scheme":"xor","parity_chunks":'$((PG_SIZE-PG_MINSIZE))
|
||||
if [ -n "$GLOBAL_CONF" ]; then
|
||||
$ETCDCTL put /vitastor/config/global "$GLOBAL_CONF"
|
||||
fi
|
||||
|
||||
if [ "$SCHEME" = "replicated" ]; then
|
||||
$ETCDCTL put /vitastor/config/pools '{"1":{"name":"testpool","scheme":"replicated","pg_size":'$PG_SIZE',"pg_minsize":'$PG_MINSIZE',"pg_count":'$PG_COUNT',"failure_domain":"osd"}}'
|
||||
else
|
||||
PG_SIZE=${PG_SIZE:-2}
|
||||
PG_MINSIZE=${PG_MINSIZE:-2}
|
||||
PG_DATA_SIZE=1
|
||||
POOLCFG='"scheme":"replicated"'
|
||||
fi
|
||||
POOLCFG='"name":"testpool","failure_domain":"osd",'$POOLCFG
|
||||
$ETCDCTL put /vitastor/config/pools '{"1":{'$POOLCFG',"pg_size":'$PG_SIZE',"pg_minsize":'$PG_MINSIZE',"pg_count":'$PG_COUNT'}}'
|
||||
|
||||
sleep 2
|
||||
|
||||
if ! ($ETCDCTL get /vitastor/config/pgs --print-value-only | jq -s -e '(.[0].items["1"] | map((.osd_set | select(. > 0)) | length == '$PG_SIZE') | length) == '$PG_COUNT); then
|
||||
format_error "FAILED: $PG_COUNT PGS NOT CONFIGURED"
|
||||
$ETCDCTL put /vitastor/config/pools '{"1":{"name":"testpool","scheme":"xor","pg_size":'$PG_SIZE',"pg_minsize":'$PG_MINSIZE',"parity_chunks":1,"pg_count":'$PG_COUNT',"failure_domain":"osd"}}'
|
||||
fi
|
||||
|
||||
if ! ($ETCDCTL get --prefix /vitastor/pg/state/ --print-value-only | jq -s -e '([ .[] | select(.state == ["active"]) ] | length) == '$PG_COUNT); then
|
||||
format_error "FAILED: $PG_COUNT PGS NOT UP"
|
||||
fi
|
||||
|
||||
try_reweight()
|
||||
wait_up()
|
||||
{
|
||||
osd=$1
|
||||
w=$2
|
||||
$ETCDCTL put /vitastor/config/osd/$osd '{"reweight":'$w'}'
|
||||
sleep 3
|
||||
}
|
||||
|
||||
wait_finish_rebalance()
|
||||
{
|
||||
sec=$1
|
||||
i=0
|
||||
local sec=$1
|
||||
local i=0
|
||||
local configured=0
|
||||
while [[ $i -lt $sec ]]; do
|
||||
($ETCDCTL get --prefix /vitastor/pg/state/ --print-value-only | jq -s -e '([ .[] | select(.state == ["active"]) ] | length) == 32') && \
|
||||
break
|
||||
if [ $i -eq 60 ]; then
|
||||
format_error "Rebalance couldn't finish in $sec seconds"
|
||||
if $ETCDCTL get /vitastor/config/pgs --print-value-only | jq -s -e '(. | length) != 0 and ([ .[0].items["1"][] |
|
||||
select(((.osd_set | select(. != 0) | sort | unique) | length) == '$PG_SIZE') ] | length) == '$PG_COUNT; then
|
||||
configured=1
|
||||
if $ETCDCTL get /vitastor/pg/state/1/ --prefix --print-value-only | jq -s -e '[ .[] | select(.state == ["active"]) ] | length == '$PG_COUNT; then
|
||||
break
|
||||
fi
|
||||
fi
|
||||
sleep 1
|
||||
i=$((i+1))
|
||||
if [ $i -eq $sec ]; then
|
||||
if [[ $configured -ne 0 ]]; then
|
||||
format_error "FAILED: $PG_COUNT PG(s) NOT CONFIGURED"
|
||||
fi
|
||||
format_error "FAILED: $PG_COUNT PG(s) NOT UP"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
check_qemu()
|
||||
{
|
||||
if ! cmp build/src/block-vitastor.so /usr/lib/x86_64-linux-gnu/qemu/block-vitastor.so; then
|
||||
sudo rm -f /usr/lib/x86_64-linux-gnu/qemu/block-vitastor.so
|
||||
sudo ln -s "$(realpath .)/build/src/block-vitastor.so" /usr/lib/x86_64-linux-gnu/qemu/block-vitastor.so
|
||||
fi
|
||||
}
|
||||
wait_up 60
|
||||
|
||||
if ! cmp build/src/block-vitastor.so /usr/lib/x86_64-linux-gnu/qemu/block-vitastor.so; then
|
||||
sudo rm -f /usr/lib/x86_64-linux-gnu/qemu/block-vitastor.so
|
||||
sudo ln -s "$(realpath .)/build/src/block-vitastor.so" /usr/lib/x86_64-linux-gnu/qemu/block-vitastor.so
|
||||
fi
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
#!/bin/bash
|
||||
|
||||
. `dirname $0`/common.sh
|
||||
|
||||
if [ "$IMMEDIATE_COMMIT" != "" ]; then
|
||||
NO_SAME="--journal_no_same_sector_overwrites true --journal_sector_buffer_count 1024 --disable_data_fsync 1 --immediate_commit all --log_level 1"
|
||||
$ETCDCTL put /vitastor/config/global '{"recovery_queue_depth":1,"osd_out_time":1,"immediate_commit":"all"}'
|
||||
else
|
||||
NO_SAME="--journal_sector_buffer_count 1024 --log_level 1"
|
||||
$ETCDCTL put /vitastor/config/global '{"recovery_queue_depth":1,"osd_out_time":1}'
|
||||
fi
|
||||
|
||||
start_osd()
|
||||
{
|
||||
local i=$1
|
||||
build/src/vitastor-osd --osd_num $i --bind_address 127.0.0.1 $NO_SAME $OSD_ARGS --etcd_address $ETCD_URL $(build/src/vitastor-cli simple-offsets --format options ./testdata/test_osd$i.bin 2>/dev/null) &>./testdata/osd$i.log &
|
||||
eval OSD${i}_PID=$!
|
||||
}
|
||||
|
||||
OSD_SIZE=1024
|
||||
OSD_COUNT=7
|
||||
OSD_ARGS=
|
||||
for i in $(seq 1 $OSD_COUNT); do
|
||||
dd if=/dev/zero of=./testdata/test_osd$i.bin bs=1024 count=1 seek=$((OSD_SIZE*1024-1))
|
||||
start_osd $i
|
||||
done
|
||||
|
||||
cd mon
|
||||
npm install
|
||||
cd ..
|
||||
node mon/mon-main.js --etcd_url $ETCD_URL --etcd_prefix "/vitastor" --verbose 1 &>./testdata/mon.log &
|
||||
MON_PID=$!
|
||||
|
||||
if [ "$EC" != "" ]; then
|
||||
PG_SIZE=3
|
||||
POOLCFG='"scheme":"xor","pg_size":3,"pg_minsize":2,"parity_chunks":1'
|
||||
else
|
||||
PG_SIZE=${PG_SIZE:-2}
|
||||
POOLCFG='"scheme":"replicated","pg_size":'$PG_SIZE',"pg_minsize":2'
|
||||
fi
|
||||
$ETCDCTL put /vitastor/config/pools '{"1":{"name":"testpool",'$POOLCFG',"pg_count":32,"failure_domain":"osd"}}'
|
||||
|
||||
sleep 2
|
||||
|
||||
if ! ($ETCDCTL get /vitastor/config/pgs --print-value-only | jq -s -e '(.[0].items["1"] | map((.osd_set | select(. > 0)) | length == '$PG_SIZE') | length) == 32'); then
|
||||
format_error "FAILED: 32 PGS NOT CONFIGURED"
|
||||
fi
|
||||
|
||||
if ! ($ETCDCTL get --prefix /vitastor/pg/state/ --print-value-only | jq -s -e '([ .[] | select(.state == ["active"]) ] | length) == 32'); then
|
||||
format_error "FAILED: 32 PGS NOT UP"
|
||||
fi
|
||||
|
||||
try_reweight()
|
||||
{
|
||||
osd=$1
|
||||
w=$2
|
||||
$ETCDCTL put /vitastor/config/osd/$osd '{"reweight":'$w'}'
|
||||
sleep 3
|
||||
}
|
||||
|
||||
wait_finish_rebalance()
|
||||
{
|
||||
sec=$1
|
||||
i=0
|
||||
while [[ $i -lt $sec ]]; do
|
||||
($ETCDCTL get --prefix /vitastor/pg/state/ --print-value-only | jq -s -e '([ .[] | select(.state == ["active"]) ] | length) == 32') && \
|
||||
break
|
||||
sleep 1
|
||||
i=$((i+1))
|
||||
if [ $i -eq $sec ]; then
|
||||
format_error "Rebalance couldn't finish in $sec seconds"
|
||||
fi
|
||||
done
|
||||
}
|
|
@ -8,11 +8,11 @@ cd $(dirname $0)
|
|||
./test_cas.sh
|
||||
|
||||
./test_change_pg_count.sh
|
||||
SCHEME=ec ./test_change_pg_count.sh
|
||||
EC=1 ./test_change_pg_count.sh
|
||||
|
||||
./test_change_pg_size.sh
|
||||
|
||||
./test_create_nomaxid.sh
|
||||
./test_degraded_delete.sh
|
||||
|
||||
./test_etcd_fail.sh
|
||||
|
||||
|
@ -20,8 +20,8 @@ SCHEME=ec ./test_change_pg_count.sh
|
|||
|
||||
./test_interrupted_rebalance.sh
|
||||
IMMEDIATE_COMMIT=1 ./test_interrupted_rebalance.sh
|
||||
SCHEME=ec ./test_interrupted_rebalance.sh
|
||||
SCHEME=ec IMMEDIATE_COMMIT=1 ./test_interrupted_rebalance.sh
|
||||
EC=1 ./test_interrupted_rebalance.sh
|
||||
EC=1 IMMEDIATE_COMMIT=1 ./test_interrupted_rebalance.sh
|
||||
|
||||
./test_minsize_1.sh
|
||||
|
||||
|
@ -29,17 +29,17 @@ SCHEME=ec IMMEDIATE_COMMIT=1 ./test_interrupted_rebalance.sh
|
|||
|
||||
./test_rebalance_verify.sh
|
||||
IMMEDIATE_COMMIT=1 ./test_rebalance_verify.sh
|
||||
SCHEME=ec ./test_rebalance_verify.sh
|
||||
SCHEME=ec IMMEDIATE_COMMIT=1 ./test_rebalance_verify.sh
|
||||
EC=1 ./test_rebalance_verify.sh
|
||||
EC=1 IMMEDIATE_COMMIT=1 ./test_rebalance_verify.sh
|
||||
|
||||
./test_rm.sh
|
||||
|
||||
./test_snapshot.sh
|
||||
SCHEME=ec ./test_snapshot.sh
|
||||
SCHEME=replicated ./test_snapshot.sh
|
||||
|
||||
./test_splitbrain.sh
|
||||
|
||||
./test_write.sh
|
||||
SCHEME=xor ./test_write.sh
|
||||
SCHEME=replicated ./test_write.sh
|
||||
|
||||
./test_write_no_same.sh
|
||||
|
|
|
@ -1,11 +1,41 @@
|
|||
#!/bin/bash -ex
|
||||
|
||||
OSD_COUNT=${OSD_COUNT:-6}
|
||||
PG_COUNT=16
|
||||
. `dirname $0`/common.sh
|
||||
|
||||
. `dirname $0`/run_3osds.sh
|
||||
if [ "$EC" != "" ]; then
|
||||
POOLCFG='"scheme":"xor","pg_size":3,"pg_minsize":2,"parity_chunks":1'
|
||||
NOBJ=512
|
||||
else
|
||||
POOLCFG='"scheme":"replicated","pg_size":2,"pg_minsize":2'
|
||||
NOBJ=1024
|
||||
fi
|
||||
|
||||
NOBJ=$(((128*8+PG_DATA_SIZE-1)/PG_DATA_SIZE))
|
||||
OSD_SIZE=1024
|
||||
OSD_COUNT=6
|
||||
OSD_ARGS=
|
||||
for i in $(seq 1 $OSD_COUNT); do
|
||||
dd if=/dev/zero of=./testdata/test_osd$i.bin bs=1024 count=1 seek=$((OSD_SIZE*1024-1))
|
||||
build/src/vitastor-osd --osd_num $i --bind_address 127.0.0.1 $OSD_ARGS --etcd_address $ETCD_URL $(build/src/vitastor-cli simple-offsets --format options ./testdata/test_osd$i.bin 2>/dev/null) &>./testdata/osd$i.log &
|
||||
eval OSD${i}_PID=$!
|
||||
done
|
||||
|
||||
cd mon
|
||||
npm install
|
||||
cd ..
|
||||
node mon/mon-main.js --etcd_url $ETCD_URL --etcd_prefix "/vitastor" --verbose 1 &>./testdata/mon.log &
|
||||
MON_PID=$!
|
||||
|
||||
$ETCDCTL put /vitastor/config/pools '{"1":{"name":"testpool",'$POOLCFG',"pg_count":16,"failure_domain":"osd"}}'
|
||||
|
||||
sleep 2
|
||||
|
||||
if ! ($ETCDCTL get /vitastor/config/pgs --print-value-only | jq -s -e '(.[0].items["1"] | map((.osd_set | select(. > 0)) | length == 2) | length) == 16'); then
|
||||
format_error "FAILED: 16 PGS NOT CONFIGURED"
|
||||
fi
|
||||
|
||||
if ! ($ETCDCTL get --prefix /vitastor/pg/state/ --print-value-only | jq -s -e '([ .[] | select(.state == ["active"]) ] | length) == 16'); then
|
||||
format_error "FAILED: 16 PGS NOT UP"
|
||||
fi
|
||||
|
||||
LD_PRELOAD="build/src/libfio_vitastor.so" \
|
||||
fio -thread -name=test -ioengine=build/src/libfio_vitastor.so -bs=4M -direct=1 -iodepth=1 -fsync=1 -rw=write \
|
||||
|
@ -19,7 +49,7 @@ try_change()
|
|||
echo --- Change PG count to $n --- >>testdata/osd$i.log
|
||||
done
|
||||
|
||||
$ETCDCTL put /vitastor/config/pools '{"1":{'$POOLCFG',"pg_size":'$PG_SIZE',"pg_minsize":'$PG_MINSIZE',"pg_count":'$n'}}'
|
||||
$ETCDCTL put /vitastor/config/pools '{"1":{"name":"testpool",'$POOLCFG',"pg_count":'$n',"failure_domain":"osd"}}'
|
||||
|
||||
for i in {1..10}; do
|
||||
($ETCDCTL get /vitastor/config/pgs --print-value-only | jq -s -e '(.[0].items["1"] | map((.osd_set | select(. > 0)) | length == 2) | length) == '$n) && \
|
||||
|
|
|
@ -1,16 +1,40 @@
|
|||
#!/bin/bash -ex
|
||||
|
||||
PG_COUNT=16
|
||||
SCHEME=${SCHEME:-replicated}
|
||||
. `dirname $0`/common.sh
|
||||
|
||||
. `dirname $0`/run_3osds.sh
|
||||
OSD_SIZE=1024
|
||||
OSD_COUNT=3
|
||||
OSD_ARGS=
|
||||
for i in $(seq 1 $OSD_COUNT); do
|
||||
dd if=/dev/zero of=./testdata/test_osd$i.bin bs=1024 count=1 seek=$((OSD_SIZE*1024-1))
|
||||
build/src/vitastor-osd --osd_num $i --bind_address 127.0.0.1 $OSD_ARGS --etcd_address $ETCD_URL $(build/src/vitastor-cli simple-offsets --format options ./testdata/test_osd$i.bin 2>/dev/null) &>./testdata/osd$i.log &
|
||||
eval OSD${i}_PID=$!
|
||||
done
|
||||
|
||||
cd mon
|
||||
npm install
|
||||
cd ..
|
||||
node mon/mon-main.js --etcd_url $ETCD_URL --etcd_prefix "/vitastor" &>./testdata/mon.log &
|
||||
MON_PID=$!
|
||||
|
||||
$ETCDCTL put /vitastor/config/pools '{"1":{"name":"testpool","scheme":"replicated","pg_size":3,"pg_minsize":2,"pg_count":16,"failure_domain":"osd"}}'
|
||||
|
||||
sleep 2
|
||||
|
||||
if ! ($ETCDCTL get /vitastor/config/pgs --print-value-only | jq -s -e '(.[0].items["1"] | map((.osd_set | sort) == ["1","2","3"]) | length) == 16'); then
|
||||
format_error "FAILED: 16 PGS NOT CONFIGURED"
|
||||
fi
|
||||
|
||||
if ! ($ETCDCTL get --prefix /vitastor/pg/state/ --print-value-only | jq -s -e '([ .[] | select(.state == ["active"]) ] | length) == 16'); then
|
||||
format_error "FAILED: 16 PGS NOT UP"
|
||||
fi
|
||||
|
||||
try_change()
|
||||
{
|
||||
n=$1
|
||||
s=$2
|
||||
|
||||
$ETCDCTL put /vitastor/config/pools '{"1":{'$POOLCFG',"pg_size":'$s',"pg_minsize":'$PG_MINSIZE',"pg_count":'$n'}}'
|
||||
$ETCDCTL put /vitastor/config/pools '{"1":{"name":"testpool","scheme":"replicated","pg_size":'$s',"pg_minsize":2,"pg_count":'$n',"failure_domain":"osd"}}'
|
||||
|
||||
for i in {1..10}; do
|
||||
($ETCDCTL get /vitastor/config/pgs --print-value-only |\
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
#!/bin/bash -ex
|
||||
|
||||
# Test vitastor-cli create when /index/maxid is out of sync
|
||||
|
||||
. `dirname $0`/run_3osds.sh
|
||||
|
||||
$ETCDCTL put /vitastor/config/inode/1/120 '{"name":"testimg","size":'$((1024*1024*1024))'}'
|
||||
|
||||
build/src/vitastor-cli create --etcd_address $ETCD_URL -s 1G testimg2
|
||||
|
||||
t=$($ETCDCTL get --print-value-only /vitastor/config/inode/1/121 | jq -r .name)
|
||||
if [[ "$t" != "testimg2" ]]; then
|
||||
format_error "testimg2 should've been created as inode 121"
|
||||
fi
|
||||
|
||||
t=$($ETCDCTL get --print-value-only /vitastor/index/maxid/1)
|
||||
if [[ "$t" != 121 ]]; then
|
||||
format_error "/index/maxid should've been set to 121"
|
||||
fi
|
||||
|
||||
format_green OK
|
|
@ -0,0 +1,131 @@
|
|||
#!/bin/bash -ex
|
||||
|
||||
# Run 3 OSDs
|
||||
|
||||
. `dirname $0`/run_3osds.sh
|
||||
|
||||
# Write inodes 1 and 2
|
||||
|
||||
LD_PRELOAD="build/src/libfio_vitastor.so" \
|
||||
fio -thread -name=test -ioengine=build/src/libfio_vitastor.so -bs=1M -direct=1 -iodepth=4 \
|
||||
-rw=write -etcd=$ETCD_URL -pool=1 -inode=1 -size=128M -runtime=10
|
||||
|
||||
LD_PRELOAD="build/src/libfio_vitastor.so" \
|
||||
fio -thread -name=test -ioengine=build/src/libfio_vitastor.so -bs=1M -direct=1 -iodepth=4 \
|
||||
-rw=write -etcd=$ETCD_URL -pool=1 -inode=2 -size=128M -runtime=10
|
||||
|
||||
LD_PRELOAD="build/src/libfio_vitastor.so" \
|
||||
fio -thread -name=test -ioengine=build/src/libfio_vitastor.so -bs=4k -direct=1 -iodepth=16 \
|
||||
-rw=randwrite -etcd=$ETCD_URL -pool=1 -inode=1 -size=128M -runtime=10 &>/dev/null &
|
||||
|
||||
sleep 5
|
||||
|
||||
# Stop OSD 1
|
||||
|
||||
kill -INT $OSD1_PID
|
||||
sleep 2
|
||||
|
||||
# Remove inode 2
|
||||
|
||||
build/src/vitastor-cli rm-data --etcd_address $ETCD_URL --pool 1 --inode 2
|
||||
|
||||
# Run 3 more OSDs and move PG to 4,5,6
|
||||
|
||||
for i in $(seq 4 6); do
|
||||
dd if=/dev/zero of=./testdata/test_osd$i.bin bs=1024 count=1 seek=$((OSD_SIZE*1024-1))
|
||||
build/src/vitastor-osd --osd_num $i --bind_address 127.0.0.1 $OSD_ARGS --etcd_address $ETCD_URL $(build/src/vitastor-cli simple-offsets --format options ./testdata/test_osd$i.bin 2>/dev/null) &>./testdata/osd$i.log &
|
||||
eval OSD${i}_PID=$!
|
||||
done
|
||||
|
||||
$ETCDCTL put /vitastor/config/osd/1 '{"reweight":0}'
|
||||
$ETCDCTL put /vitastor/config/osd/2 '{"reweight":0}'
|
||||
$ETCDCTL put /vitastor/config/osd/3 '{"reweight":0}'
|
||||
|
||||
# Wait for rebalance to finish
|
||||
|
||||
wait_finish_rebalance()
|
||||
{
|
||||
local sec=$1
|
||||
local st=$2
|
||||
local i=0
|
||||
while [[ $i -lt $sec ]]; do
|
||||
if $ETCDCTL get --prefix /vitastor/pg/state/ --print-value-only | jq -s -e \
|
||||
'([ .[] | select(.state == ['$st'] and (.peers | contains([1]) | not) and (.peers | contains([2,3]) | not)) ] | length) == '$PG_COUNT; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
i=$((i+1))
|
||||
if [ $i -eq $sec ]; then
|
||||
format_error "Rebalance couldn't finish in $sec seconds"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
wait_finish_rebalance 60 '"active","left_on_dead"'
|
||||
|
||||
# Stop OSD 2,3
|
||||
|
||||
kill -INT $OSD2_PID
|
||||
kill -INT $OSD3_PID
|
||||
sleep 2
|
||||
|
||||
# Verify that PGs are still active
|
||||
|
||||
if ! ($ETCDCTL get /vitastor/pg/state/1/ --prefix --print-value-only | jq -s -e '[ .[] | select(.state == ["active","left_on_dead"]) ] | length == '$PG_COUNT); then
|
||||
format_error "FAILED: $PG_COUNT PG(s) NOT UP"
|
||||
fi
|
||||
|
||||
# Start OSD 1
|
||||
|
||||
build/src/vitastor-osd --osd_num 1 --bind_address 127.0.0.1 $OSD_ARGS --etcd_address $ETCD_URL $(build/src/vitastor-cli simple-offsets --format options ./testdata/test_osd1.bin 2>/dev/null) &>./testdata/osd1.log &
|
||||
OSD1_PID=$!
|
||||
|
||||
# Verify that inode 2 is removed and inode 1 is in place
|
||||
|
||||
wait_repeer_1()
|
||||
{
|
||||
local sec=$1
|
||||
local i=0
|
||||
while [[ $i -lt $sec ]]; do
|
||||
if grep -q 'Repeer because of OSD 1' testdata/osd4.log testdata/osd5.log testdata/osd6.log; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
i=$((i+1))
|
||||
if [ $i -eq $sec ]; then
|
||||
format_error "OSD 4/5/6 do not peer with older OSD 1"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
wait_repeer_1 15
|
||||
|
||||
wait_finish_rebalance 15 '"active"'
|
||||
|
||||
if [ "$SCHEME" = "replicated" ]; then
|
||||
NOBJ=1024
|
||||
else
|
||||
NOBJ=$((1024/(PG_SIZE-1)))
|
||||
fi
|
||||
|
||||
if ! ($ETCDCTL get /vitastor/pg/stats/1/1 --print-value-only | jq -s -e '.[0].object_count == '$NOBJ); then
|
||||
format_error "FAILED: PG SHOULD CONTAIN EXACTLY 128 MB OF DATA, BUT IT DOESN'T"
|
||||
fi
|
||||
|
||||
qemu-img convert -S 4096 -p \
|
||||
-f raw "vitastor:etcd_host=127.0.0.1\:$ETCD_PORT/v3:pool=1:inode=1:size=4096" \
|
||||
-O raw ./testdata/inode1.bin
|
||||
|
||||
qemu-img convert -S 4096 -p \
|
||||
-f raw "vitastor:etcd_host=127.0.0.1\:$ETCD_PORT/v3:pool=1:inode=2:size="$((128*1024*1024)) \
|
||||
-O raw ./testdata/inode2.bin
|
||||
|
||||
if (dd if=/dev/zero bs=4096 count=1 | diff - ./testdata/inode1.bin); then
|
||||
format_error "FAILED: INODE 1 SEEMS LOST"
|
||||
fi
|
||||
|
||||
if ! (dd if=/dev/zero bs=1M count=128 | diff - ./testdata/inode2.bin); then
|
||||
format_error "FAILED: INODE 2 SEEMS RESTORED"
|
||||
fi
|
||||
|
||||
format_green OK
|
|
@ -3,10 +3,8 @@
|
|||
# Kill OSDs while writing
|
||||
|
||||
PG_SIZE=3
|
||||
OSD_COUNT=7
|
||||
PG_COUNT=32
|
||||
. `dirname $0`/run_3osds.sh
|
||||
check_qemu
|
||||
|
||||
. `dirname $0`/run_7osds.sh
|
||||
|
||||
IMG_SIZE=960
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#!/bin/bash -ex
|
||||
|
||||
OSD_COUNT=7
|
||||
PG_COUNT=32
|
||||
. `dirname $0`/run_3osds.sh
|
||||
. `dirname $0`/run_7osds.sh
|
||||
|
||||
IMG_SIZE=960
|
||||
|
||||
|
@ -34,14 +32,13 @@ try_reweight 5 1
|
|||
wait_finish_rebalance 60
|
||||
|
||||
# Check that PGs never had degraded objects !
|
||||
# FIXME: In fact, the test doesn't guarantee it because PGs aren't always peered only with full prior OSD sets :-(
|
||||
#if grep has_degraded ./testdata/mon.log; then
|
||||
# format_error "Some copies of objects were lost during interrupted rebalancings"
|
||||
#fi
|
||||
if grep has_degraded ./testdata/mon.log; then
|
||||
format_error "Some copies of objects were lost during interrupted rebalancings"
|
||||
fi
|
||||
|
||||
# Check that no objects are lost !
|
||||
nobj=`$ETCDCTL get --prefix '/vitastor/pg/stats' --print-value-only | jq -s '[ .[].object_count ] | reduce .[] as $num (0; .+$num)'`
|
||||
if [ "$nobj" -ne $((IMG_SIZE*8/PG_DATA_SIZE)) ]; then
|
||||
if [ "$nobj" -ne $((IMG_SIZE*8)) ]; then
|
||||
format_error "Data lost after multiple interrupted rebalancings"
|
||||
fi
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#!/bin/bash -ex
|
||||
|
||||
OSD_COUNT=7
|
||||
PG_COUNT=32
|
||||
. `dirname $0`/run_3osds.sh
|
||||
. `dirname $0`/run_7osds.sh
|
||||
|
||||
IMG_SIZE=256
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#!/bin/bash -ex
|
||||
|
||||
. `dirname $0`/run_3osds.sh
|
||||
check_qemu
|
||||
|
||||
# Test basic write and snapshot
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
OSD_SIZE=2048
|
||||
|
||||
. `dirname $0`/run_3osds.sh
|
||||
check_qemu
|
||||
|
||||
$ETCDCTL put /vitastor/config/inode/1/1 '{"name":"debian9","size":'$((2048*1024*1024))'}'
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#!/bin/bash -ex
|
||||
|
||||
. `dirname $0`/run_3osds.sh
|
||||
check_qemu
|
||||
|
||||
#LD_PRELOAD=libasan.so.5 \
|
||||
# fio -thread -name=test -ioengine=build/src/libfio_vitastor_sec.so -bs=4k -fsync=128 `$ETCDCTL get /vitastor/osd/state/1 --print-value-only | jq -r '"-host="+.addresses[0]+" -port="+(.port|tostring)'` -rw=write -size=32M
|
||||
|
|
Loading…
Reference in New Issue