본문 바로가기
운영체제 (LNX,WIN)

패키지 관리 속도 향상법 (emerge sync)

by 날으는물고기 2009. 6. 4.

패키지 관리 속도 향상법 (emerge sync)

Speeding up portage with cdb -- UPDATE

When it comes to speed the database backend of portage is rather slow because it's implemented as a raw abstraction in the filesystem. It is possible to replace this with a mysql backend which is not ideal, if you don't want to start a full-blown RDBMS. My solution is rather tiny, if you compare the code and the packages you need for that:

  1. You'll need the python interface python-cdb for DJB's cdb
    Code:
    emerge python-cdb

  2. Create /usr/lib/portage/pym/portage_db_cdb.py and put this in it:
    Code:
    # Copyright 2004, 2005 Tobias Bell <tobias.bell@web.de>
    #
    # This program is free software; you can redistribute it and/or modify
    # it under the terms of the GNU General Public License as published by
    # the Free Software Foundation; either version 2 of the License, or
    # (at your option) any later version.
    #
    # This program is distributed in the hope that it will be useful,
    # but WITHOUT ANY WARRANTY; without even the implied warranty of
    # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    # GNU General Public License for more details.
    #
    # You should have received a copy of the GNU General Public License
    # along with this program; if not, write to the Free Software
    # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    import portage_db_template
    import os
    import os.path
    import cPickle
    import cdb


    class _data(object):

        def __init__(self, path, category, uid, gid):
            self.path = path
            self.category = category
            self.uid = uid
            self.gid = gid
            self.addList = {}
            self.delList = []
            self.modified = False
            self.cdbName = os.path.normpath(os.path.join(
                self.path, self.category) + ".cdb")
            self.cdbObject = None

        def __del__(self):
            if self.modified:
                self.realSync()

            self.closeCDB()

        def realSync(self):
            if self.modified:
                self.modified = False
                newDB = cdb.cdbmake(self.cdbName, self.cdbName + ".tmp")
               
                for key, value in iter(self.cdbObject.each, None):
                    if key in self.delList:
                        if key in self.addList:
                            newDB.add(key, cPickle.dumps(self.addList[key], cPickle.HIGHEST_PROTOCOL))
                            del self.addList[key]
                    elif key in self.addList:                   
                        newDB.add(key, cPickle.dumps(self.addList[key], cPickle.HIGHEST_PROTOCOL))
                        del self.addList[key]
                    else:
                        newDB.add(key, value)
                   

                self.closeCDB()

                for key, value in self.addList.iteritems():
                    newDB.add(key, cPickle.dumps(value, cPickle.HIGHEST_PROTOCOL))
               
                newDB.finish()
                del newDB
               
                self.addList = {}
                self.delList = []

                self.openCDB()

        def openCDB(self):
            prevmask = os.umask(0)
           
            if not os.path.exists(self.path):
                os.makedirs(self.path, 02775)
                os.chown(self.path, self.uid, self.gid)
               
            if not os.path.isfile(self.cdbName):
                maker = cdb.cdbmake(self.cdbName, self.cdbName + ".tmp")
                maker.finish()
                del maker
                os.chown(self.cdbName, self.uid, self.gid)
                os.chmod(self.cdbName, 0664)

            os.umask(prevmask)
               
            self.cdbObject = cdb.init(self.cdbName)

        def closeCDB(self):
            if self.cdbObject:
                self.cdbObject = None


    class _dummyData:
        cdbName = ""

        def realSync():
            pass
        realSync = staticmethod(realSync)


    _cacheSize = 4
    _cache = [_dummyData()] * _cacheSize


    class database(portage_db_template.database):   

        def module_init(self):
            self.data = _data(self.path, self.category, self.uid, self.gid)

            for other in _cache:
                if other.cdbName == self.data.cdbName:
                    self.data = other
                    break
            else:
                self.data.openCDB()
                _cache.insert(0, self.data)           
                _cache.pop().realSync()
               
        def has_key(self, key):
            self.check_key(key)
            retVal = 0

            if self.data.cdbObject.get(key) is not None:
                retVal = 1

            if self.data.modified:
                if key in self.data.delList:
                    retVal = 0
                if key in self.data.addList:
                    retVal = 1
               
            return retVal

        def keys(self):
            myKeys = self.data.cdbObject.keys()

            if self.data.modified:
                for k in self.data.delList:
                    myKeys.remove(k)
                for k in self.data.addList.iterkeys():
                    if k not in myKeys:
                        myKeys.append(k)
                       
            return myKeys

        def get_values(self, key):
            values = None
           
            if self.has_key(key):
                if key in self.data.addList:
                    values = self.data.addList[key]
                else:
                    values = cPickle.loads(self.data.cdbObject.get(key))

            return values
       
        def set_values(self, key, val):
            self.check_key(key)
            self.data.modified = True
            self.data.addList[key] = val

        def del_key(self, key):
            retVal = 0
           
            if self.has_key(key):
                self.data.modified = True
                retVal = 1
                if key in self.data.addList:
                    del self.data.addList[key]
                else:
                    self.data.delList.append(key)

            return retVal
                       
        def sync(self):
            pass
       
        def close(self):
            pass


    if __name__ == "__main__":
        import portage
        uid = os.getuid()
        gid = os.getgid()
        portage_db_template.test_database(database,"/tmp", "sys-apps", portage.auxdbkeys, uid, gid)


  3. Create /etc/portage/modules and fill in
    Code:
    portdbapi.auxdbmodule = portage_db_cdb.database
    eclass_cache.dbmodule = portage_db_cdb.database


  4. Now you'll have to regenerate the portage cache with
    Code:
    emerge metadata

