Wikipedia:Ograniczenia szablonów

Z Wikipedii, wolnej encyklopedii

Oprogramowanie MediaWiki, na którym oparta jest Wikipedia, ma kilka parametrów, które ograniczają złożoność strony, i tylko określona ilość danych może być zawarta. Te ograniczenia w głównej mierze dotyczą tych danych, które są transkludowane lub podstawione podczas rozbudowy strony, w przeciwieństwie do wprowadzania danych bezpośrednio do źródła samej strony. Niniejsza strona wyjaśnia jak i dlaczego te limity są stosowane, i jak użytkownicy mogą pracować z tymi ograniczeniami.

Kontekst[edytuj | edytuj kod]

O czym jest tutaj mowa?[edytuj | edytuj kod]

Oprogramowanie MediaWiki, które generuje kod HTML ze źródłowego wikikodu, wykorzystuje analizator składniowy, aby poradzić sobie z zawartymi danymi. Ta czynność wykonywana jest z wykorzystaniem „preprocesora”, który konwertuje wikitekst do struktury danych, znanej jako drzewo XML, a następnie wykorzystuje to drzewo do stworzenia „rozwiniętego” wikitekstu, gdzie dwu- i trój-nawiasowe struktury są zastępowane ich wynikiem.

Podczas procesu konwersji, oprogramowanie wykorzystuje kilka liczników do śledzenia złożoność strony, która jest generowana. Gdy rozpoczyna się parsowanie strony, liczniki te mają zerową wartość, ale zwiększają te wartość podczas procesu parsowania, jak opisano poniżej. Istnieją górne granice tych liczników, na których przekroczenie parser nie zezwala.

Dlaczego istnieją takie ograniczenia?[edytuj | edytuj kod]

Bardzo długie lub skomplikowane strony stają się wolne do parsowania. Może stać się to nie tylko niedogodnością dla użytkowników, ale także być wykorzystane w atakach denial of service (DoS) na serwery, w których strona żąda wymuszenia parsowania przez oprogramowanie MediaWiki nadmiernie dużą ilość danych. Takie limity przyczyniają się do zapobiegania tego rodzaju atakom i zapewnieniają, że ​​strony są ładowane w rozsądnym czasie. Niemniej jednak, czasami złożona strona mieszcząca się w tych limitach może spowodować błąd przekroczenia czasu; zależy to od stopnia obciążenia serwerów.

Praca w obrębie ograniczeń[edytuj | edytuj kod]

Gdy dana strona osiąga limity złożoności szablonów, najczęstszym rozwiązaniem jest skrócenie szablonów, z wykorzystaniem metod opisanych poniżej. Jeśli to niemożliwe, koniecznym może się okazać zawarcie większej ilości danych bezpośrednio w kodzie źródłowym, aniżeli transkludując je szablonami (na przykład formatowanie przypisów ręcznie lub z wykorzystaniem <references />, zamiast szablonu {{Przypisy}}). Z drugiej jednak strony, szablon może pomóc uniknąć duplikacji pracy serwera (patrz poniżej).

Kiedy pojawiają się problemy?[edytuj | edytuj kod]

Limity transkluzji najczęściej są osiągane na stronach wykorzystujących ten sam szablon wielokrotnie, na przykład używanie jednej transkuzji w każdym rzędzie długiej tabeli. Nawet jeśli ilość danych dodawana przez szablon do finalnej strony może być mała, jest ona uwzględniana przez liczniki parsera wraz z każdym jego wystąpieniem, stąd limit może być osiągnięty wcześniej, niż oczekiwano. Strony, które jedynie zawierają kilkadziesiąt szablonów są mało prawdopodobne, aby przekraczać ograniczenia parsera, chyba że same te szablony zawierają dużo danych.

Jak możesz się dowiedzieć?[edytuj | edytuj kod]

Gdy strona jest przetwarzana, komentarz HTML jest dodawany pod koniec źródłowego HTML. Komentarz ten zawiera finalne wartości poszczególnych liczników, na przykład:

<!--
NewPP limit report
Preprocessor node count: 173488/1000000
Post-expand include size: 1557895/2048000 bytes
Template argument size: 561438/2048000 bytes
Highest expansion depth: 29/40
Expensive parser function count: 7/500
-->

Na serwisach wiki wykorzystujących przestrzeń nazw „Moduł” na powyższej liście pojawiają się także wartości „Lua time usage” i „Lua memory usage”.

Ze względu na sposób, w jaki wartość liczników zwiększa się, pierwsze trzy liczniki zazwyczaj będą poniżej limitów. Jeśli jakiekolwiek ze wskazań zbliża się do przekroczenia limitu, wówczas możliwe jest, że niektóre z tych wzorów nie zostały rozszerzone. Każdy przypadek wystąpienia nierozwiniętego szablonu jest identyfikowany na stronie docelowej przez komentarz HTML zawierający wiadomość błędu.

