Цей документ є чернеткою і його не слід сприймати як остаточну архітектуру.
Цей документ описує, як Вікібаза поширює зміни в репозиторії до будь-якої клієнтської вікі.
Загальний огляд
- Кожна зміна в репозиторії записується в таблицю змін, яка є джерелом оновлень для будь-якої клієнтської вікі (наприклад, для Вікіпедій).
- Диспетчерські скрипти періодично перевіряють цю таблицю змін.
- Про будь-які зміни в репозиторії кожна клієнтська вікі отримує сповіщення через запис у її списку завдань. Ці завдання використовуються для визнання недійсними і переписування відповідних сторінок у клієнтській вікі.
- Сповіщення про зроблені зміни записуються до таблиці нових редагувань, щоб їх можна було побачити в списках спостереження тощо.
- Послідовні зміни одним користувачем одного й того ж елемента даних можуть об'єднуватися в одну зміну щоб уникнути зайвої метушні.
Припущення та термінологія
Дані, що обробляються репозиторієм Wikibase, структуровані в деякі сутності. Кожна сутність виглядає як окрема вікісторінка зі структурованими даними. Є кілька типів сутностей, але один з них особливо важливий у цьому контексті: це елементи. Елементи особливі тим, що вони пов'язані зі сторінками статей у кожній клієнтській вікі (напр., у кожній Вікіпедії). Для детальнішої інформації, див. Первісна модель даних.
Механізм поширення ґрунтується на припущенні, що кожен елемент даних у репозиторії Вікіданих має щонайбільше одне посилання до кожної клієнтської вікі, і що лише один елемент у репозиторії може посилатися на конкретну сторінку в конкретній клієнтській вікі. Таким чином, будь-яка сторінка будь-якої клієнтської вікі може бути поєднана щонайбільше з одним елементом даних у репозиторії.
- (Див. коментар на сторінці обговорення щодо наслідків обмеження просування змін для випадків, коли сторінка Вікіпедії та елемент Вікіданих мають зв'язок 1:1)
Цей механізм також передбачає, що репозиторій та його клієнти (наприклад, Вікідані та Вікіпедії), можуть напряму під'єднуватися до бази даних один одного. Зазвичай, це означає, що вони розташовані в одній локальній мережі. Однак вікі можуть використовувати окремі сервери баз даних: вікі групуються в секції, кожна секція має одну головну базу даних та (потенційно) багато підпорядкованих баз даних (які разом формують кластер).
Комунікація між репозиторієм (Вікідані) та клієнтами (Вікіпедії) відбувається через стрічку оновлень. Наразі, це реалізовано у вигляді таблиці бази даних (таблиці змін), до якої диспетчерські скрипти мають прямий доступ через механізм "зовнішньої бази даних".
Підтимка сторонніх клієнтів, тобто клієнтських вікі та інших користувачів крім Вікімедії, наразі несуттєва й не розроблятиметься. Однак, її слід мати на увазі, ухвалюючи дизайнерські рішення.
Ведення журналів змін
Кожна зміна, що робиться в репозиторії, записується до таблиці ("таблиці змін", а саме wb_changes) у базі даних репозиторію. Таблиця змін поводиться подібно до таблиці нових редагувань MediaWiki, у тому сенсі, що вона містить зміни за певних час (напр., за день чи тиждень), а старіші записи періодично вилучаються. Проте, на відміну від таблиці нових редагувань, wb_changes містить інформацію, необхідну для звітування та повторення змін у клієнтській вікі: окрім інформації про те, коли й ким зроблено зміну, вона містить також структурні відмінності від попередньої версієї сутності.
Фактично, таблиця змін діє як джерело оновлень. Слід уважно ставитися до того, що відокремити таблицю бази даних як реалізацію від таблиці як джерела оновлення, щоб пізніше їх можна було замінити альтернативним механізмом, як PubHub або event bus. Однак, зверніть увагу, що протокол із семантикою черговості неприйнятний (він вимагатиме чергу на кожного клієнта).
Надсилання змін
Зміни у репозиторії (напр. wikidata.org) надсилаються до клієнтських вікі (напр. Вікіпедій) з допомогою диспетчерського скрипта. Цей скрипт запитує таблицю wb_changes щодо змін, і надсилає їх до клієнтських вікі через дописування відповідних завдань у список завдань клієнта.
The dispatcher script is designed in a way that allows any number of instances to run and share load without any prior knowledge of each other. They are coordinated via the repoysitory's database using the wb_changes_dispatch table:
- chd_client: назва бази даних клієнта (основний ключ).
- chd_latest_change: ID останньої зміни, яка була надіслана до клієнта.
- chd_touched: часова мітка, яка показує, коли зміни було надіслано до клієнта.
- chd_lock_name: назва глобального блокування, використаного диспетчером, що зараз оновлює цього клієнта (або NULL).
Диспетчер працює, роблячи такі кроки:
- Lock and initialize
- Choose a client to update from the list of known clients.
- Start DB transaction on repo's master database.
- Read the given client's row from wb_changes_dispatch (if missing, assume chd_latest_change = 0).
- If chd_lock_name is not null, call IS_FREE_LOCK(chd_lock_name) on the client's master database.
- If that returns 0, another dispatcher is holding the lock. Exit (or try another client).
- Decide on a lock name (dbname.wb_changes_dispatch.client or some such) and use GET_LOCK() to grab that lock on the client's master database.
- Update the client's row in wb_changes_dispatch with the new lock name in chd_lock_name.
- Commit DB transaction on repo's master database.
- Perform the dispatch
- Get n changes with IDs > chd_latest_change from wb_changes in the repo's database. n is the configured batch size.
- Filter changes for those relevant to this client wiki (optional, and may prove tricky in complex cases, e.g. cached queries).
- Post the corresponding change notification jobs to the client wiki's job queue.
- Log and unlock
- Start DB transaction on repo's master database.
- Update the client's row in wb_changes_dispatch with chd_lock_name=NULL and updated chd_latest_change and chd_touched.
- Call RELEASE_LOCK() to release the global lock we were holding.
- Commit DB transaction on repo's master database.
Це може повторюватися багато разів одним процесом, з налаштовуваною затримкою між запусками.
Changes Notification Jobs
The dispatcher posts changes notification jobs to the client wiki's job queue. These jobs contain a list of wikidata changes. When processing such a job, the cleint wiki performs the following steps:
- If the client maintains a local cache of entity data, update it.
- Find which pages need to be re-rendered after the change. Invalidate them and purge them from the web caches. Optionally, schedule re-render (or link update) jobs, or even re-render the page directly.
- Find which pages have changes that do not need re-rendering of content, but influence the page output, and thus need purging of the web cached (this may at some point be the case for changes to language links).
- Inject notifications about relevant changes into the client's recentchanges table. For this, consecutive edits by the same user to the same item can be coalesced.
- Possibly also inject a "null-entry" into the respective pages' history, i.e. the revision table.
- (Див. коментар на сторінці обговорення щодо нових редагувань versus таблиця історії)
Об'єднання подій
The system described above means several database writes for every change - and potentially many reads, depending on what is needed for rendering the page. And this happens on every client wiki (potentially hundreds) for every change on the repository. Since edits on the Wikibase repository tend to be very fine grained (like setting a label or adding a site link), this can quickly get problematic. Coalescing updates could help with this problem:
As explained in the Dispatching section, entries on the changes feed are processed in batches (per default, no more than 100 entries at once).
If multiple changes to the same item are processed in the same batch, these changes can be coalesced together if they were all performed consecutively by the same user. This would reduce the number of times pages get invalidated (and thus eventually re-rendered. All the necessary entries in the recentchanges table (and possibly the revision table) can be inserted using a single database request. This process can be fine tuned by adjusting the batch size and delay between batches.