Cytując dokumentację (link poniżej): POE, czyli Perl Object Environment to opensourcowe narzędzie-środowisko do szybkiego tworzenia wielozadaniowych aplikacji sieciowych. Autorzy wymieniają szereg cech, które mają zachęcić do tworzenia rozwiązań w tym frameworku - m.in. szerokie wsparcie dla komunikacji sieciowej, wygodny silnik obsługi zdarzeń, mechanizm kolejkowania komunikatów czy możliwości programowania rozproszonego. POE ma być także remedium na odwieczne problemy związane z wielowątkowością i wieloprocesowością.
Wszystko wygląda niezwykle obiecująco, szczerze mówiąc - trochę zbyt obiecująco. Za wyżej wymienionym wachlarzem funkcjonalności nie podąża jednak popularność POE. Swego czasu na grupie pl.comp.lang.perl (link poniżej) odbyła się krótka dyskusja na temat tego środowiska. Ludzie podkreślali, że POE jest zbyt skomplikowane i te same algorytmy można implementować w dużo prostszy sposób. O ile poziom skomplikowania nie jest argumentem najistotniejszym przy wyborze technologii - liczą się przecież możliwości, o tyle istnienie prostszego alternatywnego sposobu na osiąganie tych samych funkcjonalności może już stanowić czynnik dyskwalifikujący.
POE zacząłem się przyglądać przy okazji poszukiwań technologii, w której mogą być wykonane różne aplikacje przetwarzające duże ilości danych. W grę wchodzi więc zarówno wielowątkowość, jak i usługowy charakter tych aplikacji, które z resztą powinny być w stanie wymieniać między sobą kilka podstawowych komunikatów. Koncepcja nadal się nie wyklarowała - równie dobrze może się wkrótce okazać, że ostateczne rozwiązanie przyjmie kształt farmy wielowątkowych aplikacji (usług), które będą musiały pracować w sposób skoordynowany. Zgodnie z tym, co napisane w dokumentacji - POE powinno dać sobie z tym wszystkim radę.
Jakkolwiek wygoda tworzenia tego typu rozwiązań w POE mogłaby być dla dewelopera całkiem duża, o tyle nie można zapominać o wydajności końcowego produktu, który przecież zorientowany jest na masowe i logicznie skomplikowane operacje na danych. Głównym priorytetem jest więc szybkość przetwarzania. I właśnie w tym obszarze pojawia się największy problem z POE. Chodzi o to, że Perl Object Environment w obecnym kształcie nie wykorzystuje prawdziwych wątków (nie jest thread-safe, mowa oczywiście o wątkach perlowskich - interpreter threads), tylko je w swoisty sposób symuluje. Ma to swoje plusy - nie ma konieczności kopiowania do pamięci interpretera dla każdego nowego wątku, gdyż jest on współdzielony, ale...
...z drugiej strony aplikacje POE, będąc jednowątkowymi, nie są w stanie korzystać z dobrodziejstw systemów wieloprocesorowych i wielordzeniowych, co dla rozwiązania z gatunku data processing jest sporą ujmą. W moim przypadku będzie to chyba argument decydujący. Jeżeli do tworzenia aplikacji wybrany zostanie Perl jako technologia podstawowa (ze względu na natywne wsparcie dla wyrażeń regularnych), to na pewno POE jako framework nie będzie wykorzystany. POE może się jednak świetnie nadawać do innych celów, pewnie jednak się o tym nigdy nie przekonam :)
Więcej informacji:
http://poe.perl.org - Perl Object Environment home
POE: The Perl Object Environment Whitepaper (pdf)
pl.comp.lang.perl: POE (Google Groups)
Wczoraj wpadła mi w ręce ciekawa zagadka logiczna zaimplementowana we flashu, podobno jej rozwiązanie bywa nieodzownym elementem rozmów kwalifikacyjnych w Japonii. Aby przejść do gry, wystarczy kliknąć poniższy obrazek, a następnie wybrać niebieski okrągły przycisk. Warto zapoznać się z zasadami gry wymienionymi poniżej, chyba że zna się język japoński.