Komentarz zawierający wskazania odnoszące się do modułów Lua:

<!--
NewPP limit report
Preprocessor visited node count: 19190/1000000
Preprocessor generated node count: 94558/1500000
Post-expand include size: 714878/2048000 bytes
Template argument size: 25507/2048000 bytes
Highest expansion depth: 13/40
Expensive parser function count: 13/500
Lua time usage: 0.331s
Lua memory usage: 1.25 MB
-->

Rozwijanie szablonów[edytuj | edytuj kod]

Szablony w niewykonanych gałęziach funkcji warunkowych parsera nie są rozszerzane, a zatem nie liczone. Na przykład, w kodzie źródłowym: {{#if:yes|{{bar}}|{{foo}}}}, szablon {{bar}} jest rozwinięty, ale szablon {{foo}} nie jest. Tym niemniej, możliwym jest, by szablon nie pojawiający się w końcowym wyniku był uwzględniony przez liczniki parsera. Na przykład, jeśli kod {{#if:{{foo}}|yes|no}} jest parsowany, długość rozwiniętej wersji szablonu {{foo}} będzie dodana do licznika po-ekspansyjnego, ponieważ ten musi być rozwinięty, aby zdecydować, która gałąź instrukcji warunkowej powinna być wybrana.

Licznik węzłów preprocesora[edytuj | edytuj kod]

Licznik węzłów preprocesora mierzy złożoność strony (nie ilość danych). Kiedy parser rozszerza stronę, tworzy strukturę danych znaną jako drzewo, odnoszące się do struktury HTML strony. Każdy węzeł tego drzewa który jest odwiedzany podczas rozwijania jest zliczany przez licznik wezłów preprocesora. Jeśli ten licznik zostanie przekroczony, parser przerwie proces parsowania z błędem „Node-count limit exceeded”, widocznym w generowanym kodzie HTML.

Licznik rozpoczyna się od 1 dla czystego tekstu. Para tagów nie-wiki liczona jest jako 3, tytuł – 2, itp. Link nie przyczynia się do zwiększenia licznika. Dla rozwinięcia funkcji #switch każdy sprawdzony przypadek dodaje 2 do licznika. W przypadku wielu rozwinięć tego samego szablonu, zawartość szablonu bez argumentów liczona jest tylko jednokrotnie, ale taki sam szablon z argumentami (nawet jeśli są one stałymi) zliczany jest wielokrotnie.

Rozmiar transkluzji postekspansyjnej[edytuj | edytuj kod]

Rozmiar transkluzji postekspansyjnej jest sumą długości rozwiniętych wikitekstów generowanych przez szablony, funkcje parsera oraz zmienne. Ilekroć parser jest instruowany przez kod źródłowy strony, aby rozwinąć szablon itp. (to jest: zastąpić go transkluzją lub podstawieniem), parser sumuje razem długość rozwiniętego wikitekstu, generowanego przez szablon itp. wraz z bieżącą wartością licznika strony. Jeśli suma ta przekracza limit postekspansyjny, wówczas początkowy szablon itp. nie jest rozwijany, a komunikat o błędzie dodawany jest w komentarzu w wyjściowym kodzie HTML. W przeciwnym razie, licznik postekspansyjny jest zwiększany do nowej wartości, a parsowanie jest kontynuowane. Szablon, który jest rozszerzany wielokrotnie na jednej stronie, przyczynia się więcej niż jeden raz, do zwiększenia rozmiaru postekspansyjnego.

Wywołania szablonów bez żadnego argumentu posiadają rozszerzoną pamięć cache tekstu. A więc, gdy szablon {{foo}} zawiera podrzędny metaszablon  {{bar}}, wówczas wielokrotne wywołania {{foo}} będą jedynie zwiększać postekspansyjny rozmiar w pełni rozwiniętego {{foo}}, szablon {{bar}} jest liczony tylko raz. Ale jeśli ten sam szablon wykorzystano wielokrotnie poprzez {{foo|arg}}, wówczas podrzędne szablony liczone są za każdym razem, nawet jeżeli we wszystkich zastosowano ten sam argument.

Strony, które przekraczają limit postekspansyjny są automatycznie dodawane do kategorii „Strony, w których przekroczone jest ograniczenie wielkości użytych szablonów”.

Wykorzystywanie komentarzy, tagów noinclude i includeonly[edytuj | edytuj kod]

Tylko te dane, które przetrwają etap rozwinięcia preprocesora są zliczane przez licznik postekspansyjny. Komentarze HTML w wikikodzie nie są odzwierciedlane w docelowym kodzie HTML, stąd też nie są uwzględniane przez licznik postekspansyjny. Kod zawierający tagi <noinclude> lub <includeonly> nie jest rozwijany, więc sekcje te nie przyczyniają się do zwiększenia wielkości postekspansyjnej. To oznacza również, że tagi kategorii przyczyniają się do zmiany licznika postekspansyjnego, jeśli są zawarte (do kategoryzacji stron wywołujących ten szablon).

Zagnieżdżone dołączenia[edytuj | edytuj kod]

Należy pamiętać, że rozmiary wikitekstów wszystkich rozwiniętych szablonów i funkcji parsera są dodawane, nawet w przypadku zagnieżdżania (porównaj bugzillę, 13260), więc dodatkowe poziomy zwiększają licznik. Jeśli strona A transkluduje stronę B, a strona B nic nie robi, lecz transkluduje stronę C, wówczas rozmiar strony C będzie zliczony dwukrotnie w liczniku postekspansyjnym strony A, i podobnie, jeśli szablon składa się z wywołania funkcji parsera lub funkcja parsera ma połączenia jako parametr szablonu, itp. To może być czasem złagodzone przez pozwolenie funkcji parsera na utworzenie na wyjściu jedynie nazwy szablonu, zamiast rezultatu tego szablonu, np. poprzez zmianę linijki kodu:

{{#if:{{{test|}}}|{{template1}}|{{template2}} }}

na:

{{ {{#if:{{{test|}}}|template1|template2}} }}.

Rozmiar argumentu szablonu[edytuj | edytuj kod]

Licznik „rozmiaru argumentu szablonu” śledzi całkowitą długość argumentów szablonu, która została podstawiona.

Przykład:

{{3x|{{2x|abcde}}}} posiada rozmiar argumentów równy 40 bajtów: argument abcdeabcde jest liczony 3 razy, zaś argument abcde dwukrotnie.

Największa głębokość rozwinięcia[edytuj | edytuj kod]

Strony przekraczające ten limit są automatycznie uwzględniane w kategorii „Strony, w których przekroczone jest ograniczenie wielkości użytych szablonów”.

Kosztowne wywołania funkcji parsera[edytuj | edytuj kod]

Istnieje limit 500 w liczniku kosztownych funkcji parsera, to znaczy, liczbie wywołań kosztownych funkcji parsera, którymi są:

  • #ifexist – rozgałęzienia w zależności od tego, czy dana strona istnieje. Gdy limit użycia tej funkcji zostanie przekroczony, każde wywołanie funkcji #ifexist ponad limit będzie traktowane w wyniku tak, jak gdyby zapytywana strona nie istniała.
  • PAGESINCATEGORY lub PAGESINCAT
  • PAGESIZE
  • CASCADINGSOURCES
  • REVISIONUSER, gdy używany na stronie innej niż bieżąca
  • REVISIONTIMESTAMP, gdy używany na stronie innej niż bieżąca
  • Część funkcji Lua, wiele odpowiedników innych pozycji z tej listy:

Możliwe jest także zwiększenie licznika kosztownych funkcji parsera z poziomu modułu Lua, wykorzystując mw.incrementExpensiveFunctionCount.

Strony, które przekraczają ten limit są automatycznie uwzględniane w kategorii „Strony ze zbyt dużą liczbą wywołań kosztownych funkcji parsera”.

Zobacz też: mw:Manual:$wgExpensiveParserFunctionLimit

Całkowita długość formatu łańcuchów funkcji #time jest organiczona do 6000 znaków[1]

Niestety, wartość licznika nie jest przedstawiana w raporcie limitu.

Gdy strona przekracza limity, jedyną dosadną drogą na rozwiązanie tego problemu jest wykorzystanie strony specjalnej „rozwijanie szablonów”. W przeciwieństwie do podstawienia, rozwija ona rekursywnie wszystkie poziomy na raz, bez konieczności stosowania szczególnego przygotowania szablonów z kodem {{{|safesubst:}}} lub podobnym (porównaj bug 2777). To zmniejsza wszelkie liczniki do zera, z wyjątkiem liczby węzłów preprocesora, ale nawet to będzie typowo zmniejszona do liczby, która mieści się w zakresie wartości dopuszczalnej.

Historia[edytuj | edytuj kod]

Ograniczenia dla szablonów zostały wprowadzone w życie na angielskiej Wikipedii przez Tima Starlinga 14 sierpnia 2006. Nowy preprocesor został włączony w styczniu 2008 roku, usuwając „preekspansyjny limit transkluzji” i zastępując go „licznikiem węzłów preprocesora”.