Konwencje nazewnictwa OxPHP\Shared\*
Przestrzeń nazw OxPHP\Shared\* to API współbieżności na poziomie aplikacji:
Atomic, Counter, Flag, Map, Channel, Mutex, Once, Pool.
Nazwy metod podlegają jednemu zestawowi reguł, dzięki czemu użytkownicy mogą
przewidzieć kształt API bez zaglądania do dokumentacji każdego typu z osobna.
Ten dokument stanowi kanoniczne źródło odniesienia. Nowe prymitywy oraz zmiany w istniejących MUSZĄ się do niego stosować.
Reguły
1. Odczyt wartości — get()
Konwencja PHP. Używana przez Map::get(), Counter::get(), Once::get().
Atomic::load(?Ordering $order = null) to celowy wyjątek:
jego istnienie niesie argument uporządkowania, sygnalizując, że odczyt
jest częścią kontraktu modelu pamięci, odrębnego od zwykłego gettera.
2. Zapis wartości — set(), store() dla typów atomowych
Map::set(), reset wartości Mutex (przez with), Once::getOrInit().
Atomic::store($value, ?Ordering) odzwierciedla load z tego samego powodu.
3. Liczba elementów — count(): int
Każdy kontener, który udostępnia swój bieżący rozmiar, robi to pod nazwą
count(): int. Channel dodatkowo implementuje \Countable, więc
count($ch) działa jako natywny idiom dla elementów w kolejce. Map i
Pool udostępniają count(): int jako metodę, ale nie implementują
\Countable — wywołaj ją bezpośrednio:
$ch = new OxPHP\Shared\Channel(1024);
$map = new OxPHP\Shared\Map();
$pool = new OxPHP\Shared\Pool($factory);
count($ch); // queued items (Channel implements \Countable)
$map->count(); // entries
$pool->count(); // total live slots (in-use + idle)Żadnych size(), len() ani pending() — są one zakazane na publicznej
powierzchni API, niezależnie od tego, z jakiego języka wywodzi się pamięć
mięśniowa autora implementacji.
4. Getter logiczny — prefiks is*()
Channel::isClosed().
Żadnych gołych czasowników (test, check) ani nazw specyficznych dla
domeny (closed). Prefiks is oznacza czysty odczyt właściwości logicznej.
Typ, którego stan jest bogatszy niż pojedyncza wartość logiczna, udostępnia
go jako metodę status() zwracającą enum, zamiast gettera is*() —
stosują się do tego RecvResult::status() z Channel oraz Once::status(): Once\Status
(Uninitialized/Pending/Ready/Poisoned). Sięgnij po status(),
gdy odpowiedź ma więcej niż dwa przypadki.
Mutex nie udostępnia isCorrupted() — uszkodzenie jest trwałe,
nieodwracalne i ujawniane przez CorruptedMutexException przy kolejnym
przejęciu. Z takiego sprawdzenia nie da się zrobić nic pożytecznego poza
ponownym przejęciem i przechwyceniem wyjątku.
5. Trychotomia polityki oczekiwania — try* / goła nazwa / *Timeout
Prymitywy blokujące (Channel, Mutex) wyrażają politykę oczekiwania
poprzez nazwę metody, a nie przez przeciążony argument ?float $timeout:
| Przyrostek | Zachowanie | Przykłady |
|---|---|---|
try* |
Nieblokująca; natychmiast zgłasza wariant niepowodzenia. | Channel::trySend, Channel::tryRecv, Mutex::tryWithLock |
| (goła nazwa) | Blokuje w nieskończoność (lub do anulowania Fibera żądania). | Channel::send, Channel::recv, Mutex::withLock |
*Timeout |
Ograniczone oczekiwanie. Przyjmuje obowiązkowy int $ms > 0. |
Channel::sendTimeout, Channel::recvTimeout, Mutex::withLockTimeout |
Trychotomia przenosi trzy niejednoznaczne polityki (null = w nieskończoność,
0 = próba, wartość dodatnia = ograniczone) z jednego parametru do trzech
metod o samodokumentujących się nazwach.
Argument $ms w metodach *Timeout jest ściśle dodatni. Wartości zerowe,
ujemne, niecałkowite oraz brakujące powodują zgłoszenie OxPHP\Shared\TypeException
na moście.
Operacje warunkowego powodzenia znajdują się w Map pod nazwą setIfAbsent,
a nie try*: Map::setIfAbsent zatwierdza zmianę tylko wtedy, gdy klucza
brakowało, i zwraca bool (odpowiednik HashMap::try_insert).
Nazwa setIfAbsent jest zarezerwowana dla tej jednej semantyki; nie używaj
jej ponownie w innym miejscu.
Wspólny niezmiennik dla try*: albo zwraca wynik typu wartościowego
(Result) dla Channel, albo rzuca ContentionException dla Mutex. Nigdy nie
zwraca null na zakodowanie „nie powiodło się". Tak działało stare API i to
ono rodziło niejednoznaczność operatora ?? (null-coalescing), którą
trychotomia eliminuje.
6. Compare-and-swap — compareAndSet()
Atomic::compareAndSet(), Flag::compareAndSet(). Zawsze zwraca
bool (zamiana nastąpiła albo nie).
7. Podmiana i zwrot poprzedniej wartości — swap()
Atomic::swap() dla wartości całkowitych, Flag::swap() dla wartości
logicznych. Zwraca poprzednią wartość.
8. Atomowy RMW zwracający poprzednią wartość — prefiks fetch*()
Atomic::fetchAdd(), fetchSub(), fetchAnd(), fetchOr(),
fetchXor().
Prefiks fetch koduje kontrakt zwracania: wartość sprzed operacji.
Kontrastuje to z Counter::add(), który zwraca nową wartość
(licznik agregujący w stylu LongAdder).
Przy dodawaniu nowych metod RMW najpierw wybierz kontrakt, a dopiero potem nazwę:
- zwrot poprzedniej wartości →
fetchVerb(args) - zwrot nowej wartości → goła
verb(args)
Nie mieszaj tych konwencji.
9. Reset do wartości domyślnej — clear()
Map::clear() — opróżnia kontener; zwraca void.
Counter nie ma clear() — jego resetem okienkowym jest set(0).
Counter::set() to udokumentowany wyjątek, który zwraca poprzednią
wartość (a nie void): jest to atomowa wymiana, a set(0) odczytujący
dotychczasową sumę to idiom sumThenReset z LongAdder. (Atomic zapisuje
tę samą operację jako swap(); Counter zachowuje set, ponieważ set($n)
czyta się naturalnie przy inicjalizacji i pracy okienkowej.)
10. Tożsamość w rejestrze — id(): int
Każda instancja Shared\* udostępnia id(): int na potrzeby logów oraz
endpointu obserwowalności /__ox_shared/entry?id=<id>.
Ściąga
| Koncepcja | Nazwa kanoniczna | Przykłady |
|---|---|---|
| Odczyt wartości | get() |
Map::get, Counter::get |
| Odczyt typu atomowego | load($order) |
Atomic::load |
| Zapis wartości | set() |
Map::set |
| Zapis typu atomowego | store($v, $order) |
Atomic::store |
| Liczba elementów | count(): int |
Map::count, Channel::count, Pool::count |
| Właściwość logiczna | is*(): bool |
Channel::isClosed |
| Wstawienie warunkowe | setIfAbsent($k, $v) |
Map::setIfAbsent |
| Oczekiwanie nieblokujące | try*() |
Channel::trySend, Mutex::tryWithLock |
| Oczekiwanie w nieskończoność | goła nazwa czasownika | Channel::send, Channel::recv, Mutex::withLock |
| Oczekiwanie ograniczone | *Timeout(int $ms) |
Channel::sendTimeout, Mutex::withLockTimeout |
| Compare-and-swap | compareAndSet() |
Atomic::compareAndSet |
| Podmiana, zwrot poprzedniej | swap() |
Atomic::swap, Flag::swap |
| Atomowy RMW, zwrot poprzedniej | fetch*() |
Atomic::fetchAdd |
| Atomowy RMW, zwrot nowej | goła nazwa czasownika | Counter::add |
| Reset do domyślnej | clear() |
Map::clear |
| ID w rejestrze | id(): int |
każdy typ Shared\* |
Dodawanie nowego typu Shared\*
Proponując nowy prymityw, wypełnij tę listę kontrolną przed scaleniem:
- Każda metoda odpowiada wierszowi w ściądze albo ma ADR
wyjaśniający wyjątek (zobacz
Atomic::load/storeorazCounter::setpowyżej). - Jeśli typ przechowuje kolekcję wartości, implementuje
\Countablei udostępniacount(): int. - Metody odczytu to
getlubload(tylko dla typów atomowych). - Gettery logiczne używają prefiksu
is*. - Warianty polityki oczekiwania są zgodne z trychotomią
try*/ goła nazwa /*Timeout(int $ms). Wariant*Timeoutprzyjmujeint $ms > 0i odrzuca wartości zerowe / ujemne / niecałkowite zTypeException. Metody polityki oczekiwaniatry*zwracają albo wynik typu wartościowego (Result), albo rzucają wyjątek domenowy — nigdy nie kodują tego przeznull. Operacje warunkowego powodzenia stosują dedykowane nazewnictwosetIfAbsentzamiasttry*. - Żadnych
len,size,pending,testani innych doraźnych nazw. - Czasowniki specyficzne dla domeny (
evict,drain,flushitp.) pojawiają się tylko wtedy, gdy żaden kanoniczny wpis w ściądze nie obejmuje danej koncepcji.
Nazwy obserwowalności pozostają w tyle za API PHP
Powierzchnia skierowana do operatorów — nazwy metryk Prometheusa oraz JSON pod
/__ox_shared/entry?id=<id> — to kontrakt odrębny od API PHP. Zmiana tych nazw
psuje pulpity i reguły alertów. Aby uniknąć cichej niespójności, objęte tym
nazwy są emitowane dwukrotnie przez jeden cykl wydawniczy:
| Powierzchnia | Przestarzała (nadal emitowana) | Kanoniczna |
|---|---|---|
| Prometheus | oxphp_shared_channel_pending |
oxphp_shared_channel_count |
| Prometheus | oxphp_shared_pool_size |
oxphp_shared_pool_count |
| Wpis JSON | Channel.pending |
Channel.count |
| Wpis JSON | Pool.size |
Pool.count |
Wiersze # HELP przestarzałych metryk noszą prefiks (deprecated, removed in a future release; use *_count), a wtyczka ox_shared emituje przy starcie
WARN, gdy tylko włączona jest introspekcja lub metryki.
Przenieś pulpity i reguły alertów na nazwy z _count, zanim zakończy się
cykl wycofywania. Po usunięciu emitowane będą wyłącznie nazwy kanoniczne,
a panele Prometheusa/Grafany odwołujące się do starych zaczną zwracać puste
serie.
Stabilność
Reguły te są częścią kontraktu OxPHP\Shared\* 1.0. Po wydaniu 1.0 zmiany
nazw stają się zmianami łamiącymi kompatybilność i wymagają cyklu wycofywania.
Przed 1.0 reguły również obowiązują — nowe metody, które je naruszają, zostaną
odrzucone podczas przeglądu.