Zasady:
1. Tratwa zabiera najwyżej 2 osoby.
2. Matka nie może przebywać z synami bez ojca na brzegu oraz nie może z nimi podróżować.
3. Ojciec nie może przebywać z córkami bez matki na brzegu oraz nie może z nimi podróżować.
4. Złodziej nie może przebywać z członkami rodziny bez policjanta.
5. Tylko ojciec, matka i policjant potrafią sterować tratwą.
Celem gry jest przewiezienie wszystkich osób na drugą stronę rzeki.
Wszyscy zainteresowani szybszym rozruchem SQL Server Management Studio powinni wywoływać wymienioną aplikację z dodatkowymi parametrami, czyli:
SqlWb.exe -nosplash -S
Spowoduje to, że Management Studio m.in. nie wyświetli splasha powitalnego, tylko od razu umożliwi rozpoczęcie pracy. Warto więc zmodyfikować skrót prowadzący do tej aplikacji w taki sposób, aby uwzględniał powyższe parametry wywołania. Wartość elementu docelowego skrótu przy standardowym miejscu zainstalowania SQL Server wgląda wtedy następująco:
"C:\Program Files\Microsoft SQL Server\90\Tools\Binn\VSShell\Common7\IDE\SqlWb.exe" -nosplash -S
Wiele gorzkich słów zostało już wypowiedzianych na temat nawigacji między oknami kwerend w SQL Server Management Studio, nie chcę więc wypisywać tutaj kolejnych. Powiem tylko, że nowa funkcjonalność zaimplementowana pod skrótem klawiszy CTRL+TAB nie zdała egzaminu - i to do tego stopnia, że nie którzy porzucili Management Studio na rzecz starego poczciwego Query Analyzera.
W MS istnieje jednak skrót klawiszowy, którego zachowanie dokładnie odpowiada działaniu CTRL+TAB (CTRL+SHITF+TAB) z Query Analyzera, czyli przechodzeniu do następnego okna za każdym razem po jednokrotnym użyciu. Jest to mało popularny skrót CTRL+F6 ( CTRL+SHIFT+F6 - w odwrotną stronę). Co prawda taką kombinację ciężko wybrać jedną ręką nawet na klawiaturze laptopa, ale lepiej użyć dwóch rąk niż być pozbawionym możliwości rozsądnego sposobu nawigacji między oknami.
Zespół deweloperski MSSQLa planuje zmiany w funkcjonalności window navigation w Management Studio, może więc sytuacja ulegnie poprawie.
Więcej informacji:
MSDN: SQL Server Management Studio Keyboard Shortcuts
W jednym z poprzednich postów pisałem o sytuacji, w której serwis hacking.pl wywołał mniejsze czy większe poruszenie związane z niskim poziomem zabezpieczeń znanego systemu aukcyjnego Allegro.pl. Później, o czym już z braku czasu nie pisałem, podobny scenariusz był realizowany w odniesieniu do mBanku, acz ze względu na specyfikę problemu odbyło się to w mniej widowiskowy sposób. Jak podaje serwis IDG.pl w swojej wiadomości, wczoraj w późnych godzinach wieczornych - o ironio - to hacking.pl stał się ofiarą wrogiego wykorzystania luk w bezpieczeństwie. IDG.pl określiło zdarzenie jako kompromitację. Może i jest to uzasadnione w świetle ostatnich publikacji dotyczących Allegro.pl i mBanku, jednak podobne przejęcie tej strony ma miejsce średnio co kilka miesięcy, więc nie używałbym tutaj zbyt mocnych słów :) W momencie, w którym powstał ten wpis, serwis hacking.pl nadal nie funkcjonuje (wyświetlane jest jedynie logo). Do niedawna na stronie widniało:
own3d by kotecek
THERE IS A NEW ROOT IN TOWN AND WHAT WAS ALL THAT CHROOTING FOR?
Plik shadow
http ://platyna.platinum.linux.pl/gorion/
http ://memoires.viedzma.pl/2006/12/
Gr33tZ to:
#chcialbym_byc_jak_gorion
#linux-slackware2
Baseciq
viedzma
Cała sprawa ma jednak drugie dno, które chciałbym skomentować.
Każdy, kto choć trochę obserwuje środowisko security related w Polsce, bez wątpienia dojdzie do wniosku, że przejęcie hacking.pl to reakcja na "popis" Pawła "Goriona" Jabłońskiego w telewizji TVN z topornego gatunku "hakowanie na ekranie". Kto ma inne zdanie, niech poczyta informacje zawarte w linkach z powyższego listingu. Nie chcę tutaj oceniać występu telewizyjnego, gdyż go nie widziałem. Nie chcę też oceniać reakcji społeczności, choć po przeczytaniu pewnych informacji (o ile oczywiście są prawdziwe) - znajduję dla niej pewne zrozumienie :) W każdym razie to, co teraz można obserwować, to klasycznie piękna eskalacja konfliktu jednego człowieka i pewnej grupy ludzi. Obydwie strony będą w tym momencie umacniać swoje pozycje, gdyż atrakcyjna jest zarówno rola buntownika i samotnego wojownika, jak i działające integrująco posiadanie wspólnego wroga czy napiętnowanie "czarnej owcy". Wśród osób z większym dystansem do całej sprawy nie brakuje komentarzy, że obie strony zachowują się po prostu dziecinnie... Pewnie coś w tym jest, choć trudno oceniać emocje, które każdy przeżywa w sobie tylko znany sposób. I to właśnie obserwacja zachowań ludzi podyktowana tymi emocjami wydaje mi się w tej całej sprawie najciekawsza - gdyby nie to, opisywane zdarzenia nie zasługiwałyby na większą uwagę.
SQL Server 2005 posiada funkcjonalnie wydzielony obszar, w którym przechowywane są informacje dotyczące samej instancji i jej wszystkich baz. Obszarem tym jest katalog systemowy (system catalog). Informacje przechowywane w katalogu systemowym udostępniane są użytkownikowi na kilka sposobów. W najnowszej wersji SQL Server służą do tego przede wszystkim widoki DMV (Dynamic Management Views) i funkcje DMF (Dynamic Management Functions), które dostarczają informacji na temat różnego typu obiektów w poszczególnych bazach danych, a także szereg innych informacji m.in. statystycznych. Katalog systemowy występuje oczywiście również w poprzednich wersjach SQL Server, różnice co do jego struktury w porównaniu z aktualną wersją są jednak dość duże.
Informacje zawarte w katalogu systemowym nie powinny być modyfikowane przez użytkownika przy użyciu operacji DML (UPDATE, INSERT, DELETE). To kategoryczne stwierdzenie wielokrotnie artykułowane przez Microsoft ma istotnie głębokie uzasadnienie. Miałem już jednak nieprzyjemność uczestniczyć w różnych awaryjnych sytuacjach, w których pozytywne rozwiązanie problemu nie byłoby możliwe bez drastycznych działań na tabelach (widokach) systemowych. W bardzo ograniczonym zakresie działania tego typu są więc dopuszczalne. Wychodzę z założenia, że gdyby twórcy MSSQL rzeczywiście chcieli zabronić takich operacji, nie byłyby one technicznie możliwe. Tymczasem możliwe są - i to zarówno w wersji SQL Server 2000, jak i SQL Server 2005.
Co więc należy zrobić, aby wykonać przykładowo UPDATE na jakiejś tabeli systemowej (widoku)?
Wersja SQL Server 2000
Wystarczy uaktywnić odpowiednią opcję konfiguracyjną:
EXEC sp_configure 'allow updates', 1
RECONFIGURE WITH OVERRIDE
i już mamy możliwość wykonywania operacji DML na katalogu systemowym. Należy pamiętać, że po rozwiązaniu problemu trzeba przywrócić opcję allow updates do stanu disabled. Osiągniemy to wykonując powyższy kod z wartością 0 zamiast 1.
Wersja SQL Server 2005
W przypadku wersji SQL Server 2005 sytuacja jest znacznie bardziej skomplikowana. Po pierwsze należy wystartować instancję w trybie pojedynczego użytkownika (single-user mode). Musimy więc zatrzymać daną instancję (jeżeli w danym momencie działa), a następnie uruchomić ją przy pomocy następującego polecenia wydanego z linii komend (cmd):
cd c:\Program Files\Microsoft SQL Server 2005\MSSQL.1\MSSQL\Binn\
sqlservr.exe -m
przy czym dokładna ścieżka zależy oczywiście od miejsca zainstalowania MSSQLa. W przypadku nazwanej instancji polecenie wygląda tak:
sqlservr.exe -m -s nazwa_instancji
Okno linii poleceń należy zostawić otwarte, a po zakończeniu działań należy wyjść z procesu w nim uruchomionego (kombinacja klawiszy CTRL-C), co będzie równoznaczne z zatrzymaniem usługi SQL Server.
Aby mieć możliwość dokonywania zmian w katalogu systemowym, należy zalogować się poprzez DAC do instancji odpalonej w trybie single-user zgodnie z powyższymi wytycznymi. DAC (Dedicated Administrator Connection) to specjalne połączenie diagnostyczno-administracyjne, które może być wykonane z sqlcmd lub Management Studio zasadniczo jako połączenie lokalne (klient powinien być uruchomiony bezpośrednio na serwerze, choć zdalny DAC jest również możliwy). Połączenie przez DAC osiągamy przez dodanie do nazwy serwera prefixu "ADMIN:". Aby połączyć się do instancji druga na serwerze sql2005 należy jako Server name (Management Studio) podać:
ADMIN:sql2005\druga
Oczywiście w przypadku instancji domyślnej po frazie "ADMIN:" podajemy wyłącznie nazwę serwera. Trzeba też pamiętać, że do połączenia przez DAC do nazwanej instancji przez podanie jej nazwy wymagane jest działanie usługi SQL Server Browser.
Po zalogowaniu się przez DAC do określonej instancji należy w kontekście dowolnej bazy dokonać rekonfiguracji opcji allow updates:
EXEC sp_configure 'allow updates', 1;
RECONFIGURE WITH OVERRIDE;
(odbywa się to w analogiczny sposób jak w SQL Server 2000).
Po wykonaniu powyższych czynności możemy dokonywać operacji DML w katalogu systemowym. Jeszcze raz podkreślam, że należy przy tym zachować szczególną ostrożność, a w sytuacji działania na serwerze produkcyjnym (sic!), niech ktoś patrzy nam na ręce.
Więcej informacji:
MSDN: How to: Start an Instance of SQL Server
SQL Server 2005 Books Online (BOL): Using a Dedicated Administrator Connection
Różne środowiska uruchomieniowe, w tym także CLR platformy .NET, wykorzystują mechanizm automatycznego zarządzania pamięcią, określany powszechnie jako "odśmiecanie pamięci" (garbage collection). Podstawowym celem zastosowania garbage collection była chęć uwolnienia dewelopera od obowiązku ciągłego myślenia w kategorii skończoności zasobów o przydziale i zwalnianiu dostępnej pamięci. Wpisuje się to oczywiście w ogólną koncepcję tworzenia oprogramowania wg podejścia RAD (Rapid Application Development). Zgodnie z założeniami, w środowisku .NET alokacją i zwalnianiem pamięci zajmuje się specjalny mechanizm - tzw. garbage collector (GC), a programista powinien skupić się na funkcjonalności aplikacji. Nie oznacza to jednak, że możemy zupełnie zapomnieć o kwestiach dotyczących pamięci. GC funkcjonuje w oparciu o zestaw reguł, na podstawie których podejmuje określone działania. Naturalnie reguły te nie są równie efektywne w każdej z możliwych sytuacji, dlatego właśnie świadomy deweloper powinien nauczyć się tak pisać swój kod, żeby w pośredni sposób wpływać na przewidywalne zachowania garbage collectora.
Chciałbym zwrócić uwagę na kilka kwestii związanych z automatycznym zarządzaniem pamięcią na platformie .NET. Tematyka jest bardzo szeroka i wieloaspektowa, dlatego poniższe informacje mogą stanowić jedynie wstęp do bardziej dogłębnej analizy tematu.
Pamięć w sensie funkcjonalnym podzielić możemy na stos (stack) i stertę zarządzaną (managed heap). Typy bezpośrednie (value types, czyli np. zmienne w metodzie) alokowane są na stosie. GC nie ma z nimi za wiele pracy - po opuszczeniu metody pamięć jest w prosty i natychmiastowy sposób zwalniana. Wszystko komplikuje się w przypadku typów referencyjnych, które alokowane są na stercie. Każde utworzenie nowego obiektu powoduje zarezerwowanie określonego obszaru pamięci na stercie (przesuwany jest także wskaźnik alokacji NextObjPtr, wskazujący następny dostępny adres). O ile moment tworzenia obiektu jest jednoznaczny i trywialny do określenia, o tyle identyfikacja obiektów już niepotrzebnych to działanie o wiele bardziej złożone. Zadanie to GC realizuje poprzez cykliczne sprawdzanie, które obiekty nie są osiągalne z żadnego zasięgu w programie. Odbywa się to na zasadzie wstępnej negacji - początkowo wszystkie obiekty uznawane są za martwe, następnie GC z listy śmierci usuwane te, które w danym momencie mogą być osiągnięte przez kod aplikacji. Pozostałe obiekty przeznaczone są do unicestwienia. Podczas okresowej aktualizacji sterty GC zwalnia bloki pamięci odnoszące się do martwych obiektów. Dodatkowo scala pozostałe bloki tak, by nie pozostawały między nimi żadne wolne przestrzenie. Wiąże się to oczywiście z koniecznością aktualizacji wskaźnika alokacji i koniecznością przeadresowania wszystkich referencji do obiektów, gdyż po migracji bloków zmianie ulegają adresy pamięci. Operacje wykonywane przez GC są dla wnętrzności naszego programu dość rewolucyjne i kosztowne pod względem wydajności. Podczas działania GC może wystąpić chwilowa niepoprawność referencji, pamięć musi więc pozostawać niedostępna dla aplikacji, co jest realizowane przez wstrzymanie wszystkich jej wątków. Ze względu na opisaną charakterystykę pracy i kosztowność operacji, GC uruchamiany jest zasadniczo dopiero w sytuacji braku pamięci na stercie.
Algorytm garbage collection działa w rzeczywistości w nieco bardziej skomplikowany sposób, uwzględniając m.in. tzw. generacje. Możliwe jest także wymuszone uruchomienie GC z kodu aplikacji ( System.GC.Collect()). Wymienione kwestie, jak też inne szczegóły wykraczają jednak poza zakres tego powierzchownego artykułu - zainteresowanych zapraszam do zapoznania się z linkami zebranymi poniżej.
Trzeba pamiętać, że GC zajmuje się zwalnianiem pamięci zajmowanej przez martwe obiekty, a nie zwalnianiem wszystkich zasobów przez te obiekty wykorzystywanych. Sami więc musimy zadbać o zwolnienia zasobów niezarządzanych (plikowych, sieciowych, sprzętowych), np. otwartego połączenia do bazy danych. Nie chodzi tutaj wyłącznie o tzw. finalizację (zaimplementowanie finalizatora klasy), która w wielu sytuacjach może okazać się mało efektywna. Lepszym wyjściem będzie oprogramowanie metod Close() i Dispose(), czy stosowanie bloku using.
Ciekawe możliwości oferują tzw. słabe referencje (weak references). Nie jest to pomysł ani nowy, ani specyficzny wyłącznie dla platformy .NET. Słabe referencje spotykamy również w innych technologiach z mechanizmem typu garbage collection (jak Java czy Perl).
Dla jednoznaczności warto uściślić, że silna referencja do obiektu (strong reference) występuje w sytuacji, kiedy obiekt może być osiągnięty z kodu aplikacji. W sytuacji silnej (zwykłej) referencji obiekt jest więc poza zainteresowanie GC. Słaba referencja natomiast to swoisty kompromis - obiekt jest co prawda dostępny dla aplikacji (która może uzyskać do niego silną referencję), ale w każdym momencie GC może go unicestwić.
Pozornie może się wydawać, że nie ma to wielkiego sensu. Są jednak sytuacje, w których opisany kompromis jest całkiem akceptowalny. Słabe referencje świetnie nadają się do obiektów, które zajmują duży obszar pamięci, ale mogą być łatwo odtworzone. Wprowadza to swoistą elastyczność obsługi do naszej aplikacji. Kiedy zabraknie pamięci, obiekt ze słabą referencją zostanie unicestwiony przez GC i na stercie przybędzie potrzebnej w danym momencie wolnej przestrzeni. Jeżeli obiekt będzie potrzebny ponownie, zostanie w prosty sposób zrekonstruowany. W sytuacji dostatecznej ilości wolnej przestrzeni na stercie, obiekt nie zostanie zniszczony, aplikacja będzie więc go mogła użyć natychmiast po wykorzystaniu słabej referencji.
Słabych referencji nie należy stosować przy małych obiektach jak też nie są one remedium na wszystkie problemy wydajnościowe aplikacji - w każdym razie na pewno nie zastąpią rozsądnego i przemyślanego cacheowania.
Więcej informacji:
MSDN: Garbage Collection: Automatic Memory Management in the Microsoft .NET Framework
MSDN: Garbage Collection—Part 2: Automatic Memory Management in the Microsoft .NET Framework
MSDN: Using Weak References
|