2010/07/04

Holding on...

Time after time, feels like I'm fading away
Stopped on a dime, staring into space
And clarity comes, and clarity goes
But for all these epiphanies, I'm still lost
Holding the roses...

Mary Beth Maziarz - Hold on

2010/06/20

Nothing is more fatal...

Nothing is more fatal to the progress of the human mind than to presume that our views of science are ultimate, that our triumphs are complete, that there are no mysteries in nature, and that there are no new worlds to conquer.

Sir Humphry Davy

2010/05/22

Windows Mobile 6.5 vs Internet i MMS

Jak to zwykle bywa, po wymianie oprogramowania w aparacie tekefonicznym z którego korzystam straciłem możliwość wysyłania MMS'ów. Okazało się, że przywrócenie tej funkcjonalności nie należy do rzeczy prostych. Zwłaszcza, gdy okazało się, że owe oprogramowanie nie ma Playa na liście operatorów i co więcej system komórki nie akceptuje smsów z konfiguracją. Musiałem, więc wszystkich zmian dokonać ręcznie. Nie było to wcale takie proste, gdyż wymagało zmian nie w jednym a w dwóch miejscach, które co prawda wydają się dość intuicyjne, ale są pomimo tego mało wygodne. Niestety windows na PC przyswyczaił mnie do istnienia różnych kreatorów a tu najzwyczajniej w świecie kreator nie bangla. Ale do rzeczy.

Konfigurujemy połączenie "Play Internet" ( Start/ Settings/ Connections/ Connections)
APN:
internet

Ustawiamy je jako podstawowe w dziale Advanced / Selected Networks

W przypadku MMS musimy jak już wcześniej konfiguracji dokonać w dwóch miejscach

Konfigurujemy połączenie "Play MMS" ( Start/ Settings/ Connections/ Connections )
APN:
mms

W programie do wysyłania SMS/MMS (MMS Options)
Gateway:
10.10.25.5
Port: 8080
Server address: http://10.10.28.164/mms/wapenc
Connect via: "Play MMS"

i Voila. Działa :]

Rafał Prasał.

2010/05/14

SharpNapiProjekt

Całkiem niedawno, to znaczy w dniu dzisiejszym ukończyłem aplikację do pobierania napisów z NapiProjekt.pl. Napisana ona została z użyciem platformy .NET 4.0 w języku C# i w przeciwieństwie do pierwowzoru nie otwiera wielu okien przy pobieraniu napisów do więcej niż jednego filmu. Jedno okno w zupełności jej wystarcza. Jeśli chodzi o funkcjonalność to jest ona na podstawowym poziomie, ale w zupełności powinna wystarczyć przy normalnym użytkowaniu tzn. pobieraniu napisów :). Odpowiednie odnośniki do pobrania znajdują się niżej.



Jak Zainstalować

  1. Rozpakuj SharpNapiProjekt.zip np. do c:\Program files\
  2. Uruchom jako Administrator c:\Program files\SharpNapiProjekt\SharpNapiProjekt.exe (Prawym na programie i 'Uruchom jako Administrator')
  3. Kliknij "Install ShellMenu"

Jak Odinstalować
  1. Uruchom jako Administrator c:\Program files\SharpNapiProjekt\SharpNapiProjekt.exe
  2. Kliknij na "Remove ShellMenu"
  3. Skasuj c:\Program files\SharpNapiProjekt

Jak Używać
  1. Po zainstalowaniu ShellMenu
  2. Klikasz prawym przyciskiem myszy na pliku lub plikach z filmami
  3. Klikasz lewym przyciskiem myszy na "Get Subtitles"

Aplikacja zostaje udostępnione tak jak jest. Autor nie ponosi żadnej odpowiedzialności za straty wynikłe z używania tej aplikacji.

Pobieranie

Rafał Prasał

2010/05/05

Taniość życia...

Mówi się, że życie w Ankh-Morpork jest tanie. To oczywiście poważna pomyłka. Życie bywa czasem bardzo kosztowne; to śmierć można dostać za darmo.

T. Pratchett - Piramidy

2010/04/27

Złe sny...

Wszyscy je mamy. Wybudzają nas w nocy i później nie pozwalają zasnąć. Pamiętamy z nich jedynie niewielki fragment, ale to w zupełności wystarcza, aby później rozbić nam dzień, a czasem nawet i kilka... Wspomnienia, przyszłość, teraźniejszość, pragnienia, pokazują jacy to jesteśmy słabi i bezsilni wobec samych siebie. Zawsze, gdy mi się coś takiego przytrafia jestem rozbity, zdemotywowany i co więcej smutny.

Po prostu zaczynam się wtedy zastanawiać, wracać pamięcią próbując jednocześnie formułować wnioski, które za każdym razem są nieco inne. Sięgając pamięcią tak niedaleko w przeszłość przecież zastanawiam się, co przyniesie przyszłość, która dla mnie powinna być rysowana w różowych kolorach. Dlaczego jednak, taka się nie rysuje? może dlatego, że po tym, co mi się przytrafiło niestety sam nie jestem już niczego pewien... Z jednej strony chciałby znów zacząć "żyć", ale z drugiej to na co mi to wszystko, skoro i tak nie ma i nie będzie w moim życiu nikogo, no może poza moimi rodzicami, kto powie, że zmierzam w dobrym albo złym kierunku.

Niby niegłupi, niby niedługo spełni się moje marzenie z czasów jeszcze podstawówki, ale jakoś to nie wywołuje uśmiechu na mojej twarzy. Co więcej powoduje chwile słabości, których nic nie jest w stanie przebić. W trakcie ich trwania zawsze jestem "nieobecny", zamknięty ze swoimi myślami, które po prostu płyną...

Oby, w końcu kiedyś dotarły do jakiegoś brzegu...

Rafał Prasał

2010/03/20

Zylion procent normy

Każdy z nas, ludzi zajmujących się między innymi pisaniem zapytań SQL trafia na przypadki, które w jakiś sposób są wyzwaniem. Dla jednych mogą to być miliony rekordów w płaskiej tabeli, dla innych, no cóż tabela przestaje być płaska a jej pola zaczynają być indeksami do innych tabel.

W mojej praktyce zawodowej, miałem do czynienia z różnymi przypadkami, które w mniejszym, lub większym stopniu miały znaczący wpływ na obniżanie wydajności serwisów, których dotyczyły. Błędy lub niedopatrzenia jakie popełniono, mogły zdarzyć się każdemu i pewnie przy tworzeniu rozwiązań na "szybko" przytrafiają się częściej niż możemy sobie to wyobrazić.

Łączenie się w trakcie generowania strony do zewnętrznych serwisów

Początkowo wszystko wydaje się fajne, bo działa, jednakże w przypadku styku z użytkownikami
a. niepotrzebnie zapychamy sobie łącze
b. w przypadku padu połączenia z zewnętrznym serwisem, co może zdarzyć się np. jak domena przestanie istnieć, nasz serwis klasycznie dostanie DDOS.

Jak się tego ustrzec? Rozwiązanie wydaje się prostsze niż mogłoby się wydawać. Otóż można np przy pomocy CRONa zrzucać interesującą nas informację zewnętrznego serwisu do plików tymczasowych na naszym serwerze i to właśnie wykorzystywać w naszych skryptach

Karkołomne zapytania wykonywane przy każdym kliknięciu
Przypuśćmy, że chcemy w naszym serwisie pokazać dziesięć losowych spośród stu najnowsze wiadomości, które z kolei mogą znajdować się na forach, obrazkach, blogach lub w samym naszym serwisie. Przypuśćmy też, że treści generowanych przez użytkowników jest sporo powiedzmy 1000-100000 elementów dziennie a ilość wejść przez użytkowniów na nasz serwis to milion miesięcznie. Żeby stworzyć interesujący nas widok musimy wykonać, kilka zapytań, albo jedno i użyć konstrukcji union, gdyż dane będą pochodziły z kilku tabel. Genralnie jak się to wszystko policzy to masakra. W każdym razie dobrą praktyką jest użycie cache'y, ale teraz jak się z tematem zmierzyć? prawdę mówiąc istnieją 2 rozwiązania

1. Dane w czasie rzeczywistym
Dla każdej interesującej nas tabeli tworzymy trigger "after insert", który będzie ją umieszczał w tabeli cache_100 oraz dbał o to, żeby ilość elementów nie przekraczała 100. Praktyka pokazuje, że przy takiej ilości danych indeksy w tabeli cache_100 są zbędne i obniżałyby wydajność. Jednakże nawet w przedstawionym przeze mnie przypadek, może się nie sprawdzić, to znaczy wtedy, gdy ilość generowanych treści przez użytkowników będzie o rząd albo o dwa rzędy większa.

2. Dane opóźnione o jakiś czas
Innym podejściem do tematu jest wykonanie owego karkołomnego zapytania raz na jakiś czas np 5min-10min(CRON)i umieszczenie wyników w tabeli cache_100. Użytkownikowi i tak jakoś specjalnie to nie będzie przeszkadzało a my zyskamy na tym, że nawet znacznie zwiększony ruch nie zabije nam usługi.

Miliony rekordów w tabeli o wielu dowiązaniach
W sumie jest to najciekawszy przypadek jaki do tej pory miałem. Baza danych była dość skomplikowana, dowiązania wielokrotne w liczbie 15. Ogólnie sam widok schematu przyprawiał o zawrót głowy. Nie mówię, że to coś złego, po prostu takie było odzwierciedlenie nieabstrakcyjnych urządzeń znajdujących się w terenie. Jeśli doliczyć do tego ponad milion a nawet do dwóch milionów rekordów rocznie i wyniki generowane w czasie rzeczywistym filtrowane po subdevice_id i czasie to już w ogóle dech w piersiach zapiera a na usta cisną się niecenzuralne słowa. Pominę już fakt, że jeśli urządzenie zwariuje to może wysłać 10k rekordów w przeciągu jednej godziny a czasami nawet i więcej. Zapytanie takie jak poniżej, nie wchodziło w grę, choćby ze względu na to, że mogłoby się wykonywać nawet do 5-24h, bo inicjalne ustawienie pól cache'ujących trwało bagatela 1.5h.
Select * from msgs left join ... where .... order by ... limit ...;
Użyłem triggerów, które zadbały o to, żeby baza sama "pilnowała" wariantów i przynajmniej częściowo cache'owała wyniki podzapytań z dowiązań.
msgs.subdevice_id = (select device_id from devices where devices.supdevice_id = msgs.device_id and devices.subdevice = msgs.subdevice))
Czas wykonywania skrócił się do 30-60 sekund. Gdyby ten wynik zadowalał mnie i klienta to pewnie bym i na tym poprzestał, ale dla nas obojga było to niewystarczające.

Na odsiecz przybyło podzapytanie użyte w polu FROM. To zapytanie nie było specjalnie trudne ot, po prostu służyło do zawężania wyników po subdevice_id i dacie. Czyli w efekcie końcowym powstał taki twór
$x= "Select * from msgs where subdevice_id in ( $subdevices ) and rtime > $start and rtime < $koniec order by rtime desc limit 101;";
a to z kolei zostało umieszczone w polu FROM, Czyli
$sql = "Select * from ( $x ) left join ..."
Dla niektórych to, co zostało zrobione tutaj to kombinacja norweska z alpejską w jednej, ale tak naprawdę jest to bardzo proste do zrozumienia. Otóż w powyższym rozwiązaniu został wykorzystany fakt, iż zapytania na zindeksowanej "płaskiej" tabeli wykonują się o niebo szybciej niż zapytania, w których występują złączenia z innymi tabelami. Jest tak między innymi dlatego, że najpierw tworzone są wiersze wynikowe czyli między innymi rozwiązywanie dowiązań a dopiero potem następuje ich zawężanie. Zatem "Superszybkie" zapytanie zawężające liczbę wyników do 101 znacznie zmniejszyło ilość rozwiązywanych dowiązań z innymi tabelami, przez co baza danych w końcu zaczęła oddychać.

Możecie wierzyć lub nie, ale to rozwiązanie skróciło czas wykonywania zapytania do 100-300ms czyli w porównaniu z 5-24h wychodzi od 6M do 28.8M%, co wydaje się być wynikiem, co najmniej zadowalającym :].

Rafał Prasał.