Now try some searches with emerge especially with --searchdesc :wink:
Code:
emerge --searchdesc python
should be much faster than before. You can compare the performance by switching back to the normal
db module. Just make a
Code:
mv /etc/portage/modules /etc/portage/__modules
I hope you enjoy your accelerated portage.



Default portage
Code:
cd /var/cache/edb/dep/usr
rm * -Rf
time emerge metadata
real    0m40.575s
user    0m26.260s
sys     0m9.592s

time emerge -S mozilla
real    1m46.003s
user    1m36.215s
sys     0m8.721s

time emerge -upDv world
real    0m14.678s
user    0m13.289s
sys     0m1.130s


python-cdb powered portage
Code:
cd /var/cache/edb/dep/usr
rm * -Rf
time emerge metadata
real    2m18.022s
user    0m26.538s
sys     0m31.505s

time emerge -S mozilla
real    1m39.624s
user    1m32.628s
sys     0m5.418s

time emerge -upDv world
real    0m13.856s
user    0m12.986s
sys     0m0.727s



## emerge 명령어 사용법 ##


emerge 옵션 테이블

Option1 Option2 기능
-s search 프로그램 찾기 및 각 프로그램에 대한 설명 참조 가능
-p pretend 프로그램 설치 이전, 설치를 가정하고 어떤 일이 벌어지는지 확인 가능
-v -- pretend 옵션과 더불어 쓰이며, 설정 혹은 비설정 use 옵션 확인 가능
unmerge 설치된 패키지 삭제 옵션,(>,<,=)기호 사용시 특정 버젼선택 삭제가능
help 자세한 설명 필요할때
rsync 포테이지 트리 업데이트 옵션
fetchonly 필요한 압축파일을 다운로드(컴파일안함)
emptytree 포테이지가 패키지및 의존성을 만족하는 패키지들이 모두 설치되지 않은것으로 인식
nodeps 의존성을 무시하고 패키지 설치(컴파일 실패 가능성..있음)
onlydeps 패키지의 의존성을 만족시키기 위한 것들만 설치(지정 패키지 설치안됨)
noreplace 이미 설치되어 있다면 패키지 설치를 생략
usepkg 컴파일이 아닌 이미 컴파일된 바이너리로 설치시도(PKGDIR 환경변수값 이용)
debug ebuild에 기초한 bash스크립트 문법적 에러를 추적할때 사용
autoclean emerge가 패키지의 빌드를 시작하기전에 임시 빌드 디렉토리 강제 청소
verbose emerge가 더 많은 정보를 표시
update 패키지 업데이트시 사용
prune 가장 마지막으로 설치된 버전을 제외하고 모든 패키지의 모든 버전들을 제거


