Indeksowanie i wyszukiwanie plików pod Linuksem

Na jednym serwerów, którym zarządzałem przechowywane były kopie zapasowe plików. Zajmowały ok. 1,5 TB (ponad 4 mln plików) miejsca na dyskach. Przeszukiwanie tak dużego zbioru plików przy pomocy polecenia „find” jest dość uciążliwe, wolne oraz nie każdy użytkownik posiada taką możliwość. Nie znalazłem aplikacji do indeksowania oraz wyszukiwania plików pod Linuksa, która spełniałaby nasze wymagania, więc postanowiłem wykonać własny mechanizm.

Na początek określimy wymagania wyszukiwarki. Aplikacja powinna:

  • indeksować pliki w czasie rzeczywistym, czyli wykrywać i reagować na dodawanie, usuwanie oraz modyfikacje plików,
  • umożliwiać wyszukiwanie plików według nazwy i ścieżki oraz inny atrybutów np. daty ostatniej modyfikacji, rozmiar itd.,
  • generować podpowiedzi dla wpisywanych fraz oraz wyszukiwać na podstawie niepełnych fraz,
  • sortować wyniki według trafności,
  • posiadać interfejs dostępny przez WWW,
  • posiadać możliwość nadawania uprawnień do przeszukiwania określonych lokalizacji.

Początkowy plan zakładał wykorzystanie narzędzia „inotify” do monitorowania plików. Skrypt wykrywający zmiany na dysku (Python) indeksowałby pliki i zapisywał dane do bazy (MySQL). Mając dane w bazie można uruchomiać wyszukiwanie pełnotekstowe (Sphinx) i udostępniać wyniki przez WWW (PHP).

Potrzebne narzędzia instalujemy przy pomocy apt:

apt-get install inotify-tools python-pyinotify

Najprostszy skrypt do monitorowania plików może wyglądać tak:

#!/usr/bin/python

import os
import pyinotify
import MySQLdb

from pyinotify import WatchManager, Notifier, ThreadedNotifier, EventsCodes, ProcessEvent

wm = WatchManager()
mask = pyinotify.IN_ACCESS | pyinotify.IN_CREATE | pyinotify.IN_DELETE | pyinotify.IN_MODIFY

# Connect to database.
conn = MySQLdb.connect (host = "localhost", user = "myuser", passwd = "mypassword", db = "search")

class PTmp(ProcessEvent):
  def process_IN_CREATE(self, event):
    # Begin transaction.
    conn.begin()
    c = conn.cursor()

    # Try to add file.
    name = os.path.join(event.path, event.name)
    c.execute("INSERT IGNORE INTO files (name) VALUES (%s)", (name))

    # Get file ID.
    c.execute("SELECT id FROM files WHERE name == %s", (file))
    fileId = c.fetchone()[0]

    # Log operation.
    c.execute("INSERT INTO files_history (file_id, time, operation) VALUES(%s, NOW(), %s)", (fileId, "CREATE"))
    conn.commit()

  def process_IN_DELETE(self, event):
    # Begin transaction.
    conn.begin()
    c = conn.cursor()

    # Try to add file.
    name = os.path.join(event.path, event.name)
    c.execute("INSERT IGNORE INTO files (name) VALUES (%s)", (name))

    # Get file ID.
    c.execute("SELECT id FROM files WHERE name == %s", (file))
    fileId = c.fetchone()[0]

    # Log operation.
    c.execute("INSERT INTO files_history (file_id, time, operation) VALUES(%s, NOW(), %s)", (fileId, "DELETE"))
    conn.commit()

  def process_IN_MODIFY(self, event):
    # Begin transaction.
    conn.begin()
    c = conn.cursor()

    # Try to add file.
    name = os.path.join(event.path, event.name)
    c.execute("INSERT IGNORE INTO files (name) VALUES (%s)", (name))

    # Get file ID.
    c.execute("SELECT id FROM files WHERE name == %s", (file))
    fileId = c.fetchone()[0]

    # Log operation.
    c.execute("INSERT INTO files_history (file_id, time, operation) VALUES(%s, NOW(), %s)", (fileId, "MODIFY"))
    conn.commit()

notifier = Notifier(wm, PTmp())
wdd = wm.add_watch('/backup', mask, rec=True)
wdd = wm.add_watch('/home', mask, rec=True)

while True:
  try:
    # process the queue of events as explained above
    notifier.process_events()
    if notifier.check_events():
      # read notified events and enqeue them
      notifier.read_events()
    # you can do some tasks here...
  except KeyboardInterrupt:
    # destroy the inotify's instance on this interrupt (stop monitoring)
    notifier.stop()
    break

Skrypt monitoruje określone katalogi i zapisuje do bazy pliki oraz historię zmian. Niestety, szybko okazało się, że monitorowanie tak dużej liczby plików nie jest możliwe przy pomocy inotify. Próba uruchomienia skryptu kończy się komunikatem o wyczerpanym limicie obserwatorów:

[Pyinotify ERROR] add_watch: cannot watch /some/file.txt (WD=-1)

Limit można podnieść, ale ustawianie limitu na 5 mln nie wydaje się rozsądne, a uruchamianie powyższego skryptu trwa bardzo długo.

Podobny efekt możemy uzyskać przy pomocy narzędzia „inotifywait”:

inotifywait --monitor --recursive --event CREATE --event DELETE --event MODIFY /backup

Jednak uruchomienie polecenia kończy się podobnym komunikatem:

Failed to watch /backup; upper limit on inotify watches reached!
Please increase the amount of inotify watches allowed per user via `/proc/sys/fs/inotify/max_user_watches'.

Jak widać monitorowaniu dużej liczby plików przy pomocy inotify może być kłopotliwe.

Do chwili obecnej nie znalazłem jeszcze wydajnego sposobu na monitorowanie zmian w tak dużej liczbie plików w czasie rzeczywistym.

Statystyki

Indeksowanie przy pomocy python, find itd. zajęło ok. godzinę (1 h 5 min.). Tabela zawiera 4097484 rekordów i zajmuje ok. 1,3 GB.

Indeksowanie Sphinksem zajęło 39 min. 35 s., a łączy rozmiar wszystkich plików zawierających dane wynosi 9,8 GB (podczas indeksowania pliki tymczasowe zajmowały ponad 15 GB).

Linki

http://www.ibm.com/developerworks/linux/library/l-ubuntu-inotify/index.html

http://pyinotify.sourceforge.net

http://people.gnome.org/~veillard/gamin/python.html

Zaszufladkowano do kategorii Linux, MySQL, PHP, Projekty, Python | Możliwość komentowania Indeksowanie i wyszukiwanie plików pod Linuksem została wyłączona

Debian – instalacja Subversion 1.7.4

W ostatniej stabilnej wersji Debiana najnowszą dostępną wersją Subversion jest 1.6.12. Wersja 1.7 przynosi wiele udogodnień, m.in. informacje o kopii roboczej przechowywane są w katalogu „.svn” znajdującym się w głównym katalogu kopii roboczej. Wcześniejsze wersje tworzyły foldery „.svn” w każdym podkatalogu. Zmiana pozwala na uniknięcie wielu problemów związanych z przenoszeniem lub kopiowaniem plików w obrębie kopii roboczej.

Pobieramy, rozpakowujemy ostatnią stabilną wersję Subversion. Obecnie jest to wersja numer 1.7.4. Następnie uruchamiamy konfigurację.

wget http://apache.mirror.aussiehq.net.au/subversion/subversion-1.7.4.tar.gz
tar xvzf subversion-1.7.4.tar.gz
cd subversion-1.7.4
./autogen.sh
./configure

Próba skonfigurowania źródeł prawdopodobnie zakończy się komunikatem o braku biblioteki sqlite.

checking sqlite library version (via pkg-config)... no

An appropriate version of sqlite could not be found.  We recommmend
3.7.6.3, but require at least 3.6.18.
Please either install a newer sqlite on this system

or

get the sqlite 3.7.6.3 amalgamation from:
    http://www.sqlite.org/sqlite-amalgamation-3.7.6.3.tar.gz
unpack the archive using tar/gunzip and copy sqlite3.c from the
resulting directory to:
/root/sources/subversion-1.7.4/sqlite-amalgamation/sqlite3.c

Pobieramy paczkę i kopiujemy plik sqlite.c do katalogu ze źródłami Subversion.

cd ..
wget http://sqlite.org/sqlite-autoconf-3071000.tar.gz
tar xvzf sqlite-autoconf-3071000.tar.gz
mkdir subversion-1.7.4/sqlite-amalgamation
cp sqlite-autoconf-3071000/sqlite3.c subversion-1.7.4/sqlite-amalgamation/sqlite3.c

Wracamy do Subversion.

cd subversion-1.7.4
./configure

Możliwe, że otrzymamy informację o braku systemu plików BDB.

configure: WARNING: we have configured without BDB filesystem support

You don't seem to have Berkeley DB version 4.0.14 or newer
installed and linked to APR-UTIL.  We have created Makefile which will build
Subversion without support for the Berkeley DB back-end.  You can find the
latest version of Berkeley DB here:
  http://www.oracle.com/technology/software/products/berkeley-db/index.html

Ze strony wskazanej w komunikacie pobieramy plik db-5.3.15.tar.gz. Wymagane jest założenie konta oraz rejestracja, więc wspomniany plik udostępniam tutaj.

Po pobraniu, instalujemy Berkeley DB:

tar xvzf db-5.3.15.tar.gz
cd db-5.3.15
./dist/configure
make
make install

następnie apr:

wget http://ftp.tpnet.pl/vol/d1/apache/apr/apr-1.4.6.tar.gz
tar xvzf apr-1.4.6.tar.gz
cd apr-1.4.6
./configure
make
make install

oraz apr-util:

wget http://ftp.tpnet.pl/vol/d1/apache/apr/apr-util-1.4.1.tar.gz
tar xvzf apr-util-1.4.1.tar.gz
cd apr-util-1.4.1
./configure --with-apr=/usr/local/apr/ --with-berkeley-db=/usr/local/BerkeleyDB.5.3/bin/
make
make install

Ponownie wracamy do katalogu Subversion i uruchamiamy konfigurację wskazując ścieżki do nowo zainstalowanych aplikacji.

cd ../subversion-1.7.4
./configure --with-apr=/usr/local/apr/bin/ --with-apr-util=/usr/local/apr/bin/
make
make install

Tym razem konfiguracja oraz instalacje przebiega pomyślnie. Zainstalowane aplikacje znajdują się w katalogu /usr/local/bin:

find /usr/local/bin -name svn*

Aktualizacja repozytoriów

Jeżeli na serwerze posiadamy repozytoria utworzone przy pomocy starszej wersji Subversion, to możemy je zaktulizować do nowszej wersji przy pomocy aplikacji svnadmin. Przy wykonaniem poniższego polecenia warto wykonać kopię każdego repozytorium.

svnadmin upgrade /path/to/repository

Od teraz wszystkie repozytoria będą w najnowszej wersji.

Uaktualnienie

Subversion można skonfigurować z opcją „–without-berkeley-db”, aby uniknąć konieczności instalowania Berkeley DB oraz „–with-neon „, aby zapewnić wsparcie dla protokołów HTTP i HTTPS.

apt-get install libneon27-dev
./configure --with-apr=/usr/local/apr/bin/ --with-apr-util=/usr/local/apr/bin/ --with-ssl --with-neon

Bez ostatniej opcji próba pobrania repozytorium przy pomocy np. modułu dav_svn do Apache’a zakończy się komunikatem błędu.

svn: E170000: Unrecognized URL scheme for 'https...

Linki

http://subversion.apache.org/download/
http://apr.apache.org/
http://sqlite.org/
http://www.oracle.com/technetwork/database/berkeleydb/downloads/index.html
http://www.docstoc.com/docs/21393790/How-to-install-Subversion-in-CentOS-5
http://plod.fann.im/t/267 

Zaszufladkowano do kategorii Linux, SVN | Możliwość komentowania Debian – instalacja Subversion 1.7.4 została wyłączona

ProFTPD – logowanie zdarzeń do bazy SQL

Serwer ProFTPD domyślnie pobiera konfigurację oraz loguje zdarzenia do plików tekstowych. Istnieje jednak moduł, który pozwala na integrację z bazą SQL. Jest to przydatne, gdy chcemy analizować dane (np. podliczać transfer) lub zarządzać użytkownikami z poziomu bazy.

W niniejszym wpisie opiszę sposób konfiguracji serwera FTP tak, aby informacje o poprawnych i błędnych logowaniach były zapisywane do bazy MySQL.

Instalujemy serwer FTP oraz moduł umożliwiający dostęp do bazy SQL.

apt-get install proftpd proftpd-mod-mysql

W pliku /etc/proftpd/modules.conf znajduje się lista modułów. Musimy włączyć mod_sql.c oraz mod_sql_mysql.c. Wyszukujemy poniższe linie i usuwamy komentarze (znak #) lub dodajemy je na koniec pliku w przypadku ich braku.

LoadModule mod_sql.c
LoadModule mod_sql_mysql.c

W głównym pliku z konfiguracją należy dodać plik z listą modułów. Jeżeli poniższej linii nie ma w pliku /etc/proftpd/proftpd.conf, to dodajemy ją na koniec.

Include /etc/proftpd/modules.conf

Teraz czas na konfigurację MySQL-a. Zakładamy nową bazę, użytkownika oraz tabelę na dane. Moja tabela wygląda następująco. Zamiast MyISAM możemy użyć silnik ARCHIVE.

CREATE TABLE `proftpd_auth_log` (
  `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `remote_ip` VARCHAR(50) NOT NULL,
  `time` DATETIME NOT NULL,
  `command` VARCHAR(50) NOT NULL,
  `status` VARCHAR(50) UNSIGNED NOT NULL,
  PRIMARY KEY (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=MyISAM;

Na koniec pliku /etc/proftpd/proftpd.conf dodajemy poniższe polecenia, które umożliwią nawiązanie połączenia oraz logowanie danych do bazy.

SQLConnectInfo mydatabase@192.168.1.1 myuser mypassword
SQLLogFile /var/log/proftpd/mod_sql.log
SQLBackend mysql

SQLLog USER,PASS,ERR_PASS sqlauthlog
SQLNamedQuery sqlauthlog FREEFORM "INSERT INTO proftpd_auth_log (`remote_ip`, `time`, `command`, `status`) VALUES ('%a', NOW(), '%r', '%s')"

SQLConnectInfo zawiera nazwę bazy, adres serwer oraz login i hasło. SQLogFile określa ścieżkę do pliku z dziennikiem operacji wykonywanych na bazie, a SQLBackend zawiera typ bazy.

Polecenie SQLLog określa operacje, które będą logowane do bazy. W moim przypadku, są to polecenia USER, PASS oraz ERR_PASS, czyli prawidłowe oraz błędne próby logowania na serwer FTP. SQLNamedQuery to zapytanie, które dodaje dane do bazy. Loguję adresy IP, datę operacji, login oraz status (prawidłowe lub błędne logowanie). Dodatkowe informacje na temat logowania można znaleźć w dokumentacji.

Po zapisaniu zmian, restarujemy serwer.

/etc/init.d/proftpd restart

Oraz podglądamy plik z logiem.

tail -f /var/log/proftpd/mod_sql.log

Jeżeli zalogujemy się teraz na FTP, to na ekranie pojawi się odpowiednia informacja, a w bazie rekord z naszym IP oraz użytym loginem.

Uwagi

Działanie powyższej konfiguracji oraz serwera FTP możemy sprawdzić włączając logowanie przy pomocy poleceń DebugLevel oraz SystemLog.

DebugLevel 9
SystemLog /var/log/proftpd/system.log

Następnie logujemy się na FTP, wykonujemy kilka operacji (np. pobieramy plik) i sprawdzamy czy komunikacja pomiędzy ProFTPD a MySQL-em działa.

cat /var/log/proftpd/system.log | grep sql

Wynik powyższego polecenia powinien zawierać informacje o przesyłaniu poszczególnych komand do modułu mod_sql.

Mar 04 16:15:20 some.domain.pl proftpd[4566] 192.168.1.1 (::ffff:192.168.1.2[::ffff:192.168.1.2]): dispatching LOG_CMD command 'OPTS_UTF8 ON' to mod_sql
Mar 04 16:15:20 some.domain.pl proftpd[4566] 192.168.1.1 (::ffff:192.168.1.2[::ffff:192.168.1.2]): dispatching POST_CMD command 'OPTS UTF8 ON' to mod_sql
Mar 04 16:15:20 some.domain.pl proftpd[4566] 192.168.1.1 (::ffff:192.168.1.2[::ffff:192.168.1.2]): dispatching LOG_CMD command 'OPTS UTF8 ON' to mod_sql
Mar 04 16:15:22 some.domain.pl proftpd[4566] 192.168.1.1 (::ffff:192.168.1.2[::ffff:192.168.1.2]): dispatching POST_CMD command 'CWD /' to mod_sql
Mar 04 16:15:22 some.domain.pl proftpd[4566] 192.168.1.1 (::ffff:192.168.1.2[::ffff:192.168.1.2]): dispatching LOG_CMD command 'CWD /' to mod_sql
Mar 04 16:15:22 some.domain.pl proftpd[4566] 192.168.1.1 (::ffff:192.168.1.2[::ffff:192.168.1.2]): dispatching POST_CMD command 'TYPE I' to mod_sql
Mar 04 16:15:22 some.domain.pl proftpd[4566] 192.168.1.1 (::ffff:192.168.1.2[::ffff:192.168.1.2]): dispatching LOG_CMD command 'TYPE I' to mod_sql
Zaszufladkowano do kategorii Linux, MySQL | Możliwość komentowania ProFTPD – logowanie zdarzeń do bazy SQL została wyłączona

Replikacja bazy danych w MySQL

Replikację możemy wykorzystać do zrobienia kopii zapasowej lub jako serwer zapasowy, do którego nasza aplikacja podłączy się, gdy serwer główny w wyniku awarii lub zbyt dużego obciążenia przestanie działać. Konfiguracja replikacji jest prostą operacją i wymaga zmiany zaledwie kilku ustawień w pliku konfiguracyjnym serwera głównego (master) oraz serwera zapasowego (slave).

Serwer główny (master)

Edytujemy plik z ustawieniami MySQL-a.

vim /etc/mysql/my.conf

Do sekcji mysqld dodajemy ID serwera, ścieżkę do pliku dziennika oraz nazwy baz, które chcemy replikować. Nazwy baz mogą zawierać przecinki, więc musza być wypisane w osobnych liniach, a nie w postaci listy rozdzielonej przecinkami.

[mysqld]
server-id = 1
log-bin = /var/log/mysql/mysql-bin.log
binlog-do-db = nazwa_bazy_1
binlog-do-db = nazwa_bazy_2

Restartujemy MySQL-a.

/etc/init.d/mysql restart

Tworzymy użytkownika, który będzie wykorzystywany do

CREATE USER 'użytkownik'@'%' IDENTIFIED BY 'hasło';
GRANT REPLICATION SLAVE ON *.* TO 'użytkownik'@'%' IDENTIFIED BY 'hasło';
FLUSH PRIVILEGES;

Sprawdzamy czy ustawienia replikacji są poprawne.

FLUSH TABLES WITH READ LOCK;
SHOW MASTER STATUS;
UNLOCK TABLES;

Zapytanie „SHOW MASTER STATUS” powinno wyświetlić nazwę pliku dziennika, pozycję oraz nazwy baz, które będą poddawane replikacji.

File Position Binlog_Do_DB Binlog_Ignore_DB
mysql-bin.000001 106 nazwa_bazy_1,nazwa_bazy_2  

Serwer zapasowy (slave)

Edytujemy plik z ustawieniami MySQL-a.

vim /etc/mysql/my.conf

Do sekcji mysqld dodajemy ID serwera (musi być inny niż ten, który ustawiliśmy na serwerze głównym), adres serwera głównego, login i hasło wcześniej utworzonego użytkownika oraz nazwy baz. Nazwy baz również wpisujemy w osobnych liniach.

[mysqld]
server-id = 2
master-host = adres_serwera
master-user = użytkownik
master-password = hasło
master-connect-retry = 60
replicate-do-db = nazwa_bazy_1
replicate-do-db = nazwa_bazy_2

Restartujemy MySQL-a.

/etc/init.d/mysql restart

Po restarcie replikacja zostanie automatycznie uruchomiona, więc musimy ją zatrzymać.

SLAVE STOP;

Teraz należy przenieść bazy, które chcemy replikować z serwera głównego na zapasowy. Możemy to zrobić przy pomocy programu mysqldump.

Po wykonaniu kopii zapasowej na serwerze zapasowym należy określić parametry. Wykonujemy zapytanie „CHANGE MASTER TO” podając adres serwera, dane do logowania oraz nazwę pliku dziennika i pozycję. Dwie ostatnie informacje uzyskujemy po wykonaniu polecenia „SHOW MASTER STATUS” na serwerze głównym.

CHANGE MASTER TO MASTER_HOST='adres_serwera', MASTER_USER='użytkownik', MASTER_PASSWORD='hasło', MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=106;

Uruchamiamy replikację na serwerze zapasowym.

START SLAVE;

Weryfikacja

Sprawdzamy czy replikacja działa poprawnie.

SHOW SLAVE STATUS;

Wynikiem będzie tabela z informacjami o serwerze głównym, replikowanych bazach oraz pozycji w dzienniku. W kolumnie „SLAVE_IO_STATE” powinien znaleźć się komunikat „Waiting for master to send event” co oznacza, że serwer zapasowy oczekuje na dane z serwera głównego. „MASTER_LOG_FILE” to nazwa dziennika, a „READ_MASTER_LOG_POS” to pozycja w dzienniku. Pozycja powinna być taka sama jak wartość zwracane przez zapytanie „SHOW MASTER STATUS” wykonane na serwerze głównym.

Oprócz tego, możemy wyświetlić listę procesów na obu serwerach.

SHOW PROCESSLIST

Na serwerze głównym, na liście procesów pojawi się wpis z informacją o oczekiwaniu na aktualizację dziennika,

Has sent all binlog to slave; waiting for binlog to be updated

a na serwerze zapasowym informacja o oczekiwaniu na dane z serwera głównego.

Waiting for master to send event

Działanie replikacji można sprawdzić również wykonując poniższe zapytanie.

SHOW STATUS LIKE 'Slave%'

W wyniku otrzymamy m.in. wpis o nazwie „Slave_running” i wartości „ON”.

Uwagi

Opcja skip-networking nie może zostać włączona na serwerze głównym, gdyż serwer (lub serwery) zapasowe nie będą mogły nawiązać połączenia.

Podobnie jak skip-networking, opcja bind-address musi zostać wyłączona lub zawierać adres, do którego będą łączyły się serwery zapasowe.

Podczas przenoszenia bazy należy zwrócić uwagę na użytkownika, który został zdefiniowany jako twórca procedur czy triggerów. Jeżeli na serwerze slave użytkownik nie istnieje, to możemy otrzymać komunikat o błędzie. Poniższy komunikat został wygenerowany w momencie, gdy baza próbowała zreplikować zapytanie INSERT wykonane na tabeli, na której zdefiniowane były triggery.

Error 'The user specified as a definer ('użytkownik'@'%') does not exist' on query. Default database: 'nazwa_bazy_1'. Query: 'INSERT INTO ...'

Problem można rozwiązać poprzez dodanie użytkownika o takiej samej nazwie, a następnie nadaniu mu odpowiednich uprawnień do bazy na serwerze zapasowym.

Replikację można wznowić wykonując poniższe zapytania.

STOP SLAVE;
START SLAVE;

MySQL wznowi replikację począwszy od zapytania, które spowodowało problem.

Zaszufladkowano do kategorii Linux, MySQL | Możliwość komentowania Replikacja bazy danych w MySQL została wyłączona

Skrypt do tworzenia kopii zapasowych baz MySQL-a

Skrypt zrzuca zawartość bazy do pliku oraz kompresuje go. Ostatnia operacja, to usuwanie z folderu z kopiami zapasowymi plików utworzonych przed 7. dniami.

Skrypt przydaje się podczas tworzenia okresowych kopii zapasowych bazy danych.

#!/bin/bash

HOST=localhost
USER=root
PASSWORD=mypassword
DB=mydatabase

DIR=/root/backups/mysql
FILENAME="${DIR}/${DB}_`date +'%Y_%m_%d_%H_%M'`.sql"

mysqldump \
        --allow-keywords \
        --compress \
        --create-options \
        --disable-keys \
        --extended-insert \
        --host=$HOST \
        --events \
        --no-autocommit \
        --password=$PASSWORD \
        --quote-names \
        --routines \
        --skip-add-locks \
        --skip-comments \
        --skip-compact \
        --triggers \
        --user=$USER $DB > $FILENAME

gzip $FILENAME

find $DIR -mtime +7 -exec rm {} \;
Zaszufladkowano do kategorii Linux, MySQL | Możliwość komentowania Skrypt do tworzenia kopii zapasowych baz MySQL-a została wyłączona

Wysokiej jakości grafiki (antyaliasing) w pakiecie R

Aby móc renderować grafiki wysokiej jakości (np. z aktywnym antyaliasingiem) należy zainstalować bibliotekę Cairo (polecenie wykonujemy w konsoli R):

install.packages(c("Cairo"), repos="http://cran.r-project.org")

System rozpocznie pobieranie i kompilowanie biblioteki. Jeżeli podczas instalacji otrzymamy komunikat o braku pliku cairo.h:

Warning in install.packages(c("Cairo"), repos = "http://cran.r-project.org") :
argument 'lib' is missing: using '/usr/local/lib/R/site-library'
trying URL 'http://cran.r-project.org/src/contrib/Cairo_1.5-1.tar.gz'
Content type 'application/x-gzip' length 81918 bytes (79 Kb)
opened URL
==================================================
downloaded 79 Kb

* installing *source* package 'Cairo' ...
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no

...

checking if R was compiled with the RConn patch... no
checking cairo.h usability... no
checking cairo.h presence... no
checking for cairo.h... no
configure: error: Cannot find cairo.h! Please install cairo (http://www.cairographics.org/) and/or set CAIRO_CFLAGS/LIBS correspondingly.
ERROR: configuration failed for package 'Cairo'
* removing '/usr/local/lib/R/site-library/Cairo'
* restoring previous '/usr/local/lib/R/site-library/Cairo'

The downloaded packages are in
'/tmp/RtmpevzXi8/downloaded_packages'
Warning message:
In install.packages(c("Cairo"), repos = "http://cran.r-project.org") :
installation of package 'Cairo' had non-zero exit status

to znaczy, że nie mamy w systemie paczki z plikami źródłowymi biblioteki Cairo. Instalujemy pakiet „libcairo2-dev”:

apt-get install libcairo2-dev

Ponownie próbujemy pobrać bibliotekę Cairo:

install.packages(c("Cairo"), repos="http://cran.r-project.org")

Możemy otrzymać kolejny komunikat o braku plików z nagłówkami:

xlib-backend.c:34:74: error: X11/Intrinsic.h: No such file or directory
xlib-backend.c: In function 'Rcairo_init_xlib':
xlib-backend.c:158: warning: implicit declaration of function 'XrmUniqueQuark'
make: *** [xlib-backend.o] Error 1
ERROR: compilation failed for package 'Cairo'
* removing '/usr/local/lib/R/site-library/Cairo'

Instalujemy kolejną paczkę:

apt-get install libxt-dev

Jeszcze raz uruchamiamy konsolę R i próbujemy zainstalować Cairo. Jeżeli instalacja przebiegnie pomyślnie, to na końcu otrzymamy następujący komunikat:

Warning in install.packages(c("Cairo"), repos = "http://cran.r-project.org") :
argument 'lib' is missing: using '/usr/local/lib/R/site-library'
trying URL 'http://cran.r-project.org/src/contrib/Cairo_1.5-1.tar.gz'
Content type 'application/x-gzip' length 81918 bytes (79 Kb)
opened URL
==================================================
downloaded 79 Kb

* installing *source* package 'Cairo' ...
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out

...

gcc -I/usr/share/R/include -I/usr/include/cairo -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -I. -Iinclude -std=gnu99 -O3 -pipe -g -fpic -std=gnu99 -O3 -pipe -g -c w32-backend.c -o w32-backend.o
gcc -I/usr/share/R/include -I/usr/include/cairo -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -I. -Iinclude -std=gnu99 -O3 -pipe -g -fpic -std=gnu99 -O3 -pipe -g -c xlib-backend.c -o xlib-backend.o
gcc -shared -o Cairo.so cairobem.o cairogd.o cairotalk.o img-backend.o img-jpeg.o img-tiff.o pdf-backend.o ps-backend.o svg-backend.o w32-backend.o xlib-backend.o -lfreetype -lfontconfig -lpng12 -lz -lXrender -lcairo -lX11 -ljpeg -L/usr/lib64/R/lib -lR
installing to /usr/local/lib/R/site-library/Cairo/libs
** R
** preparing package for lazy loading
** help
*** installing help indices
** building package indices ...
** testing if installed package can be loaded

* DONE (Cairo)

The downloaded packages are in
'/tmp/Rtmpv9s866/downloaded_packages'
Zaszufladkowano do kategorii Linux | Możliwość komentowania Wysokiej jakości grafiki (antyaliasing) w pakiecie R została wyłączona

DirectAdmin – przenoszenie użytkowników pomiędzy resellerami

DirectAdmin nie pozwala na przenoszenie użytkowników pomiędzy resellerami, ale można to zrobić poprzez edycję plików konfiguracyjnych.

Załóżmy, że chcemy przenieść konto „seo” od resellera „admin” do „blogs”. Lista kont przypisanych do resellera znajduje się w pliku „users.list” w katalogu z ustawieniami resellera. Każda linia w pliku zawiera nazwę konta. Usuwamy konto, które chcemy przenieść z jednego pliku i dodajemy je do drugiego.

vim /usr/local/directadmin/data/users/admin/users.list
vim /usr/local/directadmin/data/users/blogs/users.list

Nazwa resellera jest również zapisana w pliku konfiguracyjnym użytkownika „user.conf”.

cat /usr/local/directadmin/data/users/seo/user.conf | grep creator

Po wykonaniu powyższego polecenia uzyskamy nazwę resellera, który utworzył nasze konto. Otwieramy plik w edytorze i w polu „creator” wpisujemy nazwę resellera, do którego chcemy przenieść konto.

creator=blogs

Po zapisaniu zmian dokonanych w plikach należy odświeżyć dane. Poniższe polecenie dodaje do kolejki zadanie, które odświeży listę użytkowników widocznych w panelu.

echo "action=cache&value=showallusers" >> /usr/local/directadmin/data/task.queue

Po kilku minutach użytkownicy zostaną zaktualizowani.

Linki

http://help.directadmin.com/item.php?id=93

Zaszufladkowano do kategorii DirectAdmin, Linux | Możliwość komentowania DirectAdmin – przenoszenie użytkowników pomiędzy resellerami została wyłączona

WarGAME

Projekt gry strategicznej. Główną funkcją jest możliwość projektowania własnych jednostek.

Gra tworzona w języku C++, za grafikę odpowiada silnik Ogre3D. Dodatkowe narzędzia, edytory tworzone w języku C#.

Zaszufladkowano do kategorii C#, C++, Projekty | Możliwość komentowania WarGAME została wyłączona

Metody podziału przestrzeni dla wykrywania kolizji

„Metody podziału przestrzeni dla wykrywania kolizji” to temat mojej pracy magisterskiej pisanej w trakcie studiów na Politechnice Śląskiej w Gliwicach.

Aplikacja tworzona na potrzeby pracy umożliwia przeprowadzanie testów wybranych algorytmów podziału przestrzeni oraz wykrywania kolizji.

Program został podzielony na dwa moduły. Pierwszy odpowiada za generowanie grafiki przy pomocy silnika Ogre3D, a drugi zawiera implementacje następujących algorytmów:

  • sfera otaczająca,
  • bryła AABB,
  • bryła OOB,
  • siatka jednolita,
  • drzewo ósemkowe,
  • drzewo BSP.

Źródła w serwisie GitLab.

 

Zaszufladkowano do kategorii C++, Projekty | Możliwość komentowania Metody podziału przestrzeni dla wykrywania kolizji została wyłączona

Osobny transfer dla domen w panelu DirectAdmin

Jeżeli chcemy, aby nasz serwis był dostępny pod wieloma domenami, to dodatkowe domeny możemy dodać przy pomocy Domain Pointers. Jednak transfer dla wszystkich domen będzie sumowany i przypisany do domeny głównej (dodanej w Domain Setup).

Chcąc rozdzielić transfer każdej z domen, wystarczy dodać dodatkowe domeny jako domeny główne (Domain Setup) zamiast jako wskaźniki (Domain Pointers). Następnie należy utworzyć dowiązanie symboliczne do katalogu „public_html” (zakładam, że jesteśmy w katalogu domowym użytkownika):

rm -r domains/domena_dodatkowa/public_html
ln -s domains/domena_dodatkowa/public_html domains/domena_glowna/public_html
Zaszufladkowano do kategorii DirectAdmin, Linux | Możliwość komentowania Osobny transfer dla domen w panelu DirectAdmin została wyłączona