사용법 emerging

사용법 1. emerge package_name
 # emerge mozilla
사용법 2. emerge dir/package_name rsync처럼 패키지명이 emerge의 특정 옵션으로 사용될 경우에 사용
# emerge net-misc/rsync
사용법 3. emerge emergefile 특정 버전을 설치할 때 사용
# emerge mozilla-1.3-r1.ebuild


portage tree 동기화

# emerge sync
or
# emerge rsync

/usr/portage의 개인 설정이 있다면 전부 삭제됨
sync와 rsync는 완전히 동일하게 작동합니다. /lefthander
메뉴얼에서는 rsync가 sync보다 서버의 부하를 덜 주어서 될수 있으면 rsync를 이용해 달라는 당부의 글이 있습니다.
아마도 sync는 모든 파일을 갱신하고 rsync는 없는 파일만 갱신하는것이 아닌가 싶습니다.

# emerge-webrsyncsync

보다 속도가 더 빠름. 스냅샷 압축파일을 받아와서 동기화


portage tree 갱신

# emerge -up system
# emerge -up world 
업데이트할 수 있는 system, world 패키지 확인

# emerge system
시스템 패키지 업데이트

# emerge world
world 패키지 업데이트

system과 world를 업데이트할 때 -u (--update) 옵션을 사용하면 의존성 있는 패키지도 함께 갱신한다.
이 의존성에 걸리는 패키지는 다운그레이드될 수 있다.


패키지 인스톨 전 확인

# emerge --pretend [package name]
or
# emerge -p pornview
# emerge -pv [package_name | ebuildfile]
설치할 패키지가 이미 설치되어 있는지, 의존관계 등의 정보를 확인


패키지 인스톨

#emerge [package name]


변경점 확인

#emerge --changelog [package name] or emerge -pl [package name]
이미 설치된 패키지와 portage상의 최신 패키지와의 차이 표시


패키지 갱신

#emerge [package name]



## 패키지 관리 명령어 비교 (yum / emerge / apt-get) ##


1. 패키지 목록 업데이트

====Fedora====
root@Fedora # yum check-update 
====Gentoo====
root@Gentoo # emerge --sync
====Debian====
root@Debian # apt-get update

2. 최신 패키지로 업데이트
====Fedora====
root@Fedora # yum update
====Gentoo====
root@Gentoo # emerge -DNu world
====Debian====
root@Debian # apt-get upgrade

3. 패키지 설치
====Fedora====
root@Fedora # yum install <packagename>
====Gentoo====
root@Gentoo # emerge <packagename>
====Debian====
root@Debian # apt-get install <packagename>

4. 패키지 재설치
====Fedora====
root@Fedora # yum update <packagename>
====Gentoo====
root@Gentoo # emerge --oneshot <packagename>
====Debian====
root@Debian # apt-get install --reinstall <packagename>

5. 패키지 검색
====Fedora====
root@Fedora # yum search <packagename>
====Gentoo====
root@Gentoo # emerge --searchdesc <packagename>
====Debian====
root@Debian # apt-cache search <packagename>

6. 패키지 삭제
====Fedora====
root@Fedora # yum remove <packagename>
====Gentoo====
root@Gentoo # emerge --unmerge <packagename>
====Debian====
root@Debian # apt-get remove <packagename>
 
참고 : http://wiki.kldp.org/wiki.php/PackageMgmt
728x90

